Essayer de faire fonctionner Webauthn

Aug 17 2020

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

mrabat Aug 26 2020 at 13:18

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.