Essayer de faire fonctionner Webauthn
J'ai lancé un projet Fido2/WebAuthn il y a quelque temps et j'ai essayé de démarrer l'implémentation de Microsofts WebAuthn. Pour cela dans ce projet il existe une traduction du fichier webauthn.h (car aujourd'hui je n'ai trouvé des références à ce fichier que dans le code des navigateurs Mozilla et Chromium...).
Maintenant ... J'ai simplement essayé de créer un formulaire avec un bouton émettant une commande pour créer des informations d'identification, mais cet appel échoue lamentablement avec une violation d'accès @ $ 0000EA60 et je n'ai aucune idée de ce que cela pourrait causer. Que puis-je faire de mal ???
Voici le code d'un gestionnaire de bouton onClick.
uses Webauthn;
// just a test JSON object that I obtained from a browser request
const cClientData : UTF8String = '{' +
'"hashAlgorithm": "SHA-256",' +
'"challenge": "fzjg31IEKi6ZxKqsQ9S_XHG9WvdmcXPah5EXd11p1bU",' +
'"origin": "https:\/\/fidotest.com",' +
'"clientExtensions": {},' +
'"type": "webauthn.create"' +
'}';
procedure TfrmWebAuthnTest.btnCredentialClick(Sender: TObject);
var RpInformation : TWebAuthnRPEntityInformation; // _In_
UserInformation : TWebAuthUserEntityInformation; // _In_
PubKeyCredParams : TWebauthnCoseCredentialParameters; // _In_
WebAuthNClientData : TWebAuthnClientData; // _In_
WebAuthNMakeCredentialOptions : TWebAuthnAuthenticatorMakeCredentialOptions; // _In_opt_
pWebAuthNCredentialAttestation : PWEBAUTHN_CREDENTIAL_ATTESTATION; // _Outptr_result_maybenull_
hr : HRESULT;
coseParams : Array[0..1] of WEBAUTHN_COSE_CREDENTIAL_PARAMETER;
i : integer;
challenge : Array[0..31] of byte;
cancellationID : TGuid;
bufClientData : UTF8String;
begin
// ################################################
// #### relying party
FillChar(RpInformation, sizeof(RpInformation), 0);
RpInformation.dwVersion := WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION;
RpInformation.pwszId := 'fidotest.com';
RpInformation.pwszName := 'Sweet home localhost';
RpInformation.pwszIcon := nil;
// ################################################
// #### user information
FillChar(UserInformation, sizeof(UserInformation), 0);
UserInformation.dwVersion := WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION;
UserInformation.cbId := sizeof( challenge );
Randomize;
// create credentials
for i := 0 to Length(challenge) - 1 do
begin
challenge[i] := Byte( Random(High(byte) + 1) );
end;
UserInformation.pbId := @challenge[0];
UserInformation.pwszName := 'Mike';
UserInformation.pwszIcon := niL;
UserInformation.pwszDisplayName := 'Mike Rabat';
// ################################################
// #### Client data
bufClientData := Copy( cClientData, 1, Length(cClientData));
FillChar(WebAuthNClientData, sizeof(WebAuthNClientData), 0);
WebAuthNClientData.dwVersion := WEBAUTHN_CLIENT_DATA_CURRENT_VERSION;
WebAuthNClientData.cbClientDataJSON := Length(cClientData);
WebAuthNClientData.pbClientDataJSON := PAnsiChar(bufClientData);
WebAuthNClientData.pwszHashAlgId := WEBAUTHN_HASH_ALGORITHM_SHA_256;
// ################################################
// #### pub ked credential params
PubKeyCredParams.cCredentialParameters := sizeof(coseParams);
PubKeyCredParams.pCredentialParameters := @coseParams[0];
coseParams[0].dwVersion := WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION;
coseParams[0].pwszCredentialType := WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY;
coseParams[0].lAlg := WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256;
coseParams[1].dwVersion := WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION;
coseParams[1].pwszCredentialType := WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY;
coseParams[1].lAlg := WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA256;
// ###########################################
// #### Fill in params
FillChar(WebAuthNMakeCredentialOptions, sizeof(WebAuthNMakeCredentialOptions), 0);
WebAuthNMakeCredentialOptions.dwVersion := WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_CURRENT_VERSION;
WebAuthNMakeCredentialOptions.dwTimeoutMilliseconds := 60000;
WebAuthNMakeCredentialOptions.bRequireResidentKey := False;
WebAuthNMakeCredentialOptions.dwAuthenticatorAttachment := WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
WebAuthNMakeCredentialOptions.dwUserVerificationRequirement := WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
WebAuthNMakeCredentialOptions.dwAttestationConveyancePreference := WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT;
// ###########################################
// #### Cancellation
assert( WebAuthNGetCancellationId(cancellationID) = S_OK, 'Cancellation ID failed');
WebAuthNMakeCredentialOptions.pCancellationId := @cancellationID;
// ###########################################
// #### do the magic
pWebAuthNCredentialAttestation := nil;
hr := WebAuthNAuthenticatorMakeCredential( Handle,
@RpInformation,
@UserInformation,
@PubKeyCredParams,
@WebAuthNClientData,
@WebAuthNMakeCredentialOptions,
pWebAuthNCredentialAttestation );
if hr = S_OK then
begin
// WriteCredAttest( pWebAuthNCredentialAttestation );
WebAuthNFreeCredentialAttestation( pWebAuthNCredentialAttestation );
memLog.Lines.Add('Finished');
end
else
begin
memLog.Lines.Add('Make Cred failed with: ' + WebAuthNGetErrorName( hr ));
end;
end;
J'utilise Delphi2010 donc toutes les chaînes doivent être Unicode sauf la chaîne de données client JSON.
Réponses
Après une longue étude du code C++ du navigateur Mozilla, je pense avoir trouvé le problème. C'était dans le champ taille de la structure COSE_PARAMS.
// #### pub ked credential params
PubKeyCredParams.cCredentialParameters := Length(coseParams);// sizeof(coseParams);
PubKeyCredParams.pCredentialParameters := @coseParams[0];
Au lieu de la taille en octets, ils semblent s'attendre à la longueur du tableau des coseParams attachés. Ce malentendu a conduit à l'AV.