Callback

To Start

You will receive a json file from the web browser. It's need to be controlled before accepting the registration.

The json file must have this structure :

{
    "id": "BP63qesxI-...",
    "rawId": "BP63qesxI-...",
    "response": {
        "attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSj...",
        "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3J...",
        "transports": ["nfc", "usb"],
        "publicKeyAlgorithm": -8,
        "publicKey": "MCowBQYDK2VwAyE...",
        "authenticatorData": "pwU_KOYP8gQFgRDoKV9JAJG_LMGwWBtPT..."
    },
    "type": "public-key",
    "authenticatorAttachment": "cross-platform"
};

The id is the id generated by the authenticator (crendential.id).

First of all, instantiate the client and the RP has defined previously :

<?php
use Svgta\WebAuthn\client;
require dirname(__FILE__, 2) . '/vendor/autoload.php';
$webauthn = new client();
$webauthn->rp->set(
  name: 'My wonderful project',
);

Perform the validation

Do the Validation

This exemple is a base of use :

$aaguid = $webauthn->register()->aaguid();
$validation = $webauthn->register()->validate(); //return a json string

Get the response of the authenticator

You will receive an array :

  • userHandle : the user.id

  • credentialId : the id given by the authentificator

  • jsonData : the datas of the process in a json string.

Example of a result of jsonData :

{
    "userHandle": "86948860-...",
    "date": {
        "registrationTs": 1701002021,
        "registrationDate": "2023-11-26 13:33:41",
        "lastAccesTs": 1701002021,
        "lastAccesDate": "2023-11-26 13:33:41"
    },
    "credential": {
        "alg": -8,
        "id": "M5XWWYD4e6M...",
        "publicKeyCredentialSource": {
            "publicKeyCredentialId": "M5XWWYD4e6M...",
            "type": "public-key",
            "transports": ["nfc", "usb"],
            "attestationType": "basic",
            "trustPath": {
                "type": "Webauthn\\TrustPath\\CertificateTrustPath",
                "x5c": ["-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n"]
            },
            "aaguid": "2fc0579f-8113-47ea-b116-bb5a8db9202a",
            "credentialPublicKey": "pAEBAycgBiFY...",
            "userHandle": "ODY5NDg...",
            "counter": 4,
            "otherUI": null
        }
    },
    "info": {
        "registration": {
            "isUserPresent": true,
            "isUserVerified": true,
            "hasAttestedCredentialData": true,
            "signCount": 4
        },
        "authentication": [],
        "attestedCredentialData": {
            "metadataBLOB": {
                "aaguid": "2fc0579f-...",
                "attestationCertificateKeyIdentifiers": [],
                "statusReports": [{
                        "status": "FIDO_CERTIFIED_L1",
                        "effectiveDate": "2020-05-12",
                        "certificationDescriptor": "YubiKey ...",
                        "certificateNumber": "FIDO20020190826002",
                        "certificationPolicyVersion": "1.1.1",
                        "certificationRequirementsVersion": "1.3"
                    }, {
                        "status": "FIDO_CERTIFIED",
                        "effectiveDate": "2020-05-12"
                    }
                ],
                "timeOfLastStatusChange": "2020-05-12"
            },
            "metadataStatement": {
                "legalHeader": "Submission of this statement and retrieval and use of this statement indicates acceptance of the appropriate agreement located at https:\/\/fidoalliance.org\/metadata\/metadata-legal-terms\/.",
                "aaguid": "2fc0579f-...",
                "attestationCertificateKeyIdentifiers": [],
                "description": "YubiKey ...",
                "alternativeDescriptions": [],
                "authenticatorVersion": 328706,
                "protocolFamily": "fido2",
                "schema": 3,
                "upv": [{
                        "major": 1,
                        "minor": 0
                    }
                ],
                "authenticationAlgorithms": ["secp256r1_ecdsa_sha256_raw", "ed25519_eddsa_sha512_raw"],
                "publicKeyAlgAndEncodings": ["cose"],
                "attestationTypes": ["basic_full"],
                "userVerificationDetails": [[{
                            "userVerificationMethod": "passcode_external"
                        }, {
                            "userVerificationMethod": "presence_internal",
                            "caDesc": {
                                "base": 64,
                                "minLength": 4,
                                "maxRetries": 8,
                                "blockSlowdown": 0
                            }
                        }
                    ], [{
                            "userVerificationMethod": "passcode_external",
                            "caDesc": {
                                "base": 64,
                                "minLength": 4,
                                "maxRetries": 8,
                                "blockSlowdown": 0
                            }
                        }
                    ], [{
                            "userVerificationMethod": "presence_internal"
                        }
                    ], [{
                            "userVerificationMethod": "none"
                        }
                    ]],
                "keyProtection": ["hardware", "secure_element"],
                "matcherProtection": ["on_chip"],
                "cryptoStrength": 128,
                "attachmentHint": ["external", "wired", "wireless", "nfc"],
                "tcDisplay": [],
                "tcDisplayPNGCharacteristics": [],
                "attestationRootCertificates": ["-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"],
                "ecdaaTrustAnchors": [],
                "icon": "data:image\/png;base64,iVBORw0KGgoAAAANSUhEU...",
                "authenticatorGetInfo": ["basic_full"],
                "supportedExtensions": []
            }
        }
    }
}

Without attestation, it's someting like that :

{
    "userHandle": "8dc2279f-...",
    "date": {
        "registrationTs": 1701002775,
        "registrationDate": "2023-11-26 13:46:15",
        "lastAccesTs": 1701002775,
        "lastAccesDate": "2023-11-26 13:46:15"
    },
    "credential": {
        "alg": -8,
        "id": "O1kSf7QDZGY...",
        "publicKeyCredentialSource": {
            "publicKeyCredentialId": "O1kSf7QDZGYUc...",
            "type": "public-key",
            "transports": [],
            "attestationType": "none",
            "trustPath": {
                "type": "Webauthn\\TrustPath\\EmptyTrustPath"
            },
            "aaguid": "00000000-0000-0000-0000-000000000000",
            "credentialPublicKey": "pAEBAycgBiFYI...",
            "userHandle": "OGRjMjI3OWYt...",
            "counter": 3,
            "otherUI": null
        }
    },
    "info": {
        "registration": {
            "isUserPresent": true,
            "isUserVerified": true,
            "hasAttestedCredentialData": true,
            "signCount": 3
        },
        "authentication": [],
        "attestedCredentialData": {
            "metadataBLOB": "Unknown device",
            "metadataStatement": "Unknown device"
        }
    }
}

Explanation :

  • date : give the date of the registration of the device. The update date is the same as the create date.

  • userHandle : is the user.id given to make the registration

  • credential :

    • alg : the algorithm used by the device to sign the datas. The same algorithm will be used to sign datas for the authentication process

    • id : the key.id of the device

    • publicKeyCredentialSource : the datas to do the authentication process

  • info : informations about the user and the device. You can use them to do more verifications or, for example, using the icon of the device in your app.

What to save in your DataBase

For the authentication process, you will need to give back the jsonData string.

You may be need to index in your dataBase for tje authentication process :

  • userHandle

  • credentialId

In the example, you don't give the json response of the web browser. The library take it from php://input.

You can give the json like that :

$aaguid = $webauthn->register()->aaguid($jsonString);

You will have an exception if you asked in the parameters to have an attestation without MDS json given. You need to give a MDS (MetaData Service) to verify the attestation.

MetaData Service

Basic usage

MDS is needed to verify attestation. The library accept the value in a json string.

Example :

{
	"aaguid": "...",
	"metadataStatement": {
		"legalHeader": "Submission ...",
		"aaguid": "...",
		"description": "Pone ...",
		"authenticatorVersion": 1,
		"protocolFamily": "fido2",
		"schema": 3,
		"upv": [{
				"major": 1,
				"minor": 0
			}
		],
		"authenticationAlgorithms": [
			"secp256r1_ecdsa_sha256_raw"
		],
		"publicKeyAlgAndEncodings": [
			"ecc_x962_raw",
			"cose"
		],
		"attestationTypes": [
			"basic_full"
		],
		"userVerificationDetails": [
			[{
					"userVerificationMethod": "passcode_internal"
				}
			],
			[{
					"userVerificationMethod": "fingerprint_internal"
				}
			]
		],
		"keyProtection": [
			"hardware",
			"secure_element"
		],
		"matcherProtection": [
			"software"
		],
		"cryptoStrength": 128,
		"attachmentHint": [
			"nfc",
			"bluetooth"
		],
		"tcDisplay": [],
		"attestationRootCertificates": [
			"MIIBwTCCAWegAwIBAgIUM9zX0yKQj8xg..."
		],
		"icon": "data:image/png;base64,iVBORw0KGgoAAAA...",
		"authenticatorGetInfo": {
			"versions": [
				"FIDO_2_0"
			],
			"extensions": [
				"hmac-secret"
			],
			"aaguid": "09591fc6981148f78f57b9f23df6413f",
			"options": {
				"plat": false,
				"rk": true,
				"clientPin": false,
				"up": true,
				"uv": true
			},
			"transports": [
				"ble",
				"nfc"
			],
			"firmwareVersion": 1
		}
	},
	"statusReports": [{
			"status": "NOT_FIDO_CERTIFIED",
			"effectiveDate": "2022-11-10"
		}
	],
	"timeOfLastStatusChange": "2022-11-10"
}

To validate with MDS :

$aaguid = $webauthn->register()->aaguid();
$webauthn->mds->load($jsonMDS);

Using MDS from FIDO Alliance

The FIDO Alliance offer for free an API to the MDS3 BLOB (link to the webpage). It's a JWT. You can use this library to get all the datas.

You must not get the MDS3 BLOB from Fido Alliance every time. You need to save the datas in your database and call the update when needed. The JWT give the date of the next update : please, use it.

The library save the MDS3 BLOB in your temp dir and parse in it the datas.

$webauthn->fido->update();

//Get the next update date :
$date = $webauthn->fido->nextUpdate(); //2023-12-01 -> save it in your database

//Get all MDS in json string format

foreach( $webauthn->fido->get_tmp_mds() as $aaguid => $json){
    //process the save in your dataBase with :
    // key : $aaguid (string)
    // value : $json (string)
}

The update(

?string $fido_url = null,

?string $fido_cert = null,

array $requestParams = []

) method can take 3 parameters :

The fido_cert is used to verify the JWT obtain bye the fido_url. If theses urls change in futur, the call must be :

$webauthn->fido->update(
    fido_url: "https://newUrlFromFidoAlliance",
    fido_cert: "http://newRootCaUrl"
);

// using a proxy 

$webauthn->fido->update(requestParams: ['proxy' => 'http://localhost:8125']);
//OR
$webauthn->fido->update(requestParams: [
    'proxy' => [
        'http'  => 'http://localhost:8125', // Use this proxy with "http"
        'https' => 'http://localhost:9124', // Use this proxy with "https",
        'no' => ['.mit.edu', 'foo.com']    // Don't use a proxy with these
    ]
]);

If you need to validate attestation with a MDS from FIDO Alliance :

  • From your database

$aaguid = $webauthn->register()->aaguid();
//...
// Process to get the json string from your dataBase using the $aaguid key
//...
$webauthn->mds->load($jsonString);
$ret = $webauthn->register()->validate(); //return a json string
  • From your server temp dir after getting the MDS3 Blob

$aaguid = $webauthn->register()->aaguid();
if($mdsJson = $webauthn->fido->get_tmp_mds_aaguid($aaguid))
  $webauthn->mds->load($mdsJson);
$ret = $webauthn->register()->validate();

Last updated