Changeset 291624 in webkit
- Timestamp:
- Mar 22, 2022 9:14:25 AM (4 months ago)
- Location:
- trunk/Source
- Files:
-
- 10 edited
-
WebCore/ChangeLog (modified) (1 diff)
-
WebCore/Modules/webauthn/WebAuthenticationUtils.cpp (modified) (2 diffs)
-
WebCore/Modules/webauthn/WebAuthenticationUtils.h (modified) (2 diffs)
-
WebCore/Modules/webauthn/fido/FidoConstants.h (modified) (1 diff)
-
WebKit/ChangeLog (modified) (1 diff)
-
WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorManager.cpp (modified) (1 diff)
-
WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorManager.h (modified) (1 diff)
-
WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorUtils.h (modified) (1 diff)
-
WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorUtils.mm (modified) (2 diffs)
-
WebKit/UIProcess/WebAuthentication/Virtual/VirtualHidConnection.cpp (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r291623 r291624 1 2022-03-22 J Pascoe <j_pascoe@apple.com> 2 3 [WebAuthn] Support getAssertion for virtual HID authenticators 4 https://bugs.webkit.org/show_bug.cgi?id=238154 5 rdar://problem/90593150 6 7 Reviewed by Brent Fulgham. 8 9 Virtual authenticators for WebAuthn support different transprots: nfc, usb, internal, 10 and ble. Currently, we only fully support the internal transport and makeCredential for 11 usb-transport. The default transport for web-platform-tests is usb. This patch implements 12 getAssertion for hid-based virtual authneticators. 13 14 * Modules/webauthn/WebAuthenticationUtils.cpp: 15 (WebCore::buildUserEntityMap): 16 (WebCore::buildCredentialDescriptor): 17 * Modules/webauthn/WebAuthenticationUtils.h: 18 * Modules/webauthn/fido/FidoConstants.h: 19 1 20 2022-03-22 Ricky Mondello <rmondello@apple.com> 2 21 -
trunk/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.cpp
r291423 r291624 30 30 31 31 #include "CBORWriter.h" 32 #include "FidoConstants.h" 32 33 #include "WebAuthenticationConstants.h" 33 34 #include <pal/crypto/CryptoDigest.h> … … 86 87 87 88 return attestedCredentialData; 89 } 90 91 cbor::CBORValue::MapValue buildUserEntityMap(const Vector<uint8_t>& userId, const String& name, const String& displayName) 92 { 93 cbor::CBORValue::MapValue userEntityMap; 94 userEntityMap[cbor::CBORValue(fido::kEntityIdMapKey)] = cbor::CBORValue(userId); 95 userEntityMap[cbor::CBORValue(fido::kEntityNameMapKey)] = cbor::CBORValue(name); 96 userEntityMap[cbor::CBORValue(fido::kDisplayNameMapKey)] = cbor::CBORValue(displayName); 97 return userEntityMap; 98 } 99 100 cbor::CBORValue::MapValue buildCredentialDescriptor(const Vector<uint8_t>& credentialId) 101 { 102 cbor::CBORValue::MapValue credential; 103 credential[cbor::CBORValue("id")] = cbor::CBORValue(credentialId); 104 return credential; 88 105 } 89 106 -
trunk/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.h
r291423 r291624 52 52 WEBCORE_EXPORT cbor::CBORValue::MapValue buildAttestationMap(Vector<uint8_t>&&, String&&, cbor::CBORValue::MapValue&&, const AttestationConveyancePreference&); 53 53 54 WEBCORE_EXPORT cbor::CBORValue::MapValue buildCredentialDescriptor(const Vector<uint8_t>& credentialId); 55 54 56 // https://www.w3.org/TR/webauthn/#attestation-object 55 57 WEBCORE_EXPORT Vector<uint8_t> buildAttestationObject(Vector<uint8_t>&& authData, String&& format, cbor::CBORValue::MapValue&& statementMap, const AttestationConveyancePreference&); … … 59 61 WEBCORE_EXPORT Vector<uint8_t> buildClientDataJsonHash(const ArrayBuffer& clientDataJson); 60 62 63 WEBCORE_EXPORT cbor::CBORValue::MapValue buildUserEntityMap(const Vector<uint8_t>& userId, const String& name, const String& displayName); 61 64 } // namespace WebCore 62 65 -
trunk/Source/WebCore/Modules/webauthn/fido/FidoConstants.h
r291423 r291624 267 267 const int64_t kCtapMakeCredentialExtensionsKey = 6; 268 268 const int64_t kCtapMakeCredentialRequestOptionsKey = 7; 269 270 const int64_t kCtapGetAssertionRpIdKey = 1; 271 const int64_t kCtapGetAssertionClientDataHashKey = 2; 272 const int64_t kCtapGetAssertionAllowListKey = 3; 273 const int64_t kCtapGetAssertionExtensionsKey = 4; 269 274 const int64_t kCtapGetAssertionRequestOptionsKey = 5; 275 const int64_t kCtapGetAssertionPinUvAuthParamKey = 6; 276 const int64_t kCtapGetAssertionPinUvAuthProtocolKey = 7; 270 277 271 278 } // namespace fido -
trunk/Source/WebKit/ChangeLog
r291622 r291624 1 2022-03-22 J Pascoe <j_pascoe@apple.com> 2 3 [WebAuthn] Support getAssertion for virtual HID authenticators 4 https://bugs.webkit.org/show_bug.cgi?id=238154 5 rdar://problem/90593150 6 7 Reviewed by Brent Fulgham. 8 9 Virtual authenticators for WebAuthn support different transports: nfc, usb, internal, 10 and ble. Currently, we only fully support the internal transport and makeCredential for 11 usb-transport. The default transport for web-platform-tests is usb. This patch implements 12 getAssertion for hid-based virtual authneticators. 13 14 Tested via manually creating virtual authenticator and performing create / get. 15 16 * UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorManager.cpp: 17 (WebKit::VirtualAuthenticatorManager::addCredential): 18 (WebKit::VirtualAuthenticatorManager::credentialsMatchingList): 19 * UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorManager.h: 20 * UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorUtils.h: 21 * UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorUtils.mm: 22 (WebKit::privateKeyFromBase64): 23 (WebKit::signatureForPrivateKey): 24 * UIProcess/WebAuthentication/Virtual/VirtualHidConnection.cpp: 25 (WebKit::VirtualHidConnection::parseRequest): 26 1 27 2022-03-22 Jer Noble <jer.noble@apple.com> 2 28 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorManager.cpp
r291423 r291624 58 58 } 59 59 60 void VirtualAuthenticatorManager::addCredential(const String& authenticatorId, constVirtualCredential& credential)60 void VirtualAuthenticatorManager::addCredential(const String& authenticatorId, VirtualCredential& credential) 61 61 { 62 m_credentialsByAuthenticator.get(authenticatorId).append(credential); 62 m_credentialsByAuthenticator.find(authenticatorId)->value.append(WTFMove(credential)); 63 } 64 65 Vector<VirtualCredential> VirtualAuthenticatorManager::credentialsMatchingList(const String& authenticatorId, const String& rpId, const Vector<Vector<uint8_t>>& credentialIds) 66 { 67 Vector<VirtualCredential> matching; 68 auto it = m_credentialsByAuthenticator.find(authenticatorId); 69 for (auto& credential : it->value) { 70 if (credential.rpId == rpId && ((credentialIds.isEmpty() && credential.isResidentCredential) || credentialIds.contains(credential.credentialId))) 71 matching.append(credential); 72 } 73 return matching; 63 74 } 64 75 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorManager.h
r291423 r291624 45 45 bool isVirtual() const final { return true; } 46 46 47 void addCredential(const String&, const VirtualCredential&); 47 void addCredential(const String&, VirtualCredential&); 48 Vector<VirtualCredential> credentialsMatchingList(const String& authenticatorId, const String& rpId, const Vector<Vector<uint8_t>>& credentialIds); 48 49 49 50 protected: -
trunk/Source/WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorUtils.h
r291423 r291624 36 36 std::pair<Vector<uint8_t>, Vector<uint8_t>> credentialIdAndCosePubKeyForPrivateKey(RetainPtr<SecKeyRef> privateKey); 37 37 String base64PrivateKey(RetainPtr<SecKeyRef> privateKey); 38 RetainPtr<SecKeyRef> privateKeyFromBase64(const String& base64PrivateKey); 39 Vector<uint8_t> signatureForPrivateKey(RetainPtr<SecKeyRef> privateKey, const Vector<uint8_t>& authData, const Vector<uint8_t>& clientDataHash); 38 40 39 41 } // namespace WebKit -
trunk/Source/WebKit/UIProcess/WebAuthentication/Virtual/VirtualAuthenticatorUtils.mm
r291423 r291624 33 33 #include <WebCore/WebAuthenticationUtils.h> 34 34 #include <pal/crypto/CryptoDigest.h> 35 #include <wtf/cocoa/TypeCastsCocoa.h> 36 #include <wtf/cocoa/VectorCocoa.h> 35 37 36 38 namespace WebKit { … … 110 112 } 111 113 114 RetainPtr<SecKeyRef> privateKeyFromBase64(const String& base64PrivateKey) 115 { 116 NSDictionary* options = @{ 117 (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, 118 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, 119 (id)kSecAttrKeySizeInBits: @256, 120 }; 121 RetainPtr<NSData> privateKey = adoptNS([[NSData alloc] initWithBase64EncodedString:base64PrivateKey options:0]); 122 CFErrorRef errorRef = nullptr; 123 auto key = adoptCF(SecKeyCreateWithData( 124 bridge_cast(privateKey.get()), 125 bridge_cast(options), 126 &errorRef 127 )); 128 ASSERT(!errorRef); 129 return key; 130 } 131 132 Vector<uint8_t> signatureForPrivateKey(RetainPtr<SecKeyRef> privateKey, const Vector<uint8_t>& authData, const Vector<uint8_t>& clientDataHash) 133 { 134 NSMutableData *dataToSign = [NSMutableData dataWithBytes:authData.data() length:authData.size()]; 135 [dataToSign appendBytes:clientDataHash.data() length:clientDataHash.size()]; 136 RetainPtr<CFDataRef> signature; 137 { 138 CFErrorRef errorRef = nullptr; 139 signature = adoptCF(SecKeyCreateSignature((__bridge SecKeyRef)((id)privateKey.get()), kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, &errorRef)); 140 auto retainError = adoptCF(errorRef); 141 ASSERT(!errorRef); 142 } 143 144 return vectorFromNSData((NSData *)signature.get()); 145 } 146 112 147 } // namespace WebKit 113 148 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Virtual/VirtualHidConnection.cpp
r291423 r291624 213 213 } 214 214 credential.userHandle = it->second.getByteString(); 215 215 auto credentialIdAndCosePubKey = credentialIdAndCosePubKeyForPrivateKey(privateKey); 216 credential.credentialId = credentialIdAndCosePubKey.first; 216 217 manager->addCredential(m_authenticatorId, credential); 217 auto credentialIdAndCosePubKey = credentialIdAndCosePubKeyForPrivateKey(privateKey);218 218 219 219 auto attestedCredentialData = buildAttestedCredentialData(Vector<uint8_t>(aaguidLength, 0), credentialIdAndCosePubKey.first, credentialIdAndCosePubKey.second); … … 221 221 auto authenticatorData = buildAuthData(credential.rpId, flagsForConfig(m_configuration), credential.signCount, attestedCredentialData); 222 222 CBORValue::MapValue response; 223 response[CBORValue(1)] = CBORValue("none"); 223 224 response[CBORValue(2)] = CBORValue(authenticatorData); 224 225 225 auto attObj = buildAttestationMap(WTFMove(authenticatorData), "", { }, AttestationConveyancePreference::None); 226 227 response[CBORValue(1)] = CBORValue("none");228 226 response[CBORValue(3)] = CBORValue(attObj); 229 227 auto payload = CBORWriter::write(CBORValue(response)); … … 235 233 auto message = FidoHidMessage::create(m_requestMessage->channelId(), FidoHidDeviceCommand::kCbor, WTFMove(buffer)); 236 234 receiveHidMessage(WTFMove(*message)); 235 } else if (cmd == CtapRequestCommand::kAuthenticatorGetAssertion) { 236 auto it = requestMap->getMap().find(CBORValue(kCtapGetAssertionRpIdKey)); 237 if (it == requestMap->getMap().end()) { 238 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrMissingParameter); 239 return; 240 } 241 auto rpId = it->second.getString(); 242 (void)rpId; 243 it = requestMap->getMap().find(CBORValue(kCtapGetAssertionClientDataHashKey)); 244 if (it == requestMap->getMap().end()) { 245 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrMissingParameter); 246 return; 247 } 248 auto clientDataHash = it->second.getByteString(); 249 (void)clientDataHash; 250 Vector<Vector<uint8_t>> allowList; 251 it = requestMap->getMap().find(CBORValue(kCtapGetAssertionAllowListKey)); 252 if (it != requestMap->getMap().end()) { 253 const auto& cborAllowList = it->second.getArray(); 254 if (cborAllowList.isEmpty()) { 255 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrInvalidOption); 256 return; 257 } 258 259 for (const auto& cborCredential : cborAllowList) { 260 auto& credMap = cborCredential.getMap(); 261 auto itr = credMap.find(CBORValue(fido::kEntityIdMapKey)); 262 if (itr == credMap.end() || !itr->second.isByteString()) { 263 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrInvalidOption); 264 return; 265 } 266 allowList.append(itr->second.getByteString()); 267 } 268 } 269 270 it = requestMap->getMap().find(CBORValue(kCtapGetAssertionRequestOptionsKey)); 271 if (it != requestMap->getMap().end()) { 272 auto& optionMap = it->second.getMap(); 273 274 auto itr = optionMap.find(CBORValue(kUserVerificationMapKey)); 275 if (itr != optionMap.end()) { 276 auto requireUserVerification = itr->second.getBool(); 277 if (requireUserVerification && !m_configuration.hasUserVerification) { 278 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrInvalidOption); 279 return; 280 } 281 if (requireUserVerification && !m_configuration.isUserVerified) { 282 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrOperationDenied); 283 return; 284 } 285 } 286 287 itr = optionMap.find(CBORValue(kUserPresenceMapKey)); 288 if (itr != optionMap.end()) { 289 auto requireUserPresence = itr->second.getBool(); 290 if (requireUserPresence && !m_configuration.isUserConsenting) { 291 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrOperationDenied); 292 return; 293 } 294 } 295 } 296 auto matchingCredentials = m_manager->credentialsMatchingList(m_authenticatorId, rpId, allowList); 297 if (matchingCredentials.isEmpty()) { 298 recieveResponseCode(CtapDeviceResponseCode::kCtap2ErrNoCredentials); 299 return; 300 } 301 auto& credential = matchingCredentials[0]; 302 CBORValue::MapValue response; 303 304 response[CBORValue(1)] = CBORValue(buildCredentialDescriptor(credential.credentialId)); 305 auto key = privateKeyFromBase64(credential.privateKey); 306 auto credentialIdAndCosePubKey = credentialIdAndCosePubKeyForPrivateKey(key); 307 auto attestedCredentialData = buildAttestedCredentialData(Vector<uint8_t>(aaguidLength, 0), credentialIdAndCosePubKey.first, credentialIdAndCosePubKey.second); 308 auto authData = buildAuthData(rpId, flagsForConfig(m_configuration), credential.signCount, attestedCredentialData); 309 response[CBORValue(2)] = CBORValue(authData); 310 response[CBORValue(3)] = CBORValue(signatureForPrivateKey(key, authData, clientDataHash)); 311 if (credential.userHandle) 312 response[CBORValue(4)] = CBORValue(buildUserEntityMap(*credential.userHandle, "", "")); 313 response[CBORValue(5)] = CBORValue((int64_t)matchingCredentials.size()); 314 auto payload = CBORWriter::write(CBORValue(response)); 315 Vector<uint8_t> buffer; 316 buffer.reserveCapacity(payload->size() + 1); 317 buffer.append(static_cast<uint8_t>(fido::CtapDeviceResponseCode::kSuccess)); 318 buffer.appendVector(*payload); 319 320 auto message = FidoHidMessage::create(m_requestMessage->channelId(), FidoHidDeviceCommand::kCbor, WTFMove(buffer)); 321 receiveHidMessage(WTFMove(*message)); 237 322 } 238 323 break;
Note: See TracChangeset
for help on using the changeset viewer.