webauthn icon indicating copy to clipboard operation
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."

Open Mahaboob-Aslam opened this issue 3 years ago • 1 comments

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."

image

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.

Mahaboob-Aslam avatar Mar 10 '21 14:03 Mahaboob-Aslam

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.

james-d-elliott avatar Feb 13 '22 03:02 james-d-elliott