webauthn
webauthn copied to clipboard
FIDO2 C++ based application using WebAuthn.dll for "YUBIKEY 5 NFC" (External authenticator) gives "This Security Key doesn't look familiar. Please try a different one."
Hi
I am writing FIDO2 C++ based application using WebAuthn.dll for "YUBIKEY 5 NFC" (External authenticator)
using the following WebAutheN APIs of Microsoft
from the
https://github.com/microsoft/webauthn/blob/master/webauthn.h
HRESULT WINAPI WebAuthNAuthenticatorMakeCredential(
_In_ HWND hWnd,
_In_ PCWEBAUTHN_RP_ENTITY_INFORMATION pRpInformation,
_In_ PCWEBAUTHN_USER_ENTITY_INFORMATION pUserInformation,
_In_ PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS pPubKeyCredParams,
_In_ PCWEBAUTHN_CLIENT_DATA pWebAuthNClientData,
_In_opt_ PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS pWebAuthNMakeCredentialOptions,
_Outptr_result_maybenull_ PWEBAUTHN_CREDENTIAL_ATTESTATION *ppWebAuthNCredentialAttestation);
HRESULT WINAPI WebAuthNAuthenticatorGetAssertion(
_In_ HWND hWnd,
_In_ LPCWSTR pwszRpId,
_In_ PCWEBAUTHN_CLIENT_DATA pWebAuthNClientData,
_In_opt_ PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS pWebAuthNGetAssertionOptions,
_Outptr_result_maybenull_ PWEBAUTHN_ASSERTION *ppWebAuthNAssertion);
I am able to get the registration successfully with the IdP (Identity Provider) using C++ API WebAuthNAuthenticatorMakeCredential() in my code.
But when it comes to Authentication, I am facing problem with the api WebAuthNAuthenticatorGetAssertion() as follows:
"This Security Key doesn't look familiar. Please try a different one."
Below is my code :
HWND hWnd = GetForegroundWindow();
LPCWSTR pwszRpId = L"tenet.domain.com";
//My client data in json format is as below...
sClientData64 = {"type":"webauthn.get","challenge":"MKB9ApSESppXbU-oVW_M","origin":"https://tenet.domain.com","crossOrigin":true};
WEBAUTHN_CLIENT_DATA oClientData_in = { WEBAUTHN_CLIENT_DATA_CURRENT_VERSION,
static_cast<DWORD>(sClientData64.length()),
(PBYTE)(sClientData64.data()),
WEBAUTHN_HASH_ALGORITHM_SHA_256
};
I tried to manipulate the values as in the following link: https://github.com/Yubico/python-fido2/blob/master/fido2/win_api.py to implement
the structure "WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS"
below:
My allow list code is as follows:
std::vector<WEBAUTHN_CREDENTIAL_EX> allowCredentials;
WEBAUTHN_CREDENTIAL_EX* pAllowCredentials = nullptr;
std::vector<WEBAUTHN_CREDENTIAL_EX*> allowCredentialsPtrs;
WEBAUTHN_CREDENTIAL_LIST allowCredentialList = { 0 };
WEBAUTHN_CREDENTIAL_LIST* pAllowCredentialList = nullptr;
DWORD dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_4; // the value is 4
if(dwversion is >= 4)
{
DWORD winTransports = 0;
std::string sAuthenticatorType = "usb";
int nTransport = 0;
if(sAuthenticatorType == "usb")
{
nTransport = 1;
}
if (nTransport & U2F_AUTHENTICATOR_TRANSPORT_USB)
{
winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
}
WEBAUTHN_CREDENTIAL_EX webCredEx = { WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
static_cast<DWORD>(sCredentialId.length()),
((BYTE*)(sCredentialId.c_str())),
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY,
winTransports
};
allowCredentials.push_back(webCredEx);
pAllowCredentials = allowCredentials.data();
for (DWORD i = 0; i < allowCredentials.size(); i++)
{
allowCredentialsPtrs.push_back(&pAllowCredentials[i]);
}
allowCredentialList.cCredentials = allowCredentials.size(); // original
allowCredentialList.ppCredentials = allowCredentialsPtrs.data(); // original
pAllowCredentialList = &allowCredentialList; // my AllowCredentialList value
}
// Credentials is as follows:
WEBAUTHN_CREDENTIALS webCredentials = {0,NULL};
DWORD dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_3; // the value is 3
if(dwversion is >= 3)
{
std::vector<WEBAUTHN_CREDENTIAL> vCredential;
std::vector<WEBAUTHN_CREDENTIAL*> pCredential;
WEBAUTHN_CREDENTIAL webAuthCredential = {WEBAUTHN_CREDENTIAL_CURRENT_VERSION,
static_cast<DWORD>(sCredentialId.length()),
((BYTE*)(sCredentialId.c_str())),
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY
};
WEBAUTHN_CREDENTIAL *pwebCredential;
vCredential.push_back(webAuthCredential);
pwebCredential = vCredential.data();
for (DWORD i = 0; i < vCredential.size(); i++)
{
pCredential.push_back(&pwebCredential[i]);
}
webCredentials.cCredentials = vCredential.size();
webCredentials.pCredentials = pwebCredential;
}
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS oWebAuthNGetAssertionOptions = {
dwVersion,
10000,
webCredentials, //WEBAUTHN_CREDENTIALS // if (dwVersion >=3) {webCredentials;} else {0,NULL} {webCredentials = NULL}
{0, NULL}, //WEBAUTHN_EXTENSIONS
dwAuthenticatorAttachement, // option for Platform (Windows Hello) vs Cross platform authenticator (Yubikey)
winUserVerificationReq, // user Verification Required (preferred)
0, // dwFlags
NULL, // as json data received it is null
pbU2fAppIdUsed, (FALSE) this is a pointer
NULL, // pCancellationId
pAllowCredentialList // allowList if (dwversion is >= 4) else allowlist is null
};
WEBAUTHN_ASSERTION* pWebAuthNAssertion = nullptr; // this is an output parameter, which will get data of signature, Authenticator etc...
// on this call i get this message dialog popup saying " This Security key doesn't look familiar. please try a different one."
hResult = WebAuthNAuthenticatorGetAssertion(hWnd, pwszRpId &oClientData_in, &oWebAuthNAssertionOptions, &pWebAuthNAssertion);
I took the python code for reference from the https://github.com/Yubico/python-fido2/blob/master/fido2/win_api.py
if (dwVersion >= 3)
self.pCancellationId = cancellationId (NULL)
if self.dwVersion >= 4:
clist = WebAuthNCredentialList(credentials)
self.pAllowCredentialList = ctypes.pointer(clist)
else:
self.CredentialList = WebAuthNCredentials(credentials)
========================================================================
I have posted the same issue in MSDN forums. https://docs.microsoft.com/en-us/answers/questions/305670/fido2-c-based-application-using-webauthndll-for-34.html
Please let me know, if any thing has to added in my code.
Thankyou.
This isn't specifically related to this library from what I can tell. However the causes for the browser not recognizing the fido2 device during attestation are the rpID or appid not matching, or the allowed credential ID's not matching.
I've personally found the most common to be the allowed credential ID's not being decoded correctly.