Попытка запустить Webauthn
Некоторое время назад я начал проект Fido2 / WebAuthn и попытался запустить реализацию MicroSoft Webauthn. Для этого в этом проекте существует перевод файла webauthn.h (поскольку сегодня я нашел ссылки на этот файл только в коде браузеров Mozilla и Chromium ...).
Теперь ... Я просто попытался создать форму с помощью кнопки, выдающей команду для создания учетных данных, но этот вызов терпит неудачу из-за нарушения прав доступа @ $ 0000EA60, и я понятия не имею, к чему это может привести. Что я могу сделать не так ???
Вот код для обработчика кнопки 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;
Я использую Delphi2010, поэтому все строки должны быть в Юникоде, кроме строки данных клиента JSON.
Ответы
После долгого изучения кода C ++ браузера Mozilla я думаю, что нашел проблему. Это было в поле размера структуры COSE_PARAMS.
// #### pub ked credential params
PubKeyCredParams.cCredentialParameters := Length(coseParams);// sizeof(coseParams);
PubKeyCredParams.pCredentialParameters := @coseParams[0];
Вместо размера в байтах они, кажется, ожидают длину массива прикрепленных coseParams. Это недоразумение привело к тому, что AV.