WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-191516-20200107101224.patch (text/plain), 83.55 KB, created by
Jiewen Tan
on 2020-01-07 10:12:25 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Jiewen Tan
Created:
2020-01-07 10:12:25 PST
Size:
83.55 KB
patch
obsolete
>Subversion Revision: 254052 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 1f8ab1055afe90e5699594e4becbb5d7277c76f4..d46b42a14b92625ed1e92a3b65c60fa0b16b0b55 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,35 @@ >+2020-01-06 Jiewen Tan <jiewen_tan@apple.com> >+ >+ [WebAuthn] Support CTAP Client Pin >+ https://bugs.webkit.org/show_bug.cgi?id=191516 >+ <rdar://problem/56558558> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Covered by API tests. >+ >+ * Modules/webauthn/fido/DeviceRequestConverter.cpp: >+ (fido::encodeMakeCredenitalRequestAsCBOR): >+ (fido::encodeGetAssertionRequestAsCBOR): >+ * Modules/webauthn/fido/Pin.cpp: >+ (fido::pin::RetriesResponse::parse): >+ (fido::pin::TokenResponse::parse): >+ (fido::pin::TokenRequest::tryCreate): >+ (fido::pin::encodeAsCBOR): >+ * Modules/webauthn/fido/Pin.h: >+ * crypto/algorithms/CryptoAlgorithmAES_CBC.h: >+ * crypto/gcrypt/CryptoAlgorithmAES_CBCGCrypt.cpp: >+ (WebCore::CryptoAlgorithmAES_CBC::platformEncrypt): >+ (WebCore::CryptoAlgorithmAES_CBC::platformDecrypt): >+ * crypto/mac/CryptoAlgorithmAES_CBCMac.cpp: >+ (WebCore::transformAES_CBC): >+ (WebCore::CryptoAlgorithmAES_CBC::platformEncrypt): >+ (WebCore::CryptoAlgorithmAES_CBC::platformDecrypt): >+ * testing/MockWebAuthenticationConfiguration.h: >+ (WebCore::MockWebAuthenticationConfiguration::HidConfiguration::encode const): >+ (WebCore::MockWebAuthenticationConfiguration::HidConfiguration::decode): >+ * testing/MockWebAuthenticationConfiguration.idl: >+ > 2020-01-06 Per Arne Vollan <pvollan@apple.com> > > [iOS] Issue mach lookup extension to launch services daemon for Mail >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 99c372701fc3330434419a6da5b366b187a7f7e7..0bbe389ad83ddad05e4063667fce20117c2cd171 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,60 @@ >+2020-01-06 Jiewen Tan <jiewen_tan@apple.com> >+ >+ [WebAuthn] Support CTAP Client Pin >+ https://bugs.webkit.org/show_bug.cgi?id=191516 >+ <rdar://problem/56558558> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch implements authenticatorClientPIN from the spec: >+ https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorClientPIN >+ Specifically, it implements section 5.5.1, 5.5.3, 5.5.4, 5.5.7, and 5.5.8. >+ >+ Here is the flow how makeCredential/getAssertion works with a PIN in our implementation: >+ 1. Determine if the connected authenticator has a PIN; >+ 2. If yes, send the makeCredential/getAssertion request to the authenticator with an empty pinAuth >+ such that the authenticator will wink for user gestures. This step intends to confirm the authenticator >+ is the one the user wants to use. Otherwise, we don't know which authenticator to send the PIN >+ if multiple are connected; >+ 3. Once the user confirms the authetnicator, it will return either CTAP2_ERR_PIN_INVALID or >+ CTAP2_ERR_PIN_AUTH_INVALID. Some authenticators return CTAP2_ERR_PIN_AUTH_INVALID even though >+ it is not suggested by the spec; >+ 4. Get retries from the authenticator; >+ 5. Get key agreement from the authenticator; >+ 6. Ask the UI client for the PIN and at the meantime inform it the retries; >+ 7. Get pin token from the authenticator; >+ 8. Resend the makeCredential/getAssertion request with the desired pinAuth. >+ >+ Besides implementating the above flow, this patch also fixes some bugs within the PIN commands encoder: >+ 1. pinAuth/pinProtocol are wrongly encoded for makeCredential/getAssertion; >+ 2. AES CBC should be called without any padding. Therefore, CryptoAlgorithmAES_CBC adds a no padding mode; >+ 3. The sharedSecret is the SHA256 digest of the ECDH key agreement instead of the raw key agreement. >+ >+ * UIProcess/API/APIWebAuthenticationPanelClient.h: >+ (API::WebAuthenticationPanelClient::requestPin const): >+ * UIProcess/WebAuthentication/Authenticator.h: >+ * UIProcess/WebAuthentication/AuthenticatorManager.cpp: >+ (WebKit::AuthenticatorManager::requestPin): >+ * UIProcess/WebAuthentication/AuthenticatorManager.h: >+ * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h: >+ * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm: >+ (WebKit::WebAuthenticationPanelClient::WebAuthenticationPanelClient): >+ (WebKit::WebAuthenticationPanelClient::requestPin const): >+ * UIProcess/WebAuthentication/Mock/MockHidConnection.cpp: >+ (WebKit::MockHidConnection::feedReports): >+ * UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp: >+ (WebKit::CtapAuthenticator::makeCredential): >+ (WebKit::CtapAuthenticator::continueMakeCredentialAfterResponseReceived): >+ (WebKit::CtapAuthenticator::getAssertion): >+ (WebKit::CtapAuthenticator::continueGetAssertionAfterResponseReceived): >+ (WebKit::CtapAuthenticator::getRetries): >+ (WebKit::CtapAuthenticator::continueGetKeyAgreementAfterGetRetries): >+ (WebKit::CtapAuthenticator::continueRequestPinAfterGetKeyAgreement): >+ (WebKit::CtapAuthenticator::continueGetPinTokenAfterRequestPin): >+ (WebKit::CtapAuthenticator::continueRequestAfterGetPinToken): >+ (WebKit::CtapAuthenticator::continueMakeCredentialAfterResponseReceived const): Deleted. >+ * UIProcess/WebAuthentication/fido/CtapAuthenticator.h: >+ > 2020-01-06 Per Arne Vollan <pvollan@apple.com> > > [iOS] Issue mach lookup extension to launch services daemon for Mail >diff --git a/Source/WebCore/Modules/webauthn/fido/DeviceRequestConverter.cpp b/Source/WebCore/Modules/webauthn/fido/DeviceRequestConverter.cpp >index b96dabb59869c425bdbba47e93f5d30098aa9d89..155e5d1ee2e3f85d744920e4aa38b9e8d9a72644 100644 >--- a/Source/WebCore/Modules/webauthn/fido/DeviceRequestConverter.cpp >+++ b/Source/WebCore/Modules/webauthn/fido/DeviceRequestConverter.cpp >@@ -126,8 +126,8 @@ Vector<uint8_t> encodeMakeCredenitalRequestAsCBOR(const Vector<uint8_t>& hash, c > > if (pin) { > ASSERT(pin->protocol >= 0); >- cborMap[CBORValue(8)] = CBORValue(pin->protocol); >- cborMap[CBORValue(9)] = CBORValue(WTFMove(pin->auth)); >+ cborMap[CBORValue(8)] = CBORValue(WTFMove(pin->auth)); >+ cborMap[CBORValue(9)] = CBORValue(pin->protocol); > } > > auto serializedParam = CBORWriter::write(CBORValue(WTFMove(cborMap))); >@@ -172,8 +172,8 @@ Vector<uint8_t> encodeGetAssertionRequestAsCBOR(const Vector<uint8_t>& hash, con > > if (pin) { > ASSERT(pin->protocol >= 0); >- cborMap[CBORValue(8)] = CBORValue(pin->protocol); >- cborMap[CBORValue(9)] = CBORValue(WTFMove(pin->auth)); >+ cborMap[CBORValue(6)] = CBORValue(WTFMove(pin->auth)); >+ cborMap[CBORValue(7)] = CBORValue(pin->protocol); > } > > auto serializedParam = CBORWriter::write(CBORValue(WTFMove(cborMap))); >diff --git a/Source/WebCore/Modules/webauthn/fido/Pin.cpp b/Source/WebCore/Modules/webauthn/fido/Pin.cpp >index 7f0c659d84d1bd27d2a56b84bee918ef58326a38..e19a1d3c3b05d099970ca88ce723bd9692b52ca0 100644 >--- a/Source/WebCore/Modules/webauthn/fido/Pin.cpp >+++ b/Source/WebCore/Modules/webauthn/fido/Pin.cpp >@@ -126,7 +126,7 @@ Optional<RetriesResponse> RetriesResponse::parse(const Vector<uint8_t>& inBuffer > return WTF::nullopt; > > RetriesResponse ret; >- ret.retries = static_cast<int64_t>(it->second.getUnsigned()); >+ ret.retries = static_cast<uint64_t>(it->second.getUnsigned()); > return ret; > } > >@@ -227,7 +227,7 @@ Optional<TokenResponse> TokenResponse::parse(const WebCore::CryptoKeyAES& shared > return WTF::nullopt; > const auto& encryptedToken = it->second.getByteString(); > >- auto tokenResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, sharedKey, encryptedToken); >+ auto tokenResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, sharedKey, encryptedToken, CryptoAlgorithmAES_CBC::Padding::No); > if (tokenResult.hasException()) > return WTF::nullopt; > auto token = tokenResult.releaseReturnValue(); >@@ -267,11 +267,16 @@ Optional<TokenRequest> TokenRequest::tryCreate(const CString& pin, const CryptoK > ASSERT(!keyPairResult.hasException()); > auto keyPair = keyPairResult.releaseReturnValue(); > >- // 2. Use ECDH to compute the shared AES-CBC key. >+ // 2. Use ECDH and SHA-256 to compute the shared AES-CBC key. > auto sharedKeyResult = CryptoAlgorithmECDH::platformDeriveBits(downcast<CryptoKeyEC>(*keyPair.privateKey), peerKey); > if (!sharedKeyResult) > return WTF::nullopt; >- auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(*sharedKeyResult), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt); >+ >+ auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); >+ crypto->addBytes(sharedKeyResult->data(), sharedKeyResult->size()); >+ auto sharedKeyHash = crypto->computeHash(); >+ >+ auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(sharedKeyHash), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt); > ASSERT(sharedKey); > > // The following encodes the public key of the above key pair into COSE format. >@@ -280,7 +285,7 @@ Optional<TokenRequest> TokenRequest::tryCreate(const CString& pin, const CryptoK > auto coseKey = encodeCOSEPublicKey(rawPublicKeyResult.returnValue()); > > // The following calculates a SHA-256 digest of the PIN, and shrink to the left 16 bytes. >- auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); >+ crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); > crypto->addBytes(pin.data(), pin.length()); > auto pinHash = crypto->computeHash(); > pinHash.shrink(16); >@@ -302,7 +307,7 @@ const CryptoKeyAES& TokenRequest::sharedKey() const > > Vector<uint8_t> encodeAsCBOR(const TokenRequest& request) > { >- auto result = CryptoAlgorithmAES_CBC::platformEncrypt({ }, request.sharedKey(), request.m_pinHash); >+ auto result = CryptoAlgorithmAES_CBC::platformEncrypt({ }, request.sharedKey(), request.m_pinHash, CryptoAlgorithmAES_CBC::Padding::No); > ASSERT(!result.hasException()); > > return encodePinCommand(Subcommand::kGetPinToken, [coseKey = WTFMove(request.m_coseKey), encryptedPin = result.releaseReturnValue()] (CBORValue::MapValue* map) mutable { >diff --git a/Source/WebCore/Modules/webauthn/fido/Pin.h b/Source/WebCore/Modules/webauthn/fido/Pin.h >index 35743a00307dcfbd9e488d95d0be0b27480e596b..f5b1eca2f54ab272f5f4d1f57cdc58471250b381 100644 >--- a/Source/WebCore/Modules/webauthn/fido/Pin.h >+++ b/Source/WebCore/Modules/webauthn/fido/Pin.h >@@ -79,7 +79,7 @@ enum class ResponseKey : uint8_t { > > // kProtocolVersion is the version of the PIN protocol that this code > // implements. >-constexpr int kProtocolVersion = 1; >+constexpr int64_t kProtocolVersion = 1; > > // encodeCOSEPublicKey takes a raw ECDH256 public key and returns it as a COSE structure. > WEBCORE_EXPORT cbor::CBORValue::MapValue encodeCOSEPublicKey(const Vector<uint8_t>& key); >@@ -110,7 +110,7 @@ struct RetriesResponse { > > // retries is the number of PIN attempts remaining before the authenticator > // locks. >- int retries; >+ uint64_t retries; > > private: > RetriesResponse(); >@@ -145,7 +145,7 @@ public: > > // sharedKey returns the shared ECDH key that was used to encrypt the PIN. > // This is needed to decrypt the response. >- const WebCore::CryptoKeyAES& sharedKey() const; >+ WEBCORE_EXPORT const WebCore::CryptoKeyAES& sharedKey() const; > > friend Vector<uint8_t> encodeAsCBOR(const TokenRequest&); > >diff --git a/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h b/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h >index fd98912b70dc0b51d1b98790664d72b46e3428fe..2732985b77fedfc39674d4749d89550a0a171c26 100644 >--- a/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h >+++ b/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h >@@ -36,13 +36,18 @@ class CryptoKeyAES; > > class CryptoAlgorithmAES_CBC final : public CryptoAlgorithm { > public: >+ enum class Padding : uint8_t { >+ Yes, >+ No >+ }; >+ > static constexpr const char* s_name = "AES-CBC"; > static constexpr CryptoAlgorithmIdentifier s_identifier = CryptoAlgorithmIdentifier::AES_CBC; > static Ref<CryptoAlgorithm> create(); > > // Operations can be performed directly. >- WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformEncrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&); >- WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformDecrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&); >+ WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformEncrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&, Padding padding = Padding::Yes); >+ WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformDecrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&, Padding padding = Padding::Yes); > > private: > CryptoAlgorithmAES_CBC() = default; >diff --git a/Source/WebCore/crypto/gcrypt/CryptoAlgorithmAES_CBCGCrypt.cpp b/Source/WebCore/crypto/gcrypt/CryptoAlgorithmAES_CBCGCrypt.cpp >index 98a6b219be202f335379a5518786fcc24cca2253..a51b66d8dde81134b5830c2a6a099d81ab0ced58 100644 >--- a/Source/WebCore/crypto/gcrypt/CryptoAlgorithmAES_CBCGCrypt.cpp >+++ b/Source/WebCore/crypto/gcrypt/CryptoAlgorithmAES_CBCGCrypt.cpp >@@ -166,7 +166,7 @@ static Optional<Vector<uint8_t>> gcryptDecrypt(const Vector<uint8_t>& key, const > return output; > } > >-ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText) >+ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText, Padding) > { > auto output = gcryptEncrypt(key.key(), parameters.ivVector(), Vector<uint8_t>(plainText)); > if (!output) >@@ -174,7 +174,7 @@ ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const Crypt > return WTFMove(*output); > } > >-ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText) >+ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText, Padding) > { > auto output = gcryptDecrypt(key.key(), parameters.ivVector(), cipherText); > if (!output) >diff --git a/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp b/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp >index 517cfc89b9737149c4807b85ad1f20dfa0aac1db..c57f10799d110ab0b4fc1e92b1714463cfb9d344 100644 >--- a/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp >+++ b/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp >@@ -34,10 +34,11 @@ > > namespace WebCore { > >-static ExceptionOr<Vector<uint8_t>> transformAES_CBC(CCOperation operation, const Vector<uint8_t>& iv, const Vector<uint8_t>& key, const Vector<uint8_t>& data) >+static ExceptionOr<Vector<uint8_t>> transformAES_CBC(CCOperation operation, const Vector<uint8_t>& iv, const Vector<uint8_t>& key, const Vector<uint8_t>& data, CryptoAlgorithmAES_CBC::Padding padding) > { >+ CCOptions options = padding == CryptoAlgorithmAES_CBC::Padding::Yes ? kCCOptionPKCS7Padding : 0; > CCCryptorRef cryptor; >- CCCryptorStatus status = CCCryptorCreate(operation, kCCAlgorithmAES, kCCOptionPKCS7Padding, key.data(), key.size(), iv.data(), &cryptor); >+ CCCryptorStatus status = CCCryptorCreate(operation, kCCAlgorithmAES, options, key.data(), key.size(), iv.data(), &cryptor); > if (status) > return Exception { OperationError }; > >@@ -49,10 +50,12 @@ static ExceptionOr<Vector<uint8_t>> transformAES_CBC(CCOperation operation, cons > return Exception { OperationError }; > > uint8_t* p = result.data() + bytesWritten; >- status = CCCryptorFinal(cryptor, p, result.end() - p, &bytesWritten); >- p += bytesWritten; >- if (status) >- return Exception { OperationError }; >+ if (padding == CryptoAlgorithmAES_CBC::Padding::Yes) { >+ status = CCCryptorFinal(cryptor, p, result.end() - p, &bytesWritten); >+ p += bytesWritten; >+ if (status) >+ return Exception { OperationError }; >+ } > > ASSERT(p <= result.end()); > result.shrink(p - result.begin()); >@@ -62,16 +65,18 @@ static ExceptionOr<Vector<uint8_t>> transformAES_CBC(CCOperation operation, cons > return WTFMove(result); > } > >-ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText) >+ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText, Padding padding) > { > ASSERT(parameters.ivVector().size() == kCCBlockSizeAES128 || parameters.ivVector().isEmpty()); >- return transformAES_CBC(kCCEncrypt, parameters.ivVector(), key.key(), plainText); >+ ASSERT(padding == Padding::Yes || !(plainText.size() % kCCBlockSizeAES128)); >+ return transformAES_CBC(kCCEncrypt, parameters.ivVector(), key.key(), plainText, padding); > } > >-ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText) >+ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText, Padding padding) > { > ASSERT(parameters.ivVector().size() == kCCBlockSizeAES128 || parameters.ivVector().isEmpty()); >- return transformAES_CBC(kCCDecrypt, parameters.ivVector(), key.key(), cipherText); >+ ASSERT(padding == Padding::Yes || !(cipherText.size() % kCCBlockSizeAES128)); >+ return transformAES_CBC(kCCDecrypt, parameters.ivVector(), key.key(), cipherText, padding); > } > > } // namespace WebCore >diff --git a/Source/WebCore/testing/MockWebAuthenticationConfiguration.h b/Source/WebCore/testing/MockWebAuthenticationConfiguration.h >index 328bb9d4eaafc75d83c71a7c7274d1650367d20b..629558f7fbdf012f1e6413f79e54775a3ced2541 100644 >--- a/Source/WebCore/testing/MockWebAuthenticationConfiguration.h >+++ b/Source/WebCore/testing/MockWebAuthenticationConfiguration.h >@@ -84,6 +84,7 @@ struct MockWebAuthenticationConfiguration { > bool continueAfterErrorData { false }; > bool canDowngrade { false }; > bool expectCancel { false }; >+ bool supportClientPin { false }; > > template<class Encoder> void encode(Encoder&) const; > template<class Decoder> static Optional<HidConfiguration> decode(Decoder&); >@@ -161,7 +162,7 @@ Optional<MockWebAuthenticationConfiguration::LocalConfiguration> MockWebAuthenti > template<class Encoder> > void MockWebAuthenticationConfiguration::HidConfiguration::encode(Encoder& encoder) const > { >- encoder << payloadBase64 << stage << subStage << error << isU2f << keepAlive << fastDataArrival << continueAfterErrorData << canDowngrade << expectCancel; >+ encoder << payloadBase64 << stage << subStage << error << isU2f << keepAlive << fastDataArrival << continueAfterErrorData << canDowngrade << expectCancel << supportClientPin; > } > > template<class Decoder> >@@ -188,6 +189,8 @@ Optional<MockWebAuthenticationConfiguration::HidConfiguration> MockWebAuthentica > return WTF::nullopt; > if (!decoder.decode(result.expectCancel)) > return WTF::nullopt; >+ if (!decoder.decode(result.supportClientPin)) >+ return WTF::nullopt; > return result; > } > >diff --git a/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl b/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl >index 7853851476fccd62284c36bf27942a8b17c5de10..ad139349ad2fc15cad83f6b2d16b0838603dee36 100644 >--- a/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl >+++ b/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl >@@ -92,6 +92,7 @@ > boolean continueAfterErrorData = false; > boolean canDowngrade = false; > boolean expectCancel = false; >+ boolean supportClientPin = false; > }; > > [ >diff --git a/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h b/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h >index 555b5619fd825cdc5bbc0450b789837662ed2944..7ec6243595e84ce341544774ee57cfd0f6491cd1 100644 >--- a/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h >+++ b/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h >@@ -27,6 +27,9 @@ > > #if ENABLE(WEB_AUTHN) > >+#include <wtf/CompletionHandler.h> >+#include <wtf/text/WTFString.h> >+ > namespace WebKit { > enum class WebAuthenticationStatus : bool; > enum class WebAuthenticationResult : bool; >@@ -41,6 +44,7 @@ public: > > virtual void updatePanel(WebKit::WebAuthenticationStatus) const { } > virtual void dismissPanel(WebKit::WebAuthenticationResult) const { } >+ virtual void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&& completionHandler) const { completionHandler(emptyString()); } > }; > > } // namespace API >diff --git a/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h b/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h >index 0d24713bf73bc09e1730a2921649ccc88eb179b3..04666c3705b5903d091c426541f62ec999f363ec 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h >+++ b/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h >@@ -47,6 +47,7 @@ public: > virtual void respondReceived(Respond&&) = 0; > virtual void downgrade(Authenticator* id, Ref<Authenticator>&& downgradedAuthenticator) = 0; > virtual void authenticatorStatusUpdated(WebAuthenticationStatus) = 0; >+ virtual void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) = 0; > }; > > virtual ~Authenticator() = default; >diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp >index 6faede547644ab7d8f96e890d838a1bb13bc089c..746ca0615f5410147bdba5a4ec502d188e629b5f 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp >+++ b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp >@@ -273,6 +273,12 @@ void AuthenticatorManager::authenticatorStatusUpdated(WebAuthenticationStatus st > panel->client().updatePanel(status); > } > >+void AuthenticatorManager::requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&& completionHandler) >+{ >+ if (auto* panel = m_pendingRequestData.panel.get()) >+ panel->client().requestPin(retries, WTFMove(completionHandler)); >+} >+ > UniqueRef<AuthenticatorTransportService> AuthenticatorManager::createService(AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const > { > return AuthenticatorTransportService::create(transport, observer); >diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h >index dc6c4443910010023bb15529809e9eea670efb0e..2a50833fdb9db63dc98c393d09d1c93020df2fa2 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h >+++ b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h >@@ -81,6 +81,7 @@ private: > void respondReceived(Respond&&) final; > void downgrade(Authenticator* id, Ref<Authenticator>&& downgradedAuthenticator) final; > void authenticatorStatusUpdated(WebAuthenticationStatus) final; >+ void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) final; > > // Overriden by MockAuthenticatorManager. > virtual UniqueRef<AuthenticatorTransportService> createService(WebCore::AuthenticatorTransport, AuthenticatorTransportService::Observer&) const; >diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h >index 3b0c8916dc092107584dd70ba010249057474cc6..1499466a1ceca8e9fd90f9cf6142565902a88fbf 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h >+++ b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h >@@ -49,6 +49,7 @@ private: > // API::WebAuthenticationPanelClient > void updatePanel(WebAuthenticationStatus) const final; > void dismissPanel(WebAuthenticationResult) const final; >+ void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&&) const final; > > _WKWebAuthenticationPanel *m_panel; > WeakObjCPtr<id <_WKWebAuthenticationPanelDelegate> > m_delegate; >@@ -56,6 +57,7 @@ private: > struct { > bool panelUpdateWebAuthenticationPanel : 1; > bool panelDismissWebAuthenticationPanelWithResult : 1; >+ bool panelRequestPinWithRemainingRetriesCompletionHandler : 1; > } m_delegateMethods; > }; > >diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm >index 35ef65beef61bbe5ea5139e8330ca73985fe412c..7f157bd98469cd6691fe100f3e35a419738f5e91 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm >+++ b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm >@@ -28,8 +28,10 @@ > > #if ENABLE(WEB_AUTHN) > >+#import "CompletionHandlerCallChecker.h" > #import "WebAuthenticationFlags.h" > #import "_WKWebAuthenticationPanel.h" >+#import <wtf/BlockPtr.h> > #import <wtf/RunLoop.h> > > namespace WebKit { >@@ -40,6 +42,7 @@ WebAuthenticationPanelClient::WebAuthenticationPanelClient(_WKWebAuthenticationP > { > m_delegateMethods.panelUpdateWebAuthenticationPanel = [delegate respondsToSelector:@selector(panel:updateWebAuthenticationPanel:)]; > m_delegateMethods.panelDismissWebAuthenticationPanelWithResult = [delegate respondsToSelector:@selector(panel:dismissWebAuthenticationPanelWithResult:)]; >+ m_delegateMethods.panelRequestPinWithRemainingRetriesCompletionHandler = [delegate respondsToSelector:@selector(panel:requestPINWithRemainingRetries:completionHandler:)]; > } > > RetainPtr<id <_WKWebAuthenticationPanelDelegate> > WebAuthenticationPanelClient::delegate() >@@ -107,6 +110,37 @@ void WebAuthenticationPanelClient::dismissPanel(WebAuthenticationResult result) > }); > } > >+void WebAuthenticationPanelClient::requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&& completionHandler) const >+{ >+ // Call delegates in the next run loop to prevent clients' reentrance that would potentially modify the state >+ // of the current run loop in unexpected ways. >+ RunLoop::main().dispatch([weakThis = makeWeakPtr(*this), this, retries, completionHandler = WTFMove(completionHandler)] () mutable { >+ if (!weakThis) { >+ completionHandler(emptyString()); >+ return; >+ } >+ >+ if (!m_delegateMethods.panelRequestPinWithRemainingRetriesCompletionHandler) { >+ completionHandler(emptyString()); >+ return; >+ } >+ >+ auto delegate = m_delegate.get(); >+ if (!delegate) { >+ completionHandler(emptyString()); >+ return; >+ } >+ >+ auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(panel:requestPINWithRemainingRetries:completionHandler:)); >+ [delegate panel:m_panel requestPINWithRemainingRetries:retries completionHandler:makeBlockPtr([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](NSString *pin) mutable { >+ if (checker->completionHandlerHasBeenCalled()) >+ return; >+ checker->didCallCompletionHandler(); >+ completionHandler(pin); >+ }).get()]; >+ }); >+} >+ > } // namespace WebKit > > #endif // ENABLE(WEB_AUTHN) >diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp >index 9e5d8fa706680df6e14f963f23be9e885e744f55..f99c704bd970b4b3707f799f894c15757cdc702d 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp >+++ b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp >@@ -31,6 +31,7 @@ > #include <WebCore/AuthenticatorGetInfoResponse.h> > #include <WebCore/CBORReader.h> > #include <WebCore/FidoConstants.h> >+#include <WebCore/Pin.h> > #include <WebCore/WebAuthenticationConstants.h> > #include <wtf/BlockPtr.h> > #include <wtf/CryptographicallyRandomNumber.h> >@@ -223,10 +224,18 @@ void MockHidConnection::feedReports() > > Optional<FidoHidMessage> message; > if (m_stage == Mock::HidStage::Info && m_subStage == Mock::HidSubStage::Msg) { >+ // FIXME(205839): > Vector<uint8_t> infoData; > if (m_configuration.hid->canDowngrade) > infoData = encodeAsCBOR(AuthenticatorGetInfoResponse({ ProtocolVersion::kCtap, ProtocolVersion::kU2f }, Vector<uint8_t>(aaguidLength, 0u))); >- else >+ else if (m_configuration.hid->supportClientPin) { >+ AuthenticatorGetInfoResponse infoResponse({ ProtocolVersion::kCtap }, Vector<uint8_t>(aaguidLength, 0u)); >+ infoResponse.setPinProtocols({ pin::kProtocolVersion }); >+ AuthenticatorSupportedOptions options; >+ options.setClientPinAvailability(AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet); >+ infoResponse.setOptions(WTFMove(options)); >+ infoData = encodeAsCBOR(infoResponse); >+ } else > infoData = encodeAsCBOR(AuthenticatorGetInfoResponse({ ProtocolVersion::kCtap }, Vector<uint8_t>(aaguidLength, 0u))); > infoData.insert(0, static_cast<uint8_t>(CtapDeviceResponseCode::kSuccess)); // Prepend status code. > if (stagesMatch() && m_configuration.hid->error == Mock::HidError::WrongChannelId) >diff --git a/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp b/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp >index 9e41eb71adc5844efede40c67dfe233fd86ac5a1..5e40764ace40485166eeb959a78c5cb9ee98f83d 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp >+++ b/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp >@@ -31,9 +31,13 @@ > #include "CtapDriver.h" > #include "CtapHidDriver.h" > #include "U2fAuthenticator.h" >+#include <WebCore/CryptoKeyAES.h> >+#include <WebCore/CryptoKeyEC.h> >+#include <WebCore/CryptoKeyHMAC.h> > #include <WebCore/DeviceRequestConverter.h> > #include <WebCore/DeviceResponseConverter.h> > #include <WebCore/ExceptionData.h> >+#include <WebCore/Pin.h> > #include <WebCore/U2fCommandConstructor.h> > #include <wtf/RunLoop.h> > #include <wtf/text/StringConcatenateNumbers.h> >@@ -53,7 +57,11 @@ void CtapAuthenticator::makeCredential() > ASSERT(!m_isDowngraded); > if (processGoogleLegacyAppIdSupportExtension()) > return; >- auto cborCmd = encodeMakeCredenitalRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options), m_info.options().userVerificationAvailability()); >+ Vector<uint8_t> cborCmd; >+ if (m_info.options().clientPinAvailability() == AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet) >+ cborCmd = encodeMakeCredenitalRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options), m_info.options().userVerificationAvailability(), PinParameters { pin::kProtocolVersion, m_pinAuth }); >+ else >+ cborCmd = encodeMakeCredenitalRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options), m_info.options().userVerificationAvailability()); > driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) { > ASSERT(RunLoop::isMain()); > if (!weakThis) >@@ -62,13 +70,16 @@ void CtapAuthenticator::makeCredential() > }); > } > >-void CtapAuthenticator::continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&& data) const >+void CtapAuthenticator::continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&& data) > { > auto response = readCTAPMakeCredentialResponse(data, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options).attestation); > if (!response) { > auto error = getResponseCode(data); > if (error == CtapDeviceResponseCode::kCtap2ErrCredentialExcluded) > receiveRespond(ExceptionData { InvalidStateError, "At least one credential matches an entry of the excludeCredentials list in the authenticator."_s }); >+ // FIXME(205837) >+ else if (error == CtapDeviceResponseCode::kCtap2ErrPinInvalid || error == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid) >+ getRetries(); > else > receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) }); > return; >@@ -79,7 +90,11 @@ void CtapAuthenticator::continueMakeCredentialAfterResponseReceived(Vector<uint8 > void CtapAuthenticator::getAssertion() > { > ASSERT(!m_isDowngraded); >- auto cborCmd = encodeGetAssertionRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialRequestOptions>(requestData().options), m_info.options().userVerificationAvailability()); >+ Vector<uint8_t> cborCmd; >+ if (m_info.options().clientPinAvailability() == AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet) >+ cborCmd = encodeGetAssertionRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialRequestOptions>(requestData().options), m_info.options().userVerificationAvailability(), PinParameters { pin::kProtocolVersion, m_pinAuth }); >+ else >+ cborCmd = encodeGetAssertionRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialRequestOptions>(requestData().options), m_info.options().userVerificationAvailability()); > driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) { > ASSERT(RunLoop::isMain()); > if (!weakThis) >@@ -93,6 +108,11 @@ void CtapAuthenticator::continueGetAssertionAfterResponseReceived(Vector<uint8_t > auto response = readCTAPGetAssertionResponse(data); > if (!response) { > auto error = getResponseCode(data); >+ // FIXME(205837) >+ if (error == CtapDeviceResponseCode::kCtap2ErrPinInvalid || error == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid) { >+ getRetries(); >+ return; >+ } > if (error != CtapDeviceResponseCode::kCtap2ErrInvalidCBOR && tryDowngrade()) > return; > if (error == CtapDeviceResponseCode::kCtap2ErrNoCredentials && observer()) >@@ -103,6 +123,93 @@ void CtapAuthenticator::continueGetAssertionAfterResponseReceived(Vector<uint8_t > receiveRespond(response.releaseNonNull()); > } > >+void CtapAuthenticator::getRetries() >+{ >+ auto cborCmd = encodeAsCBOR(pin::RetriesRequest { }); >+ driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) { >+ ASSERT(RunLoop::isMain()); >+ if (!weakThis) >+ return; >+ weakThis->continueGetKeyAgreementAfterGetRetries(WTFMove(data)); >+ }); >+} >+ >+void CtapAuthenticator::continueGetKeyAgreementAfterGetRetries(Vector<uint8_t>&& data) >+{ >+ auto retries = pin::RetriesResponse::parse(data); >+ if (!retries) { >+ auto error = getResponseCode(data); >+ receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) }); >+ return; >+ } >+ >+ auto cborCmd = encodeAsCBOR(pin::KeyAgreementRequest { }); >+ driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this), retries = retries->retries] (Vector<uint8_t>&& data) { >+ ASSERT(RunLoop::isMain()); >+ if (!weakThis) >+ return; >+ weakThis->continueRequestPinAfterGetKeyAgreement(WTFMove(data), retries); >+ }); >+} >+ >+void CtapAuthenticator::continueRequestPinAfterGetKeyAgreement(Vector<uint8_t>&& data, uint64_t retries) >+{ >+ auto keyAgreement = pin::KeyAgreementResponse::parse(data); >+ if (!keyAgreement) { >+ auto error = getResponseCode(data); >+ receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) }); >+ return; >+ } >+ >+ if (auto* observer = this->observer()) { >+ observer->requestPin(retries, [weakThis = makeWeakPtr(*this), keyAgreement = WTFMove(*keyAgreement)] (const String& pin) { >+ ASSERT(RunLoop::isMain()); >+ if (!weakThis) >+ return; >+ weakThis->continueGetPinTokenAfterRequestPin(pin, keyAgreement.peerKey); >+ }); >+ } >+} >+ >+void CtapAuthenticator::continueGetPinTokenAfterRequestPin(const String& pin, const CryptoKeyEC& peerKey) >+{ >+ auto pinUtf8 = pin::validateAndConvertToUTF8(pin); >+ if (!pinUtf8) { >+ receiveRespond(ExceptionData { UnknownError, makeString("Pin is not valid: ", pin) }); >+ return; >+ } >+ auto tokenRequest = pin::TokenRequest::tryCreate(*pinUtf8, peerKey); >+ if (!tokenRequest) { >+ receiveRespond(ExceptionData { UnknownError, "Cannot create a TokenRequest."_s }); >+ return; >+ } >+ >+ auto cborCmd = encodeAsCBOR(*tokenRequest); >+ driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this), tokenRequest = WTFMove(*tokenRequest)] (Vector<uint8_t>&& data) { >+ ASSERT(RunLoop::isMain()); >+ if (!weakThis) >+ return; >+ weakThis->continueRequestAfterGetPinToken(WTFMove(data), tokenRequest); >+ }); >+} >+ >+void CtapAuthenticator::continueRequestAfterGetPinToken(Vector<uint8_t>&& data, const fido::pin::TokenRequest& tokenRequest) >+{ >+ auto token = pin::TokenResponse::parse(tokenRequest.sharedKey(), data); >+ if (!token) { >+ auto error = getResponseCode(data); >+ receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) }); >+ return; >+ } >+ >+ m_pinAuth = token->pinAuth(requestData().hash); >+ WTF::switchOn(requestData().options, [&](const PublicKeyCredentialCreationOptions& options) { >+ makeCredential(); >+ }, [&](const PublicKeyCredentialRequestOptions& options) { >+ getAssertion(); >+ }); >+} >+ > bool CtapAuthenticator::tryDowngrade() > { > if (m_info.versions().find(ProtocolVersion::kU2f) == m_info.versions().end()) >diff --git a/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h b/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h >index ee543d85f94d08fa0c6b7a049cdfedf8ef42fc5c..58248ca124485b0adc66783ca0c6ca7a69ea3fdf 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h >+++ b/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h >@@ -30,6 +30,16 @@ > #include "FidoAuthenticator.h" > #include <WebCore/AuthenticatorGetInfoResponse.h> > >+namespace fido { >+namespace pin { >+class TokenRequest; >+} >+} >+ >+namespace WebCore { >+class CryptoKeyEC; >+} >+ > namespace WebKit { > > class CtapDriver; >@@ -45,15 +55,22 @@ private: > explicit CtapAuthenticator(std::unique_ptr<CtapDriver>&&, fido::AuthenticatorGetInfoResponse&&); > > void makeCredential() final; >- void continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&&) const; >+ void continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&&); > void getAssertion() final; > void continueGetAssertionAfterResponseReceived(Vector<uint8_t>&&); > >+ void getRetries(); >+ void continueGetKeyAgreementAfterGetRetries(Vector<uint8_t>&&); >+ void continueRequestPinAfterGetKeyAgreement(Vector<uint8_t>&&, uint64_t retries); >+ void continueGetPinTokenAfterRequestPin(const String& pin, const CryptoKeyEC&); >+ void continueRequestAfterGetPinToken(Vector<uint8_t>&&, const fido::pin::TokenRequest&); >+ > bool tryDowngrade(); > bool processGoogleLegacyAppIdSupportExtension(); > > fido::AuthenticatorGetInfoResponse m_info; > bool m_isDowngraded { false }; >+ Vector<uint8_t> m_pinAuth; > }; > > } // namespace WebKit >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index bff9bdb86b77c649c2fe8642b386bda13c69a4ae..7c27b8e02fc886791d64e513cf29f3ec22786a87 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,25 @@ >+2020-01-06 Jiewen Tan <jiewen_tan@apple.com> >+ >+ [WebAuthn] Support CTAP Client Pin >+ https://bugs.webkit.org/show_bug.cgi?id=191516 >+ <rdar://problem/56558558> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: >+ * TestWebKitAPI/Tests/WebCore/CtapPinTest.cpp: >+ (TestWebKitAPI::TEST): >+ * TestWebKitAPI/Tests/WebCore/FidoTestData.h: >+ * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm: >+ (-[TestWebAuthenticationPanelDelegate panel:requestPINWithRemainingRetries:completionHandler:]): >+ (TestWebKitAPI::TEST): >+ * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-pin.html: Added. >+ * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-key-agreement-error.html: Added. >+ * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-pin-token-error.html: Added. >+ * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-retries-error.html: Added. >+ * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-invalid-key-agreeement.html: Added. >+ * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin.html: Added. >+ > 2020-01-06 Per Arne Vollan <pvollan@apple.com> > > [iOS] Issue mach lookup extension to launch services daemon for Mail >diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >index 68d0060e5a8a0a176a21c79f3d12687dd1b5da67..c7b5f4bab4d0478d7c424dbabc6e2b8b7394f277 100644 >--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >@@ -327,6 +327,11 @@ > 55A817FF2181021A0004A39A /* 100x100-red.tga in Copy Resources */ = {isa = PBXBuildFile; fileRef = 55A817FE218101DF0004A39A /* 100x100-red.tga */; }; > 55A81800218102210004A39A /* 400x400-green.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = 55A817FD218101DF0004A39A /* 400x400-green.png */; }; > 55F9D2E52205031800A9AB38 /* AdditionalSupportedImageTypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55F9D2E42205031800A9AB38 /* AdditionalSupportedImageTypes.mm */; }; >+ 570D26F423C3CA6A00D5CF67 /* web-authentication-make-credential-hid-pin-get-key-agreement-error.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 570D26F323C3CA5500D5CF67 /* web-authentication-make-credential-hid-pin-get-key-agreement-error.html */; }; >+ 570D26F623C3D33000D5CF67 /* web-authentication-make-credential-hid-pin.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 570D26F523C3D32700D5CF67 /* web-authentication-make-credential-hid-pin.html */; }; >+ 570D26FA23C3F25100D5CF67 /* web-authentication-make-credential-hid-pin-get-pin-token-error.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 570D26F923C3F24500D5CF67 /* web-authentication-make-credential-hid-pin-get-pin-token-error.html */; }; >+ 570D26FC23C3F87000D5CF67 /* web-authentication-get-assertion-hid-pin.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */; }; >+ 570D26FE23C4FF3600D5CF67 /* web-authentication-make-credential-hid-pin-invalid-key-agreeement.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 570D26FD23C4FF2500D5CF67 /* web-authentication-make-credential-hid-pin-invalid-key-agreeement.html */; }; > 5714ECB91CA8B5B000051AC8 /* DownloadRequestOriginalURL.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */; }; > 5714ECBB1CA8BFE400051AC8 /* DownloadRequestOriginalURLFrame.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */; }; > 5714ECBD1CA8C22A00051AC8 /* DownloadRequestOriginalURL2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */; }; >@@ -343,6 +348,7 @@ > 573255A722139BC700396AE8 /* load-web-archive-2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 573255A322139B9000396AE8 /* load-web-archive-2.html */; }; > 574F55D2204D47F0002948C6 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 574F55D0204D471C002948C6 /* Security.framework */; }; > 5758597F23A2527A00C74572 /* CtapPinTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5758597E23A2527A00C74572 /* CtapPinTest.cpp */; }; >+ 5758598423C3C3A400C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5758598323C3C36200C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html */; }; > 57599E211F07191900A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm in Sources */ = {isa = PBXBuildFile; fileRef = 57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */; }; > 57599E271F071AA000A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3 in Copy Resources */ = {isa = PBXBuildFile; fileRef = 57599E241F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3 */; }; > 57599E281F071AA000A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3-shm in Copy Resources */ = {isa = PBXBuildFile; fileRef = 57599E261F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3-shm */; }; >@@ -1479,11 +1485,17 @@ > CD577799211CE0E4001B371E /* web-audio-only.html in Copy Resources */, > 57663DF32357E48900E85E09 /* web-authentication-get-assertion-hid-cancel.html in Copy Resources */, > 577454D02359B378008E1ED7 /* web-authentication-get-assertion-hid-no-credentials.html in Copy Resources */, >+ 570D26FC23C3F87000D5CF67 /* web-authentication-get-assertion-hid-pin.html in Copy Resources */, > 57663DEC234F1F9300E85E09 /* web-authentication-get-assertion-hid.html in Copy Resources */, > 579833922368FA37008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html in Copy Resources */, > 57663DEA234EA66D00E85E09 /* web-authentication-get-assertion-nfc.html in Copy Resources */, > 577454D22359BB01008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html in Copy Resources */, > 57C624502346C21E00383FE7 /* web-authentication-get-assertion.html in Copy Resources */, >+ 570D26F423C3CA6A00D5CF67 /* web-authentication-make-credential-hid-pin-get-key-agreement-error.html in Copy Resources */, >+ 570D26FA23C3F25100D5CF67 /* web-authentication-make-credential-hid-pin-get-pin-token-error.html in Copy Resources */, >+ 5758598423C3C3A400C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html in Copy Resources */, >+ 570D26FE23C4FF3600D5CF67 /* web-authentication-make-credential-hid-pin-invalid-key-agreeement.html in Copy Resources */, >+ 570D26F623C3D33000D5CF67 /* web-authentication-make-credential-hid-pin.html in Copy Resources */, > 5798337E236019A4008E5547 /* web-authentication-make-credential-hid.html in Copy Resources */, > 1C2B81861C89259D00A5529F /* webfont.html in Copy Resources */, > 51714EB41CF8C78C004723C4 /* WebProcessKillIDBCleanup-1.html in Copy Resources */, >@@ -1892,6 +1904,11 @@ > 55A817FD218101DF0004A39A /* 400x400-green.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "400x400-green.png"; sourceTree = "<group>"; }; > 55A817FE218101DF0004A39A /* 100x100-red.tga */ = {isa = PBXFileReference; lastKnownFileType = file; path = "100x100-red.tga"; sourceTree = "<group>"; }; > 55F9D2E42205031800A9AB38 /* AdditionalSupportedImageTypes.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = AdditionalSupportedImageTypes.mm; sourceTree = "<group>"; }; >+ 570D26F323C3CA5500D5CF67 /* web-authentication-make-credential-hid-pin-get-key-agreement-error.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin-get-key-agreement-error.html"; sourceTree = "<group>"; }; >+ 570D26F523C3D32700D5CF67 /* web-authentication-make-credential-hid-pin.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin.html"; sourceTree = "<group>"; }; >+ 570D26F923C3F24500D5CF67 /* web-authentication-make-credential-hid-pin-get-pin-token-error.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin-get-pin-token-error.html"; sourceTree = "<group>"; }; >+ 570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-get-assertion-hid-pin.html"; sourceTree = "<group>"; }; >+ 570D26FD23C4FF2500D5CF67 /* web-authentication-make-credential-hid-pin-invalid-key-agreeement.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin-invalid-key-agreeement.html"; sourceTree = "<group>"; }; > 5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURL.html; sourceTree = "<group>"; }; > 5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURLFrame.html; sourceTree = "<group>"; }; > 5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURL2.html; sourceTree = "<group>"; }; >@@ -1910,6 +1927,7 @@ > 574F55D0204D471C002948C6 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; > 5758597D23A2527A00C74572 /* CtapPinTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CtapPinTest.h; sourceTree = "<group>"; }; > 5758597E23A2527A00C74572 /* CtapPinTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CtapPinTest.cpp; sourceTree = "<group>"; }; >+ 5758598323C3C36200C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin-get-retries-error.html"; sourceTree = "<group>"; }; > 57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexedDBStructuredCloneBackwardCompatibility.mm; sourceTree = "<group>"; }; > 57599E231F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibilityWrite.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = IndexedDBStructuredCloneBackwardCompatibilityWrite.html; sourceTree = "<group>"; }; > 57599E241F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3 */ = {isa = PBXFileReference; lastKnownFileType = file; path = IndexedDBStructuredCloneBackwardCompatibility.sqlite3; sourceTree = "<group>"; }; >@@ -3483,11 +3501,17 @@ > CD577798211CDE8F001B371E /* web-audio-only.html */, > 57663DF22357E45D00E85E09 /* web-authentication-get-assertion-hid-cancel.html */, > 577454CF2359B338008E1ED7 /* web-authentication-get-assertion-hid-no-credentials.html */, >+ 570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */, > 57663DEB234F1F8000E85E09 /* web-authentication-get-assertion-hid.html */, > 5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */, > 57663DE9234EA60B00E85E09 /* web-authentication-get-assertion-nfc.html */, > 577454D12359BAD5008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html */, > 57C6244F2346C1EC00383FE7 /* web-authentication-get-assertion.html */, >+ 570D26F323C3CA5500D5CF67 /* web-authentication-make-credential-hid-pin-get-key-agreement-error.html */, >+ 570D26F923C3F24500D5CF67 /* web-authentication-make-credential-hid-pin-get-pin-token-error.html */, >+ 5758598323C3C36200C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html */, >+ 570D26FD23C4FF2500D5CF67 /* web-authentication-make-credential-hid-pin-invalid-key-agreeement.html */, >+ 570D26F523C3D32700D5CF67 /* web-authentication-make-credential-hid-pin.html */, > 5798337D2360196D008E5547 /* web-authentication-make-credential-hid.html */, > 51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */, > 51714EB31CF8C761004723C4 /* WebProcessKillIDBCleanup-2.html */, >diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CtapPinTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CtapPinTest.cpp >index a63aa669959b55bcd147d7325d3effa855e4e857..dfe4c84453fd88da460af38de73de53764e183ab 100644 >--- a/Tools/TestWebKitAPI/Tests/WebCore/CtapPinTest.cpp >+++ b/Tools/TestWebKitAPI/Tests/WebCore/CtapPinTest.cpp >@@ -41,7 +41,7 @@ > #include <WebCore/Pin.h> > #include <WebCore/WebAuthenticationConstants.h> > #include <WebCore/WebAuthenticationUtils.h> >-#include <wtf/text/Base64.h> >+#include <pal/crypto/CryptoDigest.h> > > namespace TestWebKitAPI { > using namespace WebCore; >@@ -98,7 +98,7 @@ TEST(CtapPinTest, TestRetriesResponse) > // Success cases > result = RetriesResponse::parse(convertBytesToVector(TestData::kCtapClientPinRetriesResponse, sizeof(TestData::kCtapClientPinRetriesResponse))); > EXPECT_TRUE(result); >- EXPECT_EQ(result->retries, 8); >+ EXPECT_EQ(result->retries, 8u); > } > > TEST(CtapPinTest, TestKeyAgreementRequest) >@@ -125,6 +125,11 @@ TEST(CtapPinTest, TestKeyAgreementResponse) > result = KeyAgreementResponse::parse(convertBytesToVector(TestData::kCtapClientPinTokenResponse, sizeof(TestData::kCtapClientPinTokenResponse))); // wrong response > EXPECT_FALSE(result); > >+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) || PLATFORM(IOS) >+ result = KeyAgreementResponse::parse(convertBytesToVector(TestData::kCtapClientPinInvalidKeyAgreementResponse, sizeof(TestData::kCtapClientPinInvalidKeyAgreementResponse))); // The point is not on the curve. >+ EXPECT_FALSE(result); >+#endif >+ > // Test COSE > auto coseKey = encodeCOSEPublicKey(Vector<uint8_t>(65)); > coseKey[CBORValue(COSE::kty)] = CBORValue(0); // wrong kty >@@ -176,7 +181,7 @@ TEST(CtapPinTest, TestTokenRequest) > auto token = TokenRequest::tryCreate(pin, downcast<CryptoKeyEC>(*keyPair.publicKey)); > EXPECT_TRUE(token); > auto result = encodeAsCBOR(*token); >- EXPECT_EQ(result.size(), 120u); >+ EXPECT_EQ(result.size(), 103u); > EXPECT_EQ(result[0], static_cast<uint8_t>(CtapRequestCommand::kAuthenticatorClientPin)); > > // Decode the CBOR binary to check if each field is encoded correctly. >@@ -224,12 +229,17 @@ TEST(CtapPinTest, TestTokenRequest) > // Check the encrypted Pin. > auto sharedKeyResult = CryptoAlgorithmECDH::platformDeriveBits(downcast<CryptoKeyEC>(*keyPair.privateKey), *cosePublicKey); > EXPECT_TRUE(sharedKeyResult); >- auto aesKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(*sharedKeyResult), true, CryptoKeyUsageDecrypt); >+ >+ auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); >+ crypto->addBytes(sharedKeyResult->data(), sharedKeyResult->size()); >+ auto sharedKeyHash = crypto->computeHash(); >+ >+ auto aesKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(sharedKeyHash), true, CryptoKeyUsageDecrypt); > EXPECT_TRUE(aesKey); > > const auto& it6 = responseMap.find(CBORValue(static_cast<uint8_t>(RequestKey::kPinHashEnc))); > EXPECT_NE(it6, responseMap.end()); >- auto pinHashResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, *aesKey, it6->second.getByteString()); >+ auto pinHashResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, *aesKey, it6->second.getByteString(), CryptoAlgorithmAES_CBC::Padding::No); > EXPECT_FALSE(pinHashResult.hasException()); > auto pinHash = pinHashResult.releaseReturnValue(); > const uint8_t expectedPinHash[] = { 0x03, 0xac, 0x67, 0x42, 0x16, 0xf3, 0xe1, 0x5c, 0x76, 0x1e, 0xe1, 0xa5, 0xe2, 0x55, 0xf0, 0x67 }; >@@ -240,10 +250,10 @@ TEST(CtapPinTest, TestTokenRequest) > TEST(CtapPinTest, TestTokenResponse) > { > const uint8_t sharedKeyData[] = { >- 0x03, 0xac, 0x67, 0x42, 0x16, 0xf3, 0xe1, 0x5c, >- 0x76, 0x1e, 0xe1, 0xa5, 0xe2, 0x55, 0xf0, 0x67, >- 0x95, 0x36, 0x23, 0xc8, 0xb3, 0x88, 0xb4, 0x45, >- 0x9e, 0x13, 0xf9, 0x78, 0xd7, 0xc8, 0x46, 0xf4, }; >+ 0x29, 0x9E, 0x65, 0xB8, 0xE7, 0x71, 0xB8, 0x1D, >+ 0xB1, 0xC4, 0x8D, 0xBE, 0xCE, 0x50, 0x2A, 0x84, >+ 0x05, 0x44, 0x7F, 0x46, 0x2D, 0xE6, 0x81, 0xFA, >+ 0xEF, 0x0A, 0x6C, 0x67, 0xA7, 0x2B, 0xB5, 0x0F, }; > auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, convertBytesToVector(sharedKeyData, sizeof(sharedKeyData)), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt); > ASSERT_TRUE(sharedKey); > >@@ -274,10 +284,10 @@ TEST(CtapPinTest, TestPinAuth) > { > // 1. Generate the token. > const uint8_t sharedKeyData[] = { >- 0x03, 0xac, 0x67, 0x42, 0x16, 0xf3, 0xe1, 0x5c, >- 0x76, 0x1e, 0xe1, 0xa5, 0xe2, 0x55, 0xf0, 0x67, >- 0x95, 0x36, 0x23, 0xc8, 0xb3, 0x88, 0xb4, 0x45, >- 0x9e, 0x13, 0xf9, 0x78, 0xd7, 0xc8, 0x46, 0xf4, }; >+ 0x29, 0x9E, 0x65, 0xB8, 0xE7, 0x71, 0xB8, 0x1D, >+ 0xB1, 0xC4, 0x8D, 0xBE, 0xCE, 0x50, 0x2A, 0x84, >+ 0x05, 0x44, 0x7F, 0x46, 0x2D, 0xE6, 0x81, 0xFA, >+ 0xEF, 0x0A, 0x6C, 0x67, 0xA7, 0x2B, 0xB5, 0x0F, }; > auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, convertBytesToVector(sharedKeyData, sizeof(sharedKeyData)), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt); > ASSERT_TRUE(sharedKey); > auto result = TokenResponse::parse(*sharedKey, convertBytesToVector(TestData::kCtapClientPinTokenResponse, sizeof(TestData::kCtapClientPinTokenResponse))); >@@ -285,7 +295,7 @@ TEST(CtapPinTest, TestPinAuth) > > // 2. Generate the pinAuth. > auto pinAuth = result->pinAuth(convertBytesToVector(sharedKeyData, sizeof(sharedKeyData))); // sharedKeyData pretends to be clientDataHash >- const uint8_t expectedPinAuth[] = { 0xb3, 0xc2, 0x65, 0x1c, 0xfd, 0xc8, 0x42, 0xb4, 0x60, 0x16, 0xed, 0x20, 0x64, 0x53, 0xaf, 0x84 }; >+ const uint8_t expectedPinAuth[] = { 0x0b, 0xec, 0x9d, 0xba, 0x69, 0xb0, 0x0f, 0x45, 0x0b, 0xec, 0x66, 0xb4, 0x75, 0x7f, 0x93, 0x85 }; > EXPECT_EQ(pinAuth.size(), 16u); > EXPECT_EQ(memcmp(pinAuth.data(), expectedPinAuth, pinAuth.size()), 0); > } >diff --git a/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h b/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h >index 3c2302b0a88b7219d9ec6adcd13ad7d7b7fedc61..f258165b731b99ed795e0461e8a56bbd5e5e9d25 100644 >--- a/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h >+++ b/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h >@@ -612,15 +612,15 @@ constexpr uint8_t kCtapMakeCredentialRequestWithPin[] = { > 0x62, 0x75, 0x76, > // True(21) > 0xf5, >- // key(8) - pinProtocol >+ // key(8) - pinAuth > 0x08, >- // value - 1 >- 0x01, >- // key(9) - pinAuth >- 0x09, > // bytes(16) > 0x50, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, >- 0x0b, 0x0c, 0x0d, 0x0e, 0x0f >+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, >+ // key(9) - pinProtocol >+ 0x09, >+ // value - 1 >+ 0x01, > }; > > constexpr uint8_t kTestComplexCtapGetAssertionRequest[] = { >@@ -745,15 +745,15 @@ constexpr uint8_t kTestComplexCtapGetAssertionRequestWithPin[] = { > 0x62, 0x75, 0x76, > // value - True(21) > 0xf5, >- // key(8) - pinProtocol >- 0x08, >- // value - 1 >- 0x01, >- // key(9) - pinAuth >- 0x09, >+ // key(6) - pinAuth >+ 0x06, > // bytes(16) > 0x50, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, >- 0x0b, 0x0c, 0x0d, 0x0e, 0x0f >+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, >+ // key(7) - pinProtocol >+ 0x07, >+ // value - 1 >+ 0x01, > }; > > // CTAP responses -------------------------------------------------------------- >@@ -1103,12 +1103,11 @@ constexpr uint8_t kCtapClientPinTokenResponse[] = { > 0xa1, > // key(2) - pinToken > 0x02, >- // bytes(32) >- 0x58, 0x20, >+ // bytes(16) >+ 0x50, > // encrypted token >- 0x48, 0xb9, 0x5d, 0x3d, 0x9e, 0xee, 0xe5, 0x00, 0xab, 0x51, 0x13, 0x2b, >- 0x35, 0x77, 0x66, 0x5c, 0x41, 0x7a, 0x56, 0x3e, 0xb3, 0xe2, 0x3c, 0xb7, >- 0x6a, 0x37, 0xb3, 0xde, 0x57, 0x2b, 0xca, 0xaa, >+ 0x13, 0xA4, 0xEE, 0xB7, 0x0E, 0xC9, 0x1A, 0xEA, 0x00, 0x1E, 0x93, 0x16, >+ 0xF6, 0x1E, 0x41, 0xF7, > }; > > constexpr uint8_t kCtapClientPinKeyAgreementResponse[] = { >@@ -1144,6 +1143,39 @@ constexpr uint8_t kCtapClientPinKeyAgreementResponse[] = { > 0x70, 0x45, 0xF4, 0x61, 0x2F, 0xB2, 0x0C, 0x91, > }; > >+constexpr uint8_t kCtapClientPinInvalidKeyAgreementResponse[] = { >+ // Success >+ 0x00, >+ // map(1) >+ 0xA1, >+ // key(1) - keyAgreement >+ 0x01, >+ // Map(5) >+ 0xA5, >+ // kty: EC key type >+ 0x01, 0x02, >+ // alg: ECDH256 signature algorithm >+ 0x03, 0x38, 0x18, >+ // crv: P-256 curve >+ 0x20, 0x01, >+ // x-coordinate >+ 0x21, >+ // Bytes(32) >+ 0x58, 0x20, >+ // Byte array content >+ 0xE8, 0x76, 0x25, 0x89, 0x6E, 0xE4, 0xE4, 0x66, 0xC0, 0x32, 0x76, 0x6E, >+ 0x80, 0x87, 0x96, 0x2F, 0x36, 0xDF, 0x9D, 0xFF, 0x8B, 0x56, 0x7F, 0x37, >+ 0x63, 0x01, 0x5B, 0x19, 0x90, 0xA6, 0x0E, 0x14, >+ // y-coordinate >+ 0x22, >+ // Bytes(32) >+ 0x58, 0x20, >+ // Byte array content >+ 0x27, 0xDE, 0x61, 0x2D, 0x66, 0x41, 0x8B, 0xDA, 0x19, 0x50, 0x58, 0x1E, >+ 0xBC, 0x5C, 0x8C, 0x1D, 0xAD, 0x71, 0x0C, 0xB1, 0x4C, 0x22, 0xF8, 0xC9, >+ 0x70, 0x45, 0xF4, 0x61, 0x2F, 0xB2, 0x0C, 0x91, >+}; >+ > constexpr uint8_t kCtapClientPinRetriesResponse[] = { > // Success > 0x00, >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm >index 66f74d382dc4d0dcbec5a6fa406d4c4479ef9c8c..bfc9cc3303ff1486e9f359ff6d3ee171e5199e2b 100644 >--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm >@@ -45,6 +45,7 @@ static bool webAuthenticationPanelSucceded = false; > static bool webAuthenticationPanelUpdateMultipleNFCTagsPresent = false; > static bool webAuthenticationPanelUpdateNoCredentialsFound = false; > static bool webAuthenticationPanelCancelImmediately = false; >+static String webAuthenticationPanelPin; > > @interface TestWebAuthenticationPanelDelegate : NSObject <_WKWebAuthenticationPanelDelegate> > @end >@@ -83,6 +84,13 @@ - (void)panel:(_WKWebAuthenticationPanel *)panel dismissWebAuthenticationPanelWi > } > } > >+- (void)panel:(_WKWebAuthenticationPanel *)panel requestPINWithRemainingRetries:(NSUInteger)retries completionHandler:(void (^)(NSString *))completionHandler >+{ >+ ASSERT_NE(panel, nil); >+ EXPECT_EQ(retries, 8ul); >+ completionHandler(webAuthenticationPanelPin); >+} >+ > @end > > @interface TestWebAuthenticationPanelFakeDelegate : NSObject <_WKWebAuthenticationPanelDelegate> >@@ -740,6 +748,149 @@ TEST(WebAuthenticationPanel, PanelHidCtapNoCredentialsFoundCancelNoCrash) > Util::run(&webAuthenticationPanelUpdateNoCredentialsFound); > } > >+TEST(WebAuthenticationPanel, PinGetRetriesError) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-retries-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Unknown internal error. Error code: 2"]; >+} >+ >+TEST(WebAuthenticationPanel, PinGetKeyAgreementError) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-key-agreement-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Unknown internal error. Error code: 2"]; >+} >+ >+TEST(WebAuthenticationPanel, PinRequestPinErrorNoDelegate) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Pin is not valid: "]; >+} >+ >+TEST(WebAuthenticationPanel, PinRequestPinErrorNullDelegate) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); >+ [delegate setIsNull:true]; >+ [webView setUIDelegate:delegate.get()]; >+ >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Pin is not valid: "]; >+} >+ >+TEST(WebAuthenticationPanel, PinRequestPinError) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); >+ [webView setUIDelegate:delegate.get()]; >+ >+ webAuthenticationPanelPin = "123"; >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Pin is not valid: 123"]; >+} >+ >+TEST(WebAuthenticationPanel, PinGetPinTokenError) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); >+ [webView setUIDelegate:delegate.get()]; >+ >+ webAuthenticationPanelPin = "1234"; >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Unknown internal error. Error code: 2"]; >+} >+ >+TEST(WebAuthenticationPanel, MakeCredentialPin) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); >+ [webView setUIDelegate:delegate.get()]; >+ >+ webAuthenticationPanelPin = "1234"; >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Succeeded!"]; >+} >+ >+TEST(WebAuthenticationPanel, GetAssertionPin) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); >+ [webView setUIDelegate:delegate.get()]; >+ >+ webAuthenticationPanelPin = "1234"; >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Succeeded!"]; >+} >+ >+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED < 101500) >+TEST(WebAuthenticationPanel, PinInvalidKeyAgreementError) >+{ >+ reset(); >+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-invalid-key-agreement" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; >+ >+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; >+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); >+ auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); >+ [webView setUIDelegate:delegate.get()]; >+ >+ webAuthenticationPanelPin = "1234"; >+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; >+ [webView waitForMessage:@"Cannot create a TokenRequest."]; >+} >+#endif >+ > } // namespace TestWebKitAPI > > #endif // ENABLE(WEB_AUTHN) >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-pin.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-pin.html >new file mode 100644 >index 0000000000000000000000000000000000000000..e31eb3bfe1e2cbcb5214a36ed684b05249682b14 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-pin.html >@@ -0,0 +1,32 @@ >+<input type="text" id="input"> >+<script> >+ const testCtapPinAuthInvalidErrorBase64 = "Mw=="; >+ const testPinGetRetriesResponseBase64 = "AKEDCA=="; >+ const testPinGetKeyAgreementResponseBase64 = "AKEBpQECAzgYIAEhWCDodiWJbuTkbcAydm6Ah5YvNt+d/otWfzdjAVsZkKYOFCJYICfeYS1mQYvaGVBYHrxcjB2tcQyxTCL4yXBF9GEvsgyR"; >+ const testPinGetPinTokenResponseBase64 = "AKECUBOk7rcOyRrqAB6TFvYeQfc="; >+ const testAssertionMessageBase64 = >+ "AKMBomJpZFhAKAitzuj+Tslzelf3/vZwIGtDQNgoKeFd5oEieYzhyzA65saf0tK2" + >+ "w/mooa7tQtGgDdwZIjOhjcuZ0pQ1ajoE4GR0eXBlanB1YmxpYy1rZXkCWCVGzH+5" + >+ "Z51VstuQkuHI2eXh0Ct1gPC0gSx3CWLh5I9a2AEAAABQA1hHMEUCIQCSFTuuBWgB" + >+ "4/F0VB7DlUVM09IHPmxe1MzHUwRoCRZbCAIgGKov6xoAx2MEf6/6qNs8OutzhP2C" + >+ "QoJ1L7Fe64G9uBc="; >+ if (window.internals) { >+ internals.setMockWebAuthenticationConfiguration({ hid: { supportClientPin: true, payloadBase64: [testCtapPinAuthInvalidErrorBase64, testPinGetRetriesResponseBase64, testPinGetKeyAgreementResponseBase64, testPinGetPinTokenResponseBase64, testAssertionMessageBase64] } }); >+ internals.withUserGesture(() => { input.focus(); }); >+ } >+ >+ const options = { >+ publicKey: { >+ challenge: new Uint8Array(16), >+ timeout: 100 >+ } >+ }; >+ >+ navigator.credentials.get(options).then(credential => { >+ // console.log("Succeeded!"); >+ window.webkit.messageHandlers.testHandler.postMessage("Succeeded!"); >+ }, error => { >+ // console.log(error.message); >+ window.webkit.messageHandlers.testHandler.postMessage(error.message); >+ }); >+</script> >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-key-agreement-error.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-key-agreement-error.html >new file mode 100644 >index 0000000000000000000000000000000000000000..83aca98794b8ae94aae10f7afaf726aeac92d9c1 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-key-agreement-error.html >@@ -0,0 +1,33 @@ >+<input type="text" id="input"> >+<script> >+ const testCtapPinInvalidErrorBase64 = "MQ=="; >+ const testPinGetRetriesResponseBase64 = "AKEDCA=="; >+ const testCtapInvalidParameterErrorBase64 = "Ag=="; >+ if (window.internals) { >+ internals.setMockWebAuthenticationConfiguration({ hid: { supportClientPin: true, payloadBase64: [testCtapPinInvalidErrorBase64, testPinGetRetriesResponseBase64, testCtapInvalidParameterErrorBase64] } }); >+ internals.withUserGesture(() => { input.focus(); }); >+ } >+ >+ const options = { >+ publicKey: { >+ rp: { >+ name: "localhost", >+ }, >+ user: { >+ name: "John Appleseed", >+ id: new Uint8Array(16), >+ displayName: "Appleseed", >+ }, >+ challenge: new Uint8Array(16), >+ pubKeyCredParams: [{ type: "public-key", alg: -7 }] >+ } >+ }; >+ >+ navigator.credentials.create(options).then(credential => { >+ // console.log("Succeeded!"); >+ window.webkit.messageHandlers.testHandler.postMessage("Succeeded!"); >+ }, error => { >+ // console.log(error.message); >+ window.webkit.messageHandlers.testHandler.postMessage(error.message); >+ }); >+</script> >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-pin-token-error.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-pin-token-error.html >new file mode 100644 >index 0000000000000000000000000000000000000000..49915b3f8ffdeba289962376b643cf996fa0a8fb >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-pin-token-error.html >@@ -0,0 +1,34 @@ >+<input type="text" id="input"> >+<script> >+ const testCtapPinInvalidErrorBase64 = "MQ=="; >+ const testPinGetRetriesResponseBase64 = "AKEDCA=="; >+ const testPinGetKeyAgreementResponseBase64 = "AKEBpQECAzgYIAEhWCDodiWJbuTkbcAydm6Ah5YvNt+d/otWfzdjAVsZkKYOFCJYICfeYS1mQYvaGVBYHrxcjB2tcQyxTCL4yXBF9GEvsgyR"; >+ const testCtapInvalidParameterErrorBase64 = "Ag=="; >+ if (window.internals) { >+ internals.setMockWebAuthenticationConfiguration({ hid: { supportClientPin: true, payloadBase64: [testCtapPinInvalidErrorBase64, testPinGetRetriesResponseBase64, testPinGetKeyAgreementResponseBase64, testCtapInvalidParameterErrorBase64] } }); >+ internals.withUserGesture(() => { input.focus(); }); >+ } >+ >+ const options = { >+ publicKey: { >+ rp: { >+ name: "localhost", >+ }, >+ user: { >+ name: "John Appleseed", >+ id: new Uint8Array(16), >+ displayName: "Appleseed", >+ }, >+ challenge: new Uint8Array(16), >+ pubKeyCredParams: [{ type: "public-key", alg: -7 }] >+ } >+ }; >+ >+ navigator.credentials.create(options).then(credential => { >+ // console.log("Succeeded!"); >+ window.webkit.messageHandlers.testHandler.postMessage("Succeeded!"); >+ }, error => { >+ // console.log(error.message); >+ window.webkit.messageHandlers.testHandler.postMessage(error.message); >+ }); >+</script> >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-retries-error.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-retries-error.html >new file mode 100644 >index 0000000000000000000000000000000000000000..cbd1157c41cf8c3d37d9e832470335b36e71b01e >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-retries-error.html >@@ -0,0 +1,32 @@ >+<input type="text" id="input"> >+<script> >+ const testCtapPinInvalidErrorBase64 = "MQ=="; >+ const testCtapInvalidParameterErrorBase64 = "Ag=="; >+ if (window.internals) { >+ internals.setMockWebAuthenticationConfiguration({ hid: { supportClientPin: true, payloadBase64: [testCtapPinInvalidErrorBase64, testCtapInvalidParameterErrorBase64] } }); >+ internals.withUserGesture(() => { input.focus(); }); >+ } >+ >+ const options = { >+ publicKey: { >+ rp: { >+ name: "localhost", >+ }, >+ user: { >+ name: "John Appleseed", >+ id: new Uint8Array(16), >+ displayName: "Appleseed", >+ }, >+ challenge: new Uint8Array(16), >+ pubKeyCredParams: [{ type: "public-key", alg: -7 }] >+ } >+ }; >+ >+ navigator.credentials.create(options).then(credential => { >+ // console.log("Succeeded!"); >+ window.webkit.messageHandlers.testHandler.postMessage("Succeeded!"); >+ }, error => { >+ // console.log(error.message); >+ window.webkit.messageHandlers.testHandler.postMessage(error.message); >+ }); >+</script> >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-invalid-key-agreeement.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-invalid-key-agreeement.html >new file mode 100644 >index 0000000000000000000000000000000000000000..168518ff0c78ae8badab5149085782eacb92b535 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-invalid-key-agreeement.html >@@ -0,0 +1,33 @@ >+<input type="text" id="input"> >+<script> >+ const testCtapPinInvalidErrorBase64 = "MQ=="; >+ const testPinGetRetriesResponseBase64 = "AKEDCA=="; >+ const testPinInvalidGetKeyAgreementResponseBase64 = "AKEBpQECAzgYIAEhWCDodiWJbuTkZsAydm6Ah5YvNt+d/4tWfzdjAVsZkKYOFCJYICfeYS1mQYvaGVBYHrxcjB2tcQyxTCL4yXBF9GEvsgyR"; >+ if (window.internals) { >+ internals.setMockWebAuthenticationConfiguration({ hid: { supportClientPin: true, payloadBase64: [testCtapPinInvalidErrorBase64, testPinGetRetriesResponseBase64, testPinInvalidGetKeyAgreementResponseBase64] } }); >+ internals.withUserGesture(() => { input.focus(); }); >+ } >+ >+ const options = { >+ publicKey: { >+ rp: { >+ name: "localhost", >+ }, >+ user: { >+ name: "John Appleseed", >+ id: new Uint8Array(16), >+ displayName: "Appleseed", >+ }, >+ challenge: new Uint8Array(16), >+ pubKeyCredParams: [{ type: "public-key", alg: -7 }] >+ } >+ }; >+ >+ navigator.credentials.create(options).then(credential => { >+ // console.log("Succeeded!"); >+ window.webkit.messageHandlers.testHandler.postMessage("Succeeded!"); >+ }, error => { >+ // console.log(error.message); >+ window.webkit.messageHandlers.testHandler.postMessage(error.message); >+ }); >+</script> >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin.html >new file mode 100644 >index 0000000000000000000000000000000000000000..715a0ff516e9b626801a48f675bd06916f8dab40 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin.html >@@ -0,0 +1,56 @@ >+<input type="text" id="input"> >+<script> >+ const testCtapPinAuthInvalidErrorBase64 = "Mw=="; >+ const testPinGetRetriesResponseBase64 = "AKEDCA=="; >+ const testPinGetKeyAgreementResponseBase64 = "AKEBpQECAzgYIAEhWCDodiWJbuTkbcAydm6Ah5YvNt+d/otWfzdjAVsZkKYOFCJYICfeYS1mQYvaGVBYHrxcjB2tcQyxTCL4yXBF9GEvsgyR"; >+ const testPinGetPinTokenResponseBase64 = "AKECUBOk7rcOyRrqAB6TFvYeQfc="; >+ const testCreationMessageBase64 = >+ "AKMBZnBhY2tlZAJYxEbMf7lnnVWy25CS4cjZ5eHQK3WA8LSBLHcJYuHkj1rYQQAA" + >+ "AE74oBHzjApNFYAGFxEfntx9AEAoCK3O6P5OyXN6V/f+9nAga0NA2Cgp4V3mgSJ5" + >+ "jOHLMDrmxp/S0rbD+aihru1C0aAN3BkiM6GNy5nSlDVqOgTgpQECAyYgASFYIEFb" + >+ "he3RkNud6sgyraBGjlh1pzTlCZehQlL/b18HZ6WGIlggJgfUd/en9p5AIqMQbUni" + >+ "nEeXdFLkvW0/zV5BpEjjNxADo2NhbGcmY3NpZ1hHMEUCIQDKg+ZBmEBtf0lWq4Re" + >+ "dH4/i/LOYqOR4uR2NAj2zQmw9QIgbTXb4hvFbj4T27bv/rGrc+y+0puoYOBkBk9P" + >+ "mCewWlNjeDVjgVkCwjCCAr4wggGmoAMCAQICBHSG/cIwDQYJKoZIhvcNAQELBQAw" + >+ "LjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290IENBIFNlcmlhbCA0NTcyMDA2MzEw" + >+ "IBcNMTQwODAxMDAwMDAwWhgPMjA1MDA5MDQwMDAwMDBaMG8xCzAJBgNVBAYTAlNF" + >+ "MRIwEAYDVQQKDAlZdWJpY28gQUIxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0" + >+ "ZXN0YXRpb24xKDAmBgNVBAMMH1l1YmljbyBVMkYgRUUgU2VyaWFsIDE5NTUwMDM4" + >+ "NDIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASVXfOt9yR9MXXv/ZzE8xpOh466" + >+ "4YEJVmFQ+ziLLl9lJ79XQJqlgaUNCsUvGERcChNUihNTyKTlmnBOUjvATevto2ww" + >+ "ajAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4xLjQxNDgyLjEuMTATBgsrBgEEAYLl" + >+ "HAIBAQQEAwIFIDAhBgsrBgEEAYLlHAEBBAQSBBD4oBHzjApNFYAGFxEfntx9MAwG" + >+ "A1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBADFcSIDmmlJ+OGaJvWn9Cqhv" + >+ "SeueToVFQVVvqtALOgCKHdwB+Wx29mg2GpHiMsgQp5xjB0ybbnpG6x212FxESJ+G" + >+ "inZD0ipchi7APwPlhIvjgH16zVX44a4e4hOsc6tLIOP71SaMsHuHgCcdH0vg5d2s" + >+ "c006WJe9TXO6fzV+ogjJnYpNKQLmCXoAXE3JBNwKGBIOCvfQDPyWmiiG5bGxYfPt" + >+ "y8Z3pnjX+1MDnM2hhr40ulMxlSNDnX/ZSnDyMGIbk8TOQmjTF02UO8auP8k3wt5D" + >+ "1rROIRU9+FCSX5WQYi68RuDrGMZB8P5+byoJqbKQdxn2LmE1oZAyohPAmLcoPO4="; >+ if (window.internals) { >+ internals.setMockWebAuthenticationConfiguration({ hid: { supportClientPin: true, payloadBase64: [testCtapPinAuthInvalidErrorBase64, testPinGetRetriesResponseBase64, testPinGetKeyAgreementResponseBase64, testPinGetPinTokenResponseBase64, testCreationMessageBase64] } }); >+ internals.withUserGesture(() => { input.focus(); }); >+ } >+ >+ const options = { >+ publicKey: { >+ rp: { >+ name: "localhost", >+ }, >+ user: { >+ name: "John Appleseed", >+ id: new Uint8Array(16), >+ displayName: "Appleseed", >+ }, >+ challenge: new Uint8Array(16), >+ pubKeyCredParams: [{ type: "public-key", alg: -7 }] >+ } >+ }; >+ >+ navigator.credentials.create(options).then(credential => { >+ // console.log("Succeeded!"); >+ window.webkit.messageHandlers.testHandler.postMessage("Succeeded!"); >+ }, error => { >+ // console.log(error.message); >+ window.webkit.messageHandlers.testHandler.postMessage(error.message); >+ }); >+</script>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 191516
:
386914
|
386984
|
387005
|
387028
|
387399
|
387598