WebAuthnResult.h (13338B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef mozilla_dom_WebAuthnResult_h_ 6 #define mozilla_dom_WebAuthnResult_h_ 7 8 #include "mozilla/Maybe.h" 9 #include "nsIWebAuthnResult.h" 10 #include "nsString.h" 11 #include "nsTArray.h" 12 13 #ifdef MOZ_WIDGET_ANDROID 14 # include "JavaBuiltins.h" 15 # include "mozilla/java/WebAuthnUtilsNatives.h" 16 #endif 17 18 #ifdef XP_WIN 19 # include <windows.h> 20 21 # include "mozilla/dom/PWebAuthnTransactionParent.h" 22 # include "winwebauthn/webauthn.h" 23 #endif 24 25 namespace mozilla::dom { 26 27 class WebAuthnRegisterResult final : public nsIWebAuthnRegisterResult { 28 public: 29 NS_DECL_THREADSAFE_ISUPPORTS 30 NS_DECL_NSIWEBAUTHNREGISTERRESULT 31 32 WebAuthnRegisterResult(const nsTArray<uint8_t>& aAttestationObject, 33 const Maybe<nsCString>& aClientDataJSON, 34 const nsTArray<uint8_t>& aCredentialId, 35 const nsTArray<nsString>& aTransports, 36 const Maybe<nsString>& aAuthenticatorAttachment, 37 const Maybe<bool>& aLargeBlobSupported, 38 const Maybe<bool>& aPrfSupported, 39 const Maybe<nsTArray<uint8_t>>& aPrfFirst, 40 const Maybe<nsTArray<uint8_t>>& aPrfSecond) 41 : mAttestationConsentPromptShown(false), 42 mClientDataJSON(aClientDataJSON), 43 mCredPropsRk(Nothing()), 44 mAuthenticatorAttachment(aAuthenticatorAttachment), 45 mLargeBlobSupported(aLargeBlobSupported), 46 mPrfSupported(aPrfSupported) { 47 mAttestationObject.AppendElements(aAttestationObject); 48 mCredentialId.AppendElements(aCredentialId); 49 mTransports.AppendElements(aTransports); 50 if (aPrfFirst.isSome()) { 51 mPrfFirst.emplace(aPrfFirst->Length()); 52 mPrfFirst->Assign(aPrfFirst.ref()); 53 } 54 if (aPrfSecond.isSome()) { 55 mPrfSecond.emplace(aPrfSecond->Length()); 56 mPrfSecond->Assign(aPrfSecond.ref()); 57 } 58 } 59 60 #ifdef MOZ_WIDGET_ANDROID 61 explicit WebAuthnRegisterResult( 62 const java::WebAuthnUtils::MakeCredentialResponse::LocalRef& aResponse) { 63 mAttestationObject.AppendElements( 64 reinterpret_cast<uint8_t*>( 65 aResponse->AttestationObject()->GetElements().Elements()), 66 aResponse->AttestationObject()->Length()); 67 mAttestationConsentPromptShown = false; 68 if (aResponse->ClientDataJson()) { 69 mClientDataJSON = Some(nsAutoCString( 70 reinterpret_cast<const char*>( 71 aResponse->ClientDataJson()->GetElements().Elements()), 72 aResponse->ClientDataJson()->Length())); 73 } 74 mCredentialId.AppendElements( 75 reinterpret_cast<uint8_t*>( 76 aResponse->KeyHandle()->GetElements().Elements()), 77 aResponse->KeyHandle()->Length()); 78 auto transports = aResponse->Transports(); 79 for (size_t i = 0; i < transports->Length(); i++) { 80 mTransports.AppendElement( 81 jni::String::LocalRef(transports->GetElement(i))->ToString()); 82 } 83 mAuthenticatorAttachment = 84 Some(aResponse->AuthenticatorAttachment()->ToString()); 85 if (aResponse->CredProps()) { 86 mCredPropsRk = Some(java::sdk::Boolean::Ref::From(aResponse->CredProps()) 87 ->BooleanValue()); 88 } 89 } 90 #endif 91 92 #ifdef XP_WIN 93 WebAuthnRegisterResult(nsCString& aClientDataJSON, 94 PCWEBAUTHN_CREDENTIAL_ATTESTATION aResponse) 95 : mClientDataJSON(Some(aClientDataJSON)) { 96 mCredentialId.AppendElements(aResponse->pbCredentialId, 97 aResponse->cbCredentialId); 98 99 mAttestationObject.AppendElements(aResponse->pbAttestationObject, 100 aResponse->cbAttestationObject); 101 mAttestationConsentPromptShown = true; 102 103 nsTArray<WebAuthnExtensionResult> extensions; 104 if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2) { 105 PCWEBAUTHN_EXTENSIONS pExtensionList = &aResponse->Extensions; 106 if (pExtensionList->cExtensions != 0 && 107 pExtensionList->pExtensions != NULL) { 108 for (DWORD dwIndex = 0; dwIndex < pExtensionList->cExtensions; 109 dwIndex++) { 110 PWEBAUTHN_EXTENSION pExtension = 111 &pExtensionList->pExtensions[dwIndex]; 112 if (pExtension->pwszExtensionIdentifier && 113 (0 == _wcsicmp(pExtension->pwszExtensionIdentifier, 114 WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET)) && 115 pExtension->cbExtension == sizeof(BOOL)) { 116 BOOL* pCredentialCreatedWithHmacSecret = 117 (BOOL*)pExtension->pvExtension; 118 if (*pCredentialCreatedWithHmacSecret) { 119 mHmacCreateSecret = Some(true); 120 mPrfSupported = Some(true); 121 } 122 } 123 } 124 } 125 } 126 127 if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_7) { 128 if (aResponse->pHmacSecret) { 129 if (aResponse->pHmacSecret->cbFirst > 0) { 130 mPrfFirst.emplace(); 131 mPrfFirst->AppendElements(aResponse->pHmacSecret->pbFirst, 132 aResponse->pHmacSecret->cbFirst); 133 } 134 if (aResponse->pHmacSecret->cbSecond > 0) { 135 mPrfSecond.emplace(); 136 mPrfSecond->AppendElements(aResponse->pHmacSecret->pbSecond, 137 aResponse->pHmacSecret->cbSecond); 138 } 139 } 140 } 141 142 DWORD transports = 0; 143 if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_8) { 144 // The dwTransports field added in version 8 lists all supported 145 // transports, whereas the dwUsedTransport available since version 3 only 146 // returns the transport that was used. 147 transports = aResponse->dwTransports; 148 } else if (aResponse->dwVersion >= 149 WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) { 150 transports = aResponse->dwUsedTransport; 151 } 152 153 if (transports & WEBAUTHN_CTAP_TRANSPORT_USB) { 154 mTransports.AppendElement(u"usb"_ns); 155 } 156 if (transports & WEBAUTHN_CTAP_TRANSPORT_NFC) { 157 mTransports.AppendElement(u"nfc"_ns); 158 } 159 if (transports & WEBAUTHN_CTAP_TRANSPORT_BLE) { 160 mTransports.AppendElement(u"ble"_ns); 161 } 162 if (transports & WEBAUTHN_CTAP_TRANSPORT_INTERNAL) { 163 mTransports.AppendElement(u"internal"_ns); 164 } 165 // WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5 corresponds to 166 // WEBAUTHN_API_VERSION_6 which is where WEBAUTHN_CTAP_TRANSPORT_HYBRID was 167 // defined. 168 if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5) { 169 if (transports & WEBAUTHN_CTAP_TRANSPORT_HYBRID) { 170 mTransports.AppendElement(u"hybrid"_ns); 171 } 172 } 173 174 if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) { 175 if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_INTERNAL) { 176 mAuthenticatorAttachment = Some(u"platform"_ns); 177 } else { 178 mAuthenticatorAttachment = Some(u"cross-platform"_ns); 179 } 180 } 181 182 if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4) { 183 if (aResponse->bLargeBlobSupported) { 184 mLargeBlobSupported = Some(true); 185 } 186 } 187 188 if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5) { 189 if (aResponse->bPrfEnabled) { 190 mPrfSupported = Some(true); 191 } 192 } 193 } 194 #endif 195 196 private: 197 ~WebAuthnRegisterResult() = default; 198 199 nsTArray<uint8_t> mAttestationObject; 200 bool mAttestationConsentPromptShown; 201 nsTArray<uint8_t> mCredentialId; 202 nsTArray<nsString> mTransports; 203 Maybe<nsCString> mClientDataJSON; 204 Maybe<bool> mCredPropsRk; 205 Maybe<bool> mHmacCreateSecret; 206 Maybe<nsString> mAuthenticatorAttachment; 207 Maybe<bool> mLargeBlobSupported; 208 Maybe<bool> mPrfSupported; 209 Maybe<nsTArray<uint8_t>> mPrfFirst; 210 Maybe<nsTArray<uint8_t>> mPrfSecond; 211 }; 212 213 class WebAuthnSignResult final : public nsIWebAuthnSignResult { 214 public: 215 NS_DECL_THREADSAFE_ISUPPORTS 216 NS_DECL_NSIWEBAUTHNSIGNRESULT 217 218 WebAuthnSignResult(const nsTArray<uint8_t>& aAuthenticatorData, 219 const Maybe<nsCString>& aClientDataJSON, 220 const nsTArray<uint8_t>& aCredentialId, 221 const nsTArray<uint8_t>& aSignature, 222 const nsTArray<uint8_t>& aUserHandle, 223 const Maybe<nsString>& aAuthenticatorAttachment, 224 const Maybe<bool>& aUsedAppId, 225 const Maybe<nsTArray<uint8_t>>& aLargeBlobValue, 226 const Maybe<bool>& aLargeBlobWritten, 227 const Maybe<nsTArray<uint8_t>>& aPrfFirst, 228 const Maybe<nsTArray<uint8_t>>& aPrfSecond) 229 : mClientDataJSON(aClientDataJSON), 230 mAuthenticatorAttachment(aAuthenticatorAttachment), 231 mUsedAppId(aUsedAppId), 232 mLargeBlobWritten(aLargeBlobWritten) { 233 mAuthenticatorData.AppendElements(aAuthenticatorData); 234 mCredentialId.AppendElements(aCredentialId); 235 mSignature.AppendElements(aSignature); 236 mUserHandle.AppendElements(aUserHandle); 237 if (aLargeBlobValue.isSome()) { 238 mLargeBlobValue.emplace(aLargeBlobValue->Length()); 239 mLargeBlobValue->Assign(aLargeBlobValue.ref()); 240 } 241 if (aPrfFirst.isSome()) { 242 mPrfFirst.emplace(aPrfFirst.ref().Length()); 243 mPrfFirst->Assign(aPrfFirst.ref()); 244 } 245 if (aPrfSecond.isSome()) { 246 mPrfSecond.emplace(aPrfSecond.ref().Length()); 247 mPrfSecond->Assign(aPrfSecond.ref()); 248 } 249 } 250 251 #ifdef MOZ_WIDGET_ANDROID 252 explicit WebAuthnSignResult( 253 const java::WebAuthnUtils::GetAssertionResponse::LocalRef& aResponse) { 254 mAuthenticatorData.AppendElements( 255 reinterpret_cast<uint8_t*>( 256 aResponse->AuthData()->GetElements().Elements()), 257 aResponse->AuthData()->Length()); 258 if (aResponse->ClientDataJson()) { 259 mClientDataJSON = Some(nsAutoCString( 260 reinterpret_cast<const char*>( 261 aResponse->ClientDataJson()->GetElements().Elements()), 262 aResponse->ClientDataJson()->Length())); 263 } 264 mCredentialId.AppendElements( 265 reinterpret_cast<uint8_t*>( 266 aResponse->KeyHandle()->GetElements().Elements()), 267 aResponse->KeyHandle()->Length()); 268 mSignature.AppendElements( 269 reinterpret_cast<uint8_t*>( 270 aResponse->Signature()->GetElements().Elements()), 271 aResponse->Signature()->Length()); 272 mUserHandle.AppendElements( 273 reinterpret_cast<uint8_t*>( 274 aResponse->UserHandle()->GetElements().Elements()), 275 aResponse->UserHandle()->Length()); 276 mAuthenticatorAttachment = 277 Some(aResponse->AuthenticatorAttachment()->ToString()); 278 } 279 #endif 280 281 #ifdef XP_WIN 282 WebAuthnSignResult(nsCString& aClientDataJSON, DWORD aCredLargeBlobOperation, 283 PCWEBAUTHN_ASSERTION aResponse) 284 : mClientDataJSON(Some(aClientDataJSON)) { 285 mSignature.AppendElements(aResponse->pbSignature, aResponse->cbSignature); 286 287 mCredentialId.AppendElements(aResponse->Credential.pbId, 288 aResponse->Credential.cbId); 289 290 mUserHandle.AppendElements(aResponse->pbUserId, aResponse->cbUserId); 291 292 mAuthenticatorData.AppendElements(aResponse->pbAuthenticatorData, 293 aResponse->cbAuthenticatorData); 294 295 mAuthenticatorAttachment = Nothing(); // not available 296 297 if (aCredLargeBlobOperation == WEBAUTHN_CRED_LARGE_BLOB_OPERATION_GET) { 298 if (aResponse->dwVersion >= WEBAUTHN_ASSERTION_VERSION_2 && 299 aResponse->dwCredLargeBlobStatus == 300 WEBAUTHN_CRED_LARGE_BLOB_STATUS_SUCCESS) { 301 mLargeBlobValue.emplace(); 302 mLargeBlobValue->AppendElements(aResponse->pbCredLargeBlob, 303 aResponse->cbCredLargeBlob); 304 } 305 } else if (aCredLargeBlobOperation == 306 WEBAUTHN_CRED_LARGE_BLOB_OPERATION_SET) { 307 if (aResponse->dwVersion >= WEBAUTHN_ASSERTION_VERSION_2 && 308 aResponse->dwCredLargeBlobStatus == 309 WEBAUTHN_CRED_LARGE_BLOB_STATUS_SUCCESS) { 310 mLargeBlobWritten.emplace(true); 311 } else { 312 mLargeBlobWritten.emplace(false); 313 } 314 } 315 316 if (aResponse->dwVersion >= WEBAUTHN_ASSERTION_VERSION_3) { 317 if (aResponse->pHmacSecret) { 318 if (aResponse->pHmacSecret->cbFirst > 0) { 319 mPrfFirst.emplace(); 320 mPrfFirst->AppendElements(aResponse->pHmacSecret->pbFirst, 321 aResponse->pHmacSecret->cbFirst); 322 } 323 if (aResponse->pHmacSecret->cbSecond > 0) { 324 mPrfSecond.emplace(); 325 mPrfSecond->AppendElements(aResponse->pHmacSecret->pbSecond, 326 aResponse->pHmacSecret->cbSecond); 327 } 328 } 329 } 330 } 331 #endif 332 333 private: 334 ~WebAuthnSignResult() = default; 335 336 nsTArray<uint8_t> mAuthenticatorData; 337 Maybe<nsCString> mClientDataJSON; 338 nsTArray<uint8_t> mCredentialId; 339 nsTArray<uint8_t> mSignature; 340 nsTArray<uint8_t> mUserHandle; 341 Maybe<nsString> mAuthenticatorAttachment; 342 Maybe<bool> mUsedAppId; 343 Maybe<nsTArray<uint8_t>> mLargeBlobValue; 344 Maybe<bool> mLargeBlobWritten; 345 Maybe<nsTArray<uint8_t>> mPrfFirst; 346 Maybe<nsTArray<uint8_t>> mPrfSecond; 347 }; 348 349 } // namespace mozilla::dom 350 #endif // mozilla_dom_WebAuthnResult_h