Changeset 254439 in webkit


Ignore:
Timestamp:
Jan 13, 2020 10:53:59 AM (4 years ago)
Author:
jiewen_tan@apple.com
Message:

[WebAuthn] Support CTAP Client Pin
https://bugs.webkit.org/show_bug.cgi?id=191516
<rdar://problem/56558558>

Reviewed by Brent Fulgham.

Source/WebCore:

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:

Source/WebKit:

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;

  1. 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;

  1. Get retries from the authenticator;
  2. Get key agreement from the authenticator;
  3. Ask the UI client for the PIN and at the meantime inform it the retries;
  4. Get pin token from the authenticator;
  5. 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:

Tools:

  • 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.html: Added.
Location:
trunk
Files:
5 added
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r254438 r254439  
     12020-01-06  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthn] Support CTAP Client Pin
     4        https://bugs.webkit.org/show_bug.cgi?id=191516
     5        <rdar://problem/56558558>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Covered by API tests.
     10
     11        * Modules/webauthn/fido/DeviceRequestConverter.cpp:
     12        (fido::encodeMakeCredenitalRequestAsCBOR):
     13        (fido::encodeGetAssertionRequestAsCBOR):
     14        * Modules/webauthn/fido/Pin.cpp:
     15        (fido::pin::RetriesResponse::parse):
     16        (fido::pin::TokenResponse::parse):
     17        (fido::pin::TokenRequest::tryCreate):
     18        (fido::pin::encodeAsCBOR):
     19        * Modules/webauthn/fido/Pin.h:
     20        * crypto/algorithms/CryptoAlgorithmAES_CBC.h:
     21        * crypto/gcrypt/CryptoAlgorithmAES_CBCGCrypt.cpp:
     22        (WebCore::CryptoAlgorithmAES_CBC::platformEncrypt):
     23        (WebCore::CryptoAlgorithmAES_CBC::platformDecrypt):
     24        * crypto/mac/CryptoAlgorithmAES_CBCMac.cpp:
     25        (WebCore::transformAES_CBC):
     26        (WebCore::CryptoAlgorithmAES_CBC::platformEncrypt):
     27        (WebCore::CryptoAlgorithmAES_CBC::platformDecrypt):
     28        * testing/MockWebAuthenticationConfiguration.h:
     29        (WebCore::MockWebAuthenticationConfiguration::HidConfiguration::encode const):
     30        (WebCore::MockWebAuthenticationConfiguration::HidConfiguration::decode):
     31        * testing/MockWebAuthenticationConfiguration.idl:
     32
    1332020-01-13  Zalan Bujtas  <zalan@apple.com>
    234
  • trunk/Source/WebCore/Modules/webauthn/fido/DeviceRequestConverter.cpp

    r253811 r254439  
    127127    if (pin) {
    128128        ASSERT(pin->protocol >= 0);
    129         cborMap[CBORValue(8)] = CBORValue(pin->protocol);
    130         cborMap[CBORValue(9)] = CBORValue(WTFMove(pin->auth));
     129        cborMap[CBORValue(8)] = CBORValue(WTFMove(pin->auth));
     130        cborMap[CBORValue(9)] = CBORValue(pin->protocol);
    131131    }
    132132
     
    173173    if (pin) {
    174174        ASSERT(pin->protocol >= 0);
    175         cborMap[CBORValue(8)] = CBORValue(pin->protocol);
    176         cborMap[CBORValue(9)] = CBORValue(WTFMove(pin->auth));
     175        cborMap[CBORValue(6)] = CBORValue(WTFMove(pin->auth));
     176        cborMap[CBORValue(7)] = CBORValue(pin->protocol);
    177177    }
    178178
  • trunk/Source/WebCore/Modules/webauthn/fido/Pin.cpp

    r254079 r254439  
    132132
    133133    RetriesResponse ret;
    134     ret.retries = static_cast<int64_t>(it->second.getUnsigned());
     134    ret.retries = static_cast<uint64_t>(it->second.getUnsigned());
    135135    return ret;
    136136}
     
    233233    const auto& encryptedToken = it->second.getByteString();
    234234
    235     auto tokenResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, sharedKey, encryptedToken);
     235    auto tokenResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, sharedKey, encryptedToken, CryptoAlgorithmAES_CBC::Padding::No);
    236236    if (tokenResult.hasException())
    237237        return WTF::nullopt;
     
    273273    auto keyPair = keyPairResult.releaseReturnValue();
    274274
    275     // 2. Use ECDH to compute the shared AES-CBC key.
     275    // 2. Use ECDH and SHA-256 to compute the shared AES-CBC key.
    276276    auto sharedKeyResult = CryptoAlgorithmECDH::platformDeriveBits(downcast<CryptoKeyEC>(*keyPair.privateKey), peerKey);
    277277    if (!sharedKeyResult)
    278278        return WTF::nullopt;
    279     auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(*sharedKeyResult), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt);
     279
     280    auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
     281    crypto->addBytes(sharedKeyResult->data(), sharedKeyResult->size());
     282    auto sharedKeyHash = crypto->computeHash();
     283
     284    auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(sharedKeyHash), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt);
    280285    ASSERT(sharedKey);
    281286
     
    286291
    287292    // The following calculates a SHA-256 digest of the PIN, and shrink to the left 16 bytes.
    288     auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
     293    crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
    289294    crypto->addBytes(pin.data(), pin.length());
    290295    auto pinHash = crypto->computeHash();
     
    308313Vector<uint8_t> encodeAsCBOR(const TokenRequest& request)
    309314{
    310     auto result = CryptoAlgorithmAES_CBC::platformEncrypt({ }, request.sharedKey(), request.m_pinHash);
     315    auto result = CryptoAlgorithmAES_CBC::platformEncrypt({ }, request.sharedKey(), request.m_pinHash, CryptoAlgorithmAES_CBC::Padding::No);
    311316    ASSERT(!result.hasException());
    312317
  • trunk/Source/WebCore/Modules/webauthn/fido/Pin.h

    r253811 r254439  
    8080// kProtocolVersion is the version of the PIN protocol that this code
    8181// implements.
    82 constexpr int kProtocolVersion = 1;
     82constexpr int64_t kProtocolVersion = 1;
    8383
    8484// encodeCOSEPublicKey takes a raw ECDH256 public key and returns it as a COSE structure.
     
    111111    // retries is the number of PIN attempts remaining before the authenticator
    112112    // locks.
    113     int retries;
     113    uint64_t retries;
    114114
    115115private:
     
    146146    // sharedKey returns the shared ECDH key that was used to encrypt the PIN.
    147147    // This is needed to decrypt the response.
    148     const WebCore::CryptoKeyAES& sharedKey() const;
     148    WEBCORE_EXPORT const WebCore::CryptoKeyAES& sharedKey() const;
    149149
    150150    friend Vector<uint8_t> encodeAsCBOR(const TokenRequest&);
  • trunk/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h

    r253811 r254439  
    3737class CryptoAlgorithmAES_CBC final : public CryptoAlgorithm {
    3838public:
     39    enum class Padding : uint8_t {
     40        Yes,
     41        No
     42    };
     43
    3944    static constexpr const char* s_name = "AES-CBC";
    4045    static constexpr CryptoAlgorithmIdentifier s_identifier = CryptoAlgorithmIdentifier::AES_CBC;
     
    4247
    4348    // Operations can be performed directly.
    44     WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformEncrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&);
    45     WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformDecrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&);
     49    WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformEncrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&, Padding padding = Padding::Yes);
     50    WEBCORE_EXPORT static ExceptionOr<Vector<uint8_t>> platformDecrypt(const CryptoAlgorithmAesCbcCfbParams&, const CryptoKeyAES&, const Vector<uint8_t>&, Padding padding = Padding::Yes);
    4651
    4752private:
  • trunk/Source/WebCore/crypto/gcrypt/CryptoAlgorithmAES_CBCGCrypt.cpp

    r239427 r254439  
    167167}
    168168
    169 ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText)
     169ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText, Padding)
    170170{
    171171    auto output = gcryptEncrypt(key.key(), parameters.ivVector(), Vector<uint8_t>(plainText));
     
    175175}
    176176
    177 ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText)
     177ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText, Padding)
    178178{
    179179    auto output = gcryptDecrypt(key.key(), parameters.ivVector(), cipherText);
  • trunk/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp

    r253811 r254439  
    3535namespace WebCore {
    3636
    37 static ExceptionOr<Vector<uint8_t>> transformAES_CBC(CCOperation operation, const Vector<uint8_t>& iv, const Vector<uint8_t>& key, const Vector<uint8_t>& data)
     37static 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)
    3838{
     39    CCOptions options = padding == CryptoAlgorithmAES_CBC::Padding::Yes ? kCCOptionPKCS7Padding : 0;
    3940    CCCryptorRef cryptor;
    40     CCCryptorStatus status = CCCryptorCreate(operation, kCCAlgorithmAES, kCCOptionPKCS7Padding, key.data(), key.size(), iv.data(), &cryptor);
     41    CCCryptorStatus status = CCCryptorCreate(operation, kCCAlgorithmAES, options, key.data(), key.size(), iv.data(), &cryptor);
    4142    if (status)
    4243        return Exception { OperationError };
     
    5051
    5152    uint8_t* p = result.data() + bytesWritten;
    52     status = CCCryptorFinal(cryptor, p, result.end() - p, &bytesWritten);
    53     p += bytesWritten;
    54     if (status)
    55         return Exception { OperationError };
     53    if (padding == CryptoAlgorithmAES_CBC::Padding::Yes) {
     54        status = CCCryptorFinal(cryptor, p, result.end() - p, &bytesWritten);
     55        p += bytesWritten;
     56        if (status)
     57            return Exception { OperationError };
     58    }
    5659
    5760    ASSERT(p <= result.end());
     
    6366}
    6467
    65 ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText)
     68ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText, Padding padding)
    6669{
    6770    ASSERT(parameters.ivVector().size() == kCCBlockSizeAES128 || parameters.ivVector().isEmpty());
    68     return transformAES_CBC(kCCEncrypt, parameters.ivVector(), key.key(), plainText);
     71    ASSERT(padding == Padding::Yes || !(plainText.size() % kCCBlockSizeAES128));
     72    return transformAES_CBC(kCCEncrypt, parameters.ivVector(), key.key(), plainText, padding);
    6973}
    7074
    71 ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText)
     75ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcCfbParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText, Padding padding)
    7276{
    7377    ASSERT(parameters.ivVector().size() == kCCBlockSizeAES128 || parameters.ivVector().isEmpty());
    74     return transformAES_CBC(kCCDecrypt, parameters.ivVector(), key.key(), cipherText);
     78    ASSERT(padding == Padding::Yes || !(cipherText.size() % kCCBlockSizeAES128));
     79    return transformAES_CBC(kCCDecrypt, parameters.ivVector(), key.key(), cipherText, padding);
    7580}
    7681
  • trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.h

    r251645 r254439  
    8585        bool canDowngrade { false };
    8686        bool expectCancel { false };
     87        bool supportClientPin { false };
    8788
    8889        template<class Encoder> void encode(Encoder&) const;
     
    162163void MockWebAuthenticationConfiguration::HidConfiguration::encode(Encoder& encoder) const
    163164{
    164     encoder << payloadBase64 << stage << subStage << error << isU2f << keepAlive << fastDataArrival << continueAfterErrorData << canDowngrade << expectCancel;
     165    encoder << payloadBase64 << stage << subStage << error << isU2f << keepAlive << fastDataArrival << continueAfterErrorData << canDowngrade << expectCancel << supportClientPin;
    165166}
    166167
     
    188189        return WTF::nullopt;
    189190    if (!decoder.decode(result.expectCancel))
     191        return WTF::nullopt;
     192    if (!decoder.decode(result.supportClientPin))
    190193        return WTF::nullopt;
    191194    return result;
  • trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl

    r251645 r254439  
    9393    boolean canDowngrade = false;
    9494    boolean expectCancel = false;
     95    boolean supportClientPin = false;
    9596};
    9697
  • trunk/Source/WebKit/ChangeLog

    r254436 r254439  
     12020-01-06  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthn] Support CTAP Client Pin
     4        https://bugs.webkit.org/show_bug.cgi?id=191516
     5        <rdar://problem/56558558>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        This patch implements authenticatorClientPIN from the spec:
     10        https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorClientPIN
     11        Specifically, it implements section 5.5.1, 5.5.3, 5.5.4, 5.5.7, and 5.5.8.
     12
     13        Here is the flow how makeCredential/getAssertion works with a PIN in our implementation:
     14        1. Determine if the connected authenticator has a PIN;
     15        2. If yes, send the makeCredential/getAssertion request to the authenticator with an empty pinAuth
     16        such that the authenticator will wink for user gestures. This step intends to confirm the authenticator
     17        is the one the user wants to use. Otherwise, we don't know which authenticator to send the PIN
     18        if multiple are connected;
     19        3. Once the user confirms the authetnicator, it will return either CTAP2_ERR_PIN_INVALID or
     20        CTAP2_ERR_PIN_AUTH_INVALID. Some authenticators return CTAP2_ERR_PIN_AUTH_INVALID even though
     21        it is not suggested by the spec;
     22        4. Get retries from the authenticator;
     23        5. Get key agreement from the authenticator;
     24        6. Ask the UI client for the PIN and at the meantime inform it the retries;
     25        7. Get pin token from the authenticator;
     26        8. Resend the makeCredential/getAssertion request with the desired pinAuth.
     27
     28        Besides implementating the above flow, this patch also fixes some bugs within the PIN commands encoder:
     29        1. pinAuth/pinProtocol are wrongly encoded for makeCredential/getAssertion;
     30        2. AES CBC should be called without any padding. Therefore, CryptoAlgorithmAES_CBC adds a no padding mode;
     31        3. The sharedSecret is the SHA256 digest of the ECDH key agreement instead of the raw key agreement.
     32
     33        * UIProcess/API/APIWebAuthenticationPanelClient.h:
     34        (API::WebAuthenticationPanelClient::requestPin const):
     35        * UIProcess/WebAuthentication/Authenticator.h:
     36        * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
     37        (WebKit::AuthenticatorManager::requestPin):
     38        * UIProcess/WebAuthentication/AuthenticatorManager.h:
     39        * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h:
     40        * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm:
     41        (WebKit::WebAuthenticationPanelClient::WebAuthenticationPanelClient):
     42        (WebKit::WebAuthenticationPanelClient::requestPin const):
     43        * UIProcess/WebAuthentication/Mock/MockHidConnection.cpp:
     44        (WebKit::MockHidConnection::feedReports):
     45        * UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp:
     46        (WebKit::CtapAuthenticator::makeCredential):
     47        (WebKit::CtapAuthenticator::continueMakeCredentialAfterResponseReceived):
     48        (WebKit::CtapAuthenticator::getAssertion):
     49        (WebKit::CtapAuthenticator::continueGetAssertionAfterResponseReceived):
     50        (WebKit::CtapAuthenticator::getRetries):
     51        (WebKit::CtapAuthenticator::continueGetKeyAgreementAfterGetRetries):
     52        (WebKit::CtapAuthenticator::continueRequestPinAfterGetKeyAgreement):
     53        (WebKit::CtapAuthenticator::continueGetPinTokenAfterRequestPin):
     54        (WebKit::CtapAuthenticator::continueRequestAfterGetPinToken):
     55        (WebKit::CtapAuthenticator::continueMakeCredentialAfterResponseReceived const): Deleted.
     56        * UIProcess/WebAuthentication/fido/CtapAuthenticator.h:
     57
    1582020-01-13  Brent Fulgham  <bfulgham@apple.com>
    259
  • trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h

    r254356 r254439  
    3131#include <wtf/HashSet.h>
    3232#include <wtf/RefCounted.h>
     33#include <wtf/text/WTFString.h>
    3334
    3435namespace WebCore {
     
    5152    virtual void dismissPanel(WebKit::WebAuthenticationResult) const { }
    5253    virtual void selectAssertionResponses(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>& responses, CompletionHandler<void(const Ref<WebCore::AuthenticatorAssertionResponse>&)>&& completionHandler) const { completionHandler(*responses.begin()); }
     54    virtual void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&& completionHandler) const { completionHandler(emptyString()); }
    5355};
    5456
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h

    r254356 r254439  
    5353        virtual void authenticatorStatusUpdated(WebAuthenticationStatus) = 0;
    5454        virtual void selectAssertionResponses(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const Ref<WebCore::AuthenticatorAssertionResponse>&)>&&) = 0;
     55        virtual void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) = 0;
    5556    };
    5657
  • trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp

    r254356 r254439  
    280280}
    281281
     282void AuthenticatorManager::requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&& completionHandler)
     283{
     284    if (auto* panel = m_pendingRequestData.panel.get())
     285        panel->client().requestPin(retries, WTFMove(completionHandler));
     286}
     287
    282288UniqueRef<AuthenticatorTransportService> AuthenticatorManager::createService(AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const
    283289{
  • trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h

    r254356 r254439  
    8383    void authenticatorStatusUpdated(WebAuthenticationStatus) final;
    8484    void selectAssertionResponses(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const Ref<WebCore::AuthenticatorAssertionResponse>&)>&&) final;
     85    void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) final;
    8586
    8687    // Overriden by MockAuthenticatorManager.
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h

    r251317 r254439  
    5050    void updatePanel(WebAuthenticationStatus) const final;
    5151    void dismissPanel(WebAuthenticationResult) const final;
     52    void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&&) const final;
    5253
    5354    _WKWebAuthenticationPanel *m_panel;
     
    5758        bool panelUpdateWebAuthenticationPanel : 1;
    5859        bool panelDismissWebAuthenticationPanelWithResult : 1;
     60        bool panelRequestPinWithRemainingRetriesCompletionHandler : 1;
    5961    } m_delegateMethods;
    6062};
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm

    r252035 r254439  
    2929#if ENABLE(WEB_AUTHN)
    3030
     31#import "CompletionHandlerCallChecker.h"
    3132#import "WebAuthenticationFlags.h"
    3233#import "_WKWebAuthenticationPanel.h"
     34#import <wtf/BlockPtr.h>
    3335#import <wtf/RunLoop.h>
    3436
     
    4143    m_delegateMethods.panelUpdateWebAuthenticationPanel = [delegate respondsToSelector:@selector(panel:updateWebAuthenticationPanel:)];
    4244    m_delegateMethods.panelDismissWebAuthenticationPanelWithResult = [delegate respondsToSelector:@selector(panel:dismissWebAuthenticationPanelWithResult:)];
     45    m_delegateMethods.panelRequestPinWithRemainingRetriesCompletionHandler = [delegate respondsToSelector:@selector(panel:requestPINWithRemainingRetries:completionHandler:)];
    4346}
    4447
     
    108111}
    109112
     113void WebAuthenticationPanelClient::requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&& completionHandler) const
     114{
     115    // Call delegates in the next run loop to prevent clients' reentrance that would potentially modify the state
     116    // of the current run loop in unexpected ways.
     117    RunLoop::main().dispatch([weakThis = makeWeakPtr(*this), this, retries, completionHandler = WTFMove(completionHandler)] () mutable {
     118        if (!weakThis) {
     119            completionHandler(emptyString());
     120            return;
     121        }
     122
     123        if (!m_delegateMethods.panelRequestPinWithRemainingRetriesCompletionHandler) {
     124            completionHandler(emptyString());
     125            return;
     126        }
     127
     128        auto delegate = m_delegate.get();
     129        if (!delegate) {
     130            completionHandler(emptyString());
     131            return;
     132        }
     133
     134        auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(panel:requestPINWithRemainingRetries:completionHandler:));
     135        [delegate panel:m_panel requestPINWithRemainingRetries:retries completionHandler:makeBlockPtr([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](NSString *pin) mutable {
     136            if (checker->completionHandlerHasBeenCalled())
     137                return;
     138            checker->didCallCompletionHandler();
     139            completionHandler(pin);
     140        }).get()];
     141    });
     142}
     143
    110144} // namespace WebKit
    111145
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp

    r254356 r254439  
    3232#include <WebCore/CBORReader.h>
    3333#include <WebCore/FidoConstants.h>
     34#include <WebCore/Pin.h>
    3435#include <WebCore/WebAuthenticationConstants.h>
    3536#include <wtf/BlockPtr.h>
     
    224225    Optional<FidoHidMessage> message;
    225226    if (m_stage == Mock::HidStage::Info && m_subStage == Mock::HidSubStage::Msg) {
     227        // FIXME(205839):
    226228        Vector<uint8_t> infoData;
    227229        if (m_configuration.hid->canDowngrade)
    228230            infoData = encodeAsCBOR(AuthenticatorGetInfoResponse({ ProtocolVersion::kCtap, ProtocolVersion::kU2f }, Vector<uint8_t>(aaguidLength, 0u)));
    229         else
     231        else if (m_configuration.hid->supportClientPin) {
     232            AuthenticatorGetInfoResponse infoResponse({ ProtocolVersion::kCtap }, Vector<uint8_t>(aaguidLength, 0u));
     233            infoResponse.setPinProtocols({ pin::kProtocolVersion });
     234            AuthenticatorSupportedOptions options;
     235            options.setClientPinAvailability(AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet);
     236            infoResponse.setOptions(WTFMove(options));
     237            infoData = encodeAsCBOR(infoResponse);
     238        } else
    230239            infoData = encodeAsCBOR(AuthenticatorGetInfoResponse({ ProtocolVersion::kCtap }, Vector<uint8_t>(aaguidLength, 0u)));
    231240        infoData.insert(0, static_cast<uint8_t>(CtapDeviceResponseCode::kSuccess)); // Prepend status code.
  • trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp

    r254356 r254439  
    3232#include "CtapHidDriver.h"
    3333#include "U2fAuthenticator.h"
     34#include <WebCore/CryptoKeyAES.h>
     35#include <WebCore/CryptoKeyEC.h>
     36#include <WebCore/CryptoKeyHMAC.h>
    3437#include <WebCore/DeviceRequestConverter.h>
    3538#include <WebCore/DeviceResponseConverter.h>
    3639#include <WebCore/ExceptionData.h>
     40#include <WebCore/Pin.h>
    3741#include <WebCore/U2fCommandConstructor.h>
    3842#include <wtf/RunLoop.h>
     
    5458    if (processGoogleLegacyAppIdSupportExtension())
    5559        return;
    56     auto cborCmd = encodeMakeCredenitalRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options), m_info.options().userVerificationAvailability());
     60    Vector<uint8_t> cborCmd;
     61    if (m_info.options().clientPinAvailability() == AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet)
     62        cborCmd = encodeMakeCredenitalRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options), m_info.options().userVerificationAvailability(), PinParameters { pin::kProtocolVersion, m_pinAuth });
     63    else
     64        cborCmd = encodeMakeCredenitalRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options), m_info.options().userVerificationAvailability());
    5765    driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) {
    5866        ASSERT(RunLoop::isMain());
     
    6371}
    6472
    65 void CtapAuthenticator::continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&& data) const
     73void CtapAuthenticator::continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&& data)
    6674{
    6775    auto response = readCTAPMakeCredentialResponse(data, WTF::get<PublicKeyCredentialCreationOptions>(requestData().options).attestation);
     
    7078        if (error == CtapDeviceResponseCode::kCtap2ErrCredentialExcluded)
    7179            receiveRespond(ExceptionData { InvalidStateError, "At least one credential matches an entry of the excludeCredentials list in the authenticator."_s });
     80        // FIXME(205837)
     81        else if (error == CtapDeviceResponseCode::kCtap2ErrPinInvalid || error == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid)
     82            getRetries();
    7283        else
    7384            receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) });
     
    8091{
    8192    ASSERT(!m_isDowngraded);
    82     auto cborCmd = encodeGetAssertionRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialRequestOptions>(requestData().options), m_info.options().userVerificationAvailability());
     93    Vector<uint8_t> cborCmd;
     94    if (m_info.options().clientPinAvailability() == AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet)
     95        cborCmd = encodeGetAssertionRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialRequestOptions>(requestData().options), m_info.options().userVerificationAvailability(), PinParameters { pin::kProtocolVersion, m_pinAuth });
     96    else
     97        cborCmd = encodeGetAssertionRequestAsCBOR(requestData().hash, WTF::get<PublicKeyCredentialRequestOptions>(requestData().options), m_info.options().userVerificationAvailability());
    8398    driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) {
    8499        ASSERT(RunLoop::isMain());
     
    94109    if (!response) {
    95110        auto error = getResponseCode(data);
     111        // FIXME(205837)
     112        if (error == CtapDeviceResponseCode::kCtap2ErrPinInvalid || error == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid) {
     113            getRetries();
     114            return;
     115        }
    96116        if (error != CtapDeviceResponseCode::kCtap2ErrInvalidCBOR && tryDowngrade())
    97117            return;
     
    153173}
    154174
     175void CtapAuthenticator::getRetries()
     176{
     177    auto cborCmd = encodeAsCBOR(pin::RetriesRequest { });
     178    driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) {
     179        ASSERT(RunLoop::isMain());
     180        if (!weakThis)
     181            return;
     182        weakThis->continueGetKeyAgreementAfterGetRetries(WTFMove(data));
     183    });
     184}
     185
     186void CtapAuthenticator::continueGetKeyAgreementAfterGetRetries(Vector<uint8_t>&& data)
     187{
     188    auto retries = pin::RetriesResponse::parse(data);
     189    if (!retries) {
     190        auto error = getResponseCode(data);
     191        receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) });
     192        return;
     193    }
     194
     195    auto cborCmd = encodeAsCBOR(pin::KeyAgreementRequest { });
     196    driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this), retries = retries->retries] (Vector<uint8_t>&& data) {
     197        ASSERT(RunLoop::isMain());
     198        if (!weakThis)
     199            return;
     200        weakThis->continueRequestPinAfterGetKeyAgreement(WTFMove(data), retries);
     201    });
     202}
     203
     204void CtapAuthenticator::continueRequestPinAfterGetKeyAgreement(Vector<uint8_t>&& data, uint64_t retries)
     205{
     206    auto keyAgreement = pin::KeyAgreementResponse::parse(data);
     207    if (!keyAgreement) {
     208        auto error = getResponseCode(data);
     209        receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) });
     210        return;
     211    }
     212
     213    if (auto* observer = this->observer()) {
     214        observer->requestPin(retries, [weakThis = makeWeakPtr(*this), keyAgreement = WTFMove(*keyAgreement)] (const String& pin) {
     215            ASSERT(RunLoop::isMain());
     216            if (!weakThis)
     217                return;
     218            weakThis->continueGetPinTokenAfterRequestPin(pin, keyAgreement.peerKey);
     219        });
     220    }
     221}
     222
     223void CtapAuthenticator::continueGetPinTokenAfterRequestPin(const String& pin, const CryptoKeyEC& peerKey)
     224{
     225    auto pinUtf8 = pin::validateAndConvertToUTF8(pin);
     226    if (!pinUtf8) {
     227        receiveRespond(ExceptionData { UnknownError, makeString("Pin is not valid: ", pin) });
     228        return;
     229    }
     230    auto tokenRequest = pin::TokenRequest::tryCreate(*pinUtf8, peerKey);
     231    if (!tokenRequest) {
     232        receiveRespond(ExceptionData { UnknownError, "Cannot create a TokenRequest."_s });
     233        return;
     234    }
     235
     236    auto cborCmd = encodeAsCBOR(*tokenRequest);
     237    driver().transact(WTFMove(cborCmd), [weakThis = makeWeakPtr(*this), tokenRequest = WTFMove(*tokenRequest)] (Vector<uint8_t>&& data) {
     238        ASSERT(RunLoop::isMain());
     239        if (!weakThis)
     240            return;
     241        weakThis->continueRequestAfterGetPinToken(WTFMove(data), tokenRequest);
     242    });
     243}
     244
     245void CtapAuthenticator::continueRequestAfterGetPinToken(Vector<uint8_t>&& data, const fido::pin::TokenRequest& tokenRequest)
     246{
     247    auto token = pin::TokenResponse::parse(tokenRequest.sharedKey(), data);
     248    if (!token) {
     249        auto error = getResponseCode(data);
     250        receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) });
     251        return;
     252    }
     253
     254    m_pinAuth = token->pinAuth(requestData().hash);
     255    WTF::switchOn(requestData().options, [&](const PublicKeyCredentialCreationOptions& options) {
     256        makeCredential();
     257    }, [&](const PublicKeyCredentialRequestOptions& options) {
     258        getAssertion();
     259    });
     260}
     261
    155262bool CtapAuthenticator::tryDowngrade()
    156263{
  • trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h

    r254356 r254439  
    3131#include <WebCore/AuthenticatorGetInfoResponse.h>
    3232
     33namespace fido {
     34namespace pin {
     35class TokenRequest;
     36}
     37}
     38
     39namespace WebCore {
     40class CryptoKeyEC;
     41}
     42
    3343namespace WebKit {
    3444
     
    4656
    4757    void makeCredential() final;
    48     void continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&&) const;
     58    void continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&&);
    4959    void getAssertion() final;
    5060    void continueGetAssertionAfterResponseReceived(Vector<uint8_t>&&);
    5161    void continueGetNextAssertionAfterResponseReceived(Vector<uint8_t>&&);
     62
     63    void getRetries();
     64    void continueGetKeyAgreementAfterGetRetries(Vector<uint8_t>&&);
     65    void continueRequestPinAfterGetKeyAgreement(Vector<uint8_t>&&, uint64_t retries);
     66    void continueGetPinTokenAfterRequestPin(const String& pin, const CryptoKeyEC&);
     67    void continueRequestAfterGetPinToken(Vector<uint8_t>&&, const fido::pin::TokenRequest&);
    5268
    5369    bool tryDowngrade();
     
    5874    size_t m_remainingAssertionResponses { 0 };
    5975    HashSet<Ref<WebCore::AuthenticatorAssertionResponse>> m_assertionResponses;
     76    Vector<uint8_t> m_pinAuth;
    6077};
    6178
  • trunk/Tools/ChangeLog

    r254409 r254439  
     12020-01-06  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthn] Support CTAP Client Pin
     4        https://bugs.webkit.org/show_bug.cgi?id=191516
     5        <rdar://problem/56558558>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     10        * TestWebKitAPI/Tests/WebCore/CtapPinTest.cpp:
     11        (TestWebKitAPI::TEST):
     12        * TestWebKitAPI/Tests/WebCore/FidoTestData.h:
     13        * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
     14        (-[TestWebAuthenticationPanelDelegate panel:requestPINWithRemainingRetries:completionHandler:]):
     15        (TestWebKitAPI::TEST):
     16        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-pin.html: Added.
     17        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-key-agreement-error.html: Added.
     18        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-pin-token-error.html: Added.
     19        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin-get-retries-error.html: Added.
     20        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-hid-pin.html: Added.
     21
    1222020-01-11  Alex Christensen  <achristensen@webkit.org>
    223
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r254389 r254439  
    328328                55A81800218102210004A39A /* 400x400-green.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = 55A817FD218101DF0004A39A /* 400x400-green.png */; };
    329329                55F9D2E52205031800A9AB38 /* AdditionalSupportedImageTypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55F9D2E42205031800A9AB38 /* AdditionalSupportedImageTypes.mm */; };
     330                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 */; };
     331                570D26F623C3D33000D5CF67 /* web-authentication-make-credential-hid-pin.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 570D26F523C3D32700D5CF67 /* web-authentication-make-credential-hid-pin.html */; };
     332                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 */; };
     333                570D26FC23C3F87000D5CF67 /* web-authentication-get-assertion-hid-pin.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */; };
    330334                5714ECB91CA8B5B000051AC8 /* DownloadRequestOriginalURL.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */; };
    331335                5714ECBB1CA8BFE400051AC8 /* DownloadRequestOriginalURLFrame.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */; };
     
    344348                574F55D2204D47F0002948C6 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 574F55D0204D471C002948C6 /* Security.framework */; };
    345349                5758597F23A2527A00C74572 /* CtapPinTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5758597E23A2527A00C74572 /* CtapPinTest.cpp */; };
     350                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 */; };
    346351                57599E211F07191900A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm in Sources */ = {isa = PBXBuildFile; fileRef = 57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */; };
    347352                57599E271F071AA000A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3 in Copy Resources */ = {isa = PBXBuildFile; fileRef = 57599E241F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3 */; };
     
    14811486                                57663DF32357E48900E85E09 /* web-authentication-get-assertion-hid-cancel.html in Copy Resources */,
    14821487                                577454D02359B378008E1ED7 /* web-authentication-get-assertion-hid-no-credentials.html in Copy Resources */,
     1488                                570D26FC23C3F87000D5CF67 /* web-authentication-get-assertion-hid-pin.html in Copy Resources */,
    14831489                                57663DEC234F1F9300E85E09 /* web-authentication-get-assertion-hid.html in Copy Resources */,
    14841490                                579833922368FA37008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html in Copy Resources */,
     
    14861492                                577454D22359BB01008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html in Copy Resources */,
    14871493                                57C624502346C21E00383FE7 /* web-authentication-get-assertion.html in Copy Resources */,
     1494                                570D26F423C3CA6A00D5CF67 /* web-authentication-make-credential-hid-pin-get-key-agreement-error.html in Copy Resources */,
     1495                                570D26FA23C3F25100D5CF67 /* web-authentication-make-credential-hid-pin-get-pin-token-error.html in Copy Resources */,
     1496                                5758598423C3C3A400C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html in Copy Resources */,
     1497                                570D26F623C3D33000D5CF67 /* web-authentication-make-credential-hid-pin.html in Copy Resources */,
    14881498                                5798337E236019A4008E5547 /* web-authentication-make-credential-hid.html in Copy Resources */,
    14891499                                1C2B81861C89259D00A5529F /* webfont.html in Copy Resources */,
     
    18941904                55A817FE218101DF0004A39A /* 100x100-red.tga */ = {isa = PBXFileReference; lastKnownFileType = file; path = "100x100-red.tga"; sourceTree = "<group>"; };
    18951905                55F9D2E42205031800A9AB38 /* AdditionalSupportedImageTypes.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = AdditionalSupportedImageTypes.mm; sourceTree = "<group>"; };
     1906                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>"; };
     1907                570D26F523C3D32700D5CF67 /* web-authentication-make-credential-hid-pin.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin.html"; sourceTree = "<group>"; };
     1908                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>"; };
     1909                570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-get-assertion-hid-pin.html"; sourceTree = "<group>"; };
    18961910                5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURL.html; sourceTree = "<group>"; };
    18971911                5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURLFrame.html; sourceTree = "<group>"; };
     
    19121926                5758597D23A2527A00C74572 /* CtapPinTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CtapPinTest.h; sourceTree = "<group>"; };
    19131927                5758597E23A2527A00C74572 /* CtapPinTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CtapPinTest.cpp; sourceTree = "<group>"; };
     1928                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>"; };
    19141929                57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexedDBStructuredCloneBackwardCompatibility.mm; sourceTree = "<group>"; };
    19151930                57599E231F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibilityWrite.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = IndexedDBStructuredCloneBackwardCompatibilityWrite.html; sourceTree = "<group>"; };
     
    34883503                                57663DF22357E45D00E85E09 /* web-authentication-get-assertion-hid-cancel.html */,
    34893504                                577454CF2359B338008E1ED7 /* web-authentication-get-assertion-hid-no-credentials.html */,
     3505                                570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */,
    34903506                                57663DEB234F1F8000E85E09 /* web-authentication-get-assertion-hid.html */,
    34913507                                5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */,
     
    34933509                                577454D12359BAD5008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html */,
    34943510                                57C6244F2346C1EC00383FE7 /* web-authentication-get-assertion.html */,
     3511                                570D26F323C3CA5500D5CF67 /* web-authentication-make-credential-hid-pin-get-key-agreement-error.html */,
     3512                                570D26F923C3F24500D5CF67 /* web-authentication-make-credential-hid-pin-get-pin-token-error.html */,
     3513                                5758598323C3C36200C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html */,
     3514                                570D26F523C3D32700D5CF67 /* web-authentication-make-credential-hid-pin.html */,
    34953515                                5798337D2360196D008E5547 /* web-authentication-make-credential-hid.html */,
    34963516                                51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */,
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapPinTest.cpp

    r253811 r254439  
    4242#include <WebCore/WebAuthenticationConstants.h>
    4343#include <WebCore/WebAuthenticationUtils.h>
    44 #include <wtf/text/Base64.h>
     44#include <pal/crypto/CryptoDigest.h>
    4545
    4646namespace TestWebKitAPI {
     
    9999    result = RetriesResponse::parse(convertBytesToVector(TestData::kCtapClientPinRetriesResponse, sizeof(TestData::kCtapClientPinRetriesResponse)));
    100100    EXPECT_TRUE(result);
    101     EXPECT_EQ(result->retries, 8);
     101    EXPECT_EQ(result->retries, 8u);
    102102}
    103103
     
    125125    result = KeyAgreementResponse::parse(convertBytesToVector(TestData::kCtapClientPinTokenResponse, sizeof(TestData::kCtapClientPinTokenResponse))); // wrong response
    126126    EXPECT_FALSE(result);
     127
     128#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || PLATFORM(IOS)
     129    result = KeyAgreementResponse::parse(convertBytesToVector(TestData::kCtapClientPinInvalidKeyAgreementResponse, sizeof(TestData::kCtapClientPinInvalidKeyAgreementResponse))); // The point is not on the curve.
     130    EXPECT_FALSE(result);
     131#endif
    127132
    128133    // Test COSE
     
    177182    EXPECT_TRUE(token);
    178183    auto result = encodeAsCBOR(*token);
    179     EXPECT_EQ(result.size(), 120u);
     184    EXPECT_EQ(result.size(), 103u);
    180185    EXPECT_EQ(result[0], static_cast<uint8_t>(CtapRequestCommand::kAuthenticatorClientPin));
    181186
     
    225230    auto sharedKeyResult = CryptoAlgorithmECDH::platformDeriveBits(downcast<CryptoKeyEC>(*keyPair.privateKey), *cosePublicKey);
    226231    EXPECT_TRUE(sharedKeyResult);
    227     auto aesKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(*sharedKeyResult), true, CryptoKeyUsageDecrypt);
     232
     233    auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
     234    crypto->addBytes(sharedKeyResult->data(), sharedKeyResult->size());
     235    auto sharedKeyHash = crypto->computeHash();
     236
     237    auto aesKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, WTFMove(sharedKeyHash), true, CryptoKeyUsageDecrypt);
    228238    EXPECT_TRUE(aesKey);
    229239
    230240    const auto& it6 = responseMap.find(CBORValue(static_cast<uint8_t>(RequestKey::kPinHashEnc)));
    231241    EXPECT_NE(it6, responseMap.end());
    232     auto pinHashResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, *aesKey, it6->second.getByteString());
     242    auto pinHashResult = CryptoAlgorithmAES_CBC::platformDecrypt({ }, *aesKey, it6->second.getByteString(), CryptoAlgorithmAES_CBC::Padding::No);
    233243    EXPECT_FALSE(pinHashResult.hasException());
    234244    auto pinHash = pinHashResult.releaseReturnValue();
     
    241251{
    242252    const uint8_t sharedKeyData[] = {
    243         0x03, 0xac, 0x67, 0x42, 0x16, 0xf3, 0xe1, 0x5c,
    244         0x76, 0x1e, 0xe1, 0xa5, 0xe2, 0x55, 0xf0, 0x67,
    245         0x95, 0x36, 0x23, 0xc8, 0xb3, 0x88, 0xb4, 0x45,
    246         0x9e, 0x13, 0xf9, 0x78, 0xd7, 0xc8, 0x46, 0xf4, };
     253        0x29, 0x9E, 0x65, 0xB8, 0xE7, 0x71, 0xB8, 0x1D,
     254        0xB1, 0xC4, 0x8D, 0xBE, 0xCE, 0x50, 0x2A, 0x84,
     255        0x05, 0x44, 0x7F, 0x46, 0x2D, 0xE6, 0x81, 0xFA,
     256        0xEF, 0x0A, 0x6C, 0x67, 0xA7, 0x2B, 0xB5, 0x0F, };
    247257    auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, convertBytesToVector(sharedKeyData, sizeof(sharedKeyData)), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt);
    248258    ASSERT_TRUE(sharedKey);
     
    275285    // 1. Generate the token.
    276286    const uint8_t sharedKeyData[] = {
    277         0x03, 0xac, 0x67, 0x42, 0x16, 0xf3, 0xe1, 0x5c,
    278         0x76, 0x1e, 0xe1, 0xa5, 0xe2, 0x55, 0xf0, 0x67,
    279         0x95, 0x36, 0x23, 0xc8, 0xb3, 0x88, 0xb4, 0x45,
    280         0x9e, 0x13, 0xf9, 0x78, 0xd7, 0xc8, 0x46, 0xf4, };
     287        0x29, 0x9E, 0x65, 0xB8, 0xE7, 0x71, 0xB8, 0x1D,
     288        0xB1, 0xC4, 0x8D, 0xBE, 0xCE, 0x50, 0x2A, 0x84,
     289        0x05, 0x44, 0x7F, 0x46, 0x2D, 0xE6, 0x81, 0xFA,
     290        0xEF, 0x0A, 0x6C, 0x67, 0xA7, 0x2B, 0xB5, 0x0F, };
    281291    auto sharedKey = CryptoKeyAES::importRaw(CryptoAlgorithmIdentifier::AES_CBC, convertBytesToVector(sharedKeyData, sizeof(sharedKeyData)), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt);
    282292    ASSERT_TRUE(sharedKey);
     
    286296    // 2. Generate the pinAuth.
    287297    auto pinAuth = result->pinAuth(convertBytesToVector(sharedKeyData, sizeof(sharedKeyData))); // sharedKeyData pretends to be clientDataHash
    288     const uint8_t expectedPinAuth[] = { 0xb3, 0xc2, 0x65, 0x1c, 0xfd, 0xc8, 0x42, 0xb4, 0x60, 0x16, 0xed, 0x20, 0x64, 0x53, 0xaf, 0x84 };
     298    const uint8_t expectedPinAuth[] = { 0x0b, 0xec, 0x9d, 0xba, 0x69, 0xb0, 0x0f, 0x45, 0x0b, 0xec, 0x66, 0xb4, 0x75, 0x7f, 0x93, 0x85 };
    289299    EXPECT_EQ(pinAuth.size(), 16u);
    290300    EXPECT_EQ(memcmp(pinAuth.data(), expectedPinAuth, pinAuth.size()), 0);
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h

    r254356 r254439  
    613613    // True(21)
    614614    0xf5,
    615     // key(8) - pinProtocol
     615    // key(8) - pinAuth
    616616    0x08,
    617     // value - 1
    618     0x01,
    619     // key(9) - pinAuth
    620     0x09,
    621617    // bytes(16)
    622618    0x50, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
    623     0x0b, 0x0c, 0x0d, 0x0e, 0x0f
     619    0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     620    // key(9) - pinProtocol
     621    0x09,
     622    // value - 1
     623    0x01,
    624624};
    625625
     
    746746    // value - True(21)
    747747    0xf5,
    748     // key(8) - pinProtocol
    749     0x08,
    750     // value - 1
    751     0x01,
    752     // key(9) - pinAuth
    753     0x09,
     748    // key(6) - pinAuth
     749    0x06,
    754750    // bytes(16)
    755751    0x50, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
    756     0x0b, 0x0c, 0x0d, 0x0e, 0x0f
     752    0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     753    // key(7) - pinProtocol
     754    0x07,
     755    // value - 1
     756    0x01,
    757757};
    758758
     
    12281228    // key(2) - pinToken
    12291229    0x02,
    1230     // bytes(32)
    1231     0x58, 0x20,
     1230    // bytes(16)
     1231    0x50,
    12321232    // encrypted token
    1233     0x48, 0xb9, 0x5d, 0x3d, 0x9e, 0xee, 0xe5, 0x00, 0xab, 0x51, 0x13, 0x2b,
    1234     0x35, 0x77, 0x66, 0x5c, 0x41, 0x7a, 0x56, 0x3e, 0xb3, 0xe2, 0x3c, 0xb7,
    1235     0x6a, 0x37, 0xb3, 0xde, 0x57, 0x2b, 0xca, 0xaa,
     1233    0x13, 0xA4, 0xEE, 0xB7, 0x0E, 0xC9, 0x1A, 0xEA, 0x00, 0x1E, 0x93, 0x16,
     1234    0xF6, 0x1E, 0x41, 0xF7,
    12361235};
    12371236
     
    12691268};
    12701269
     1270constexpr uint8_t kCtapClientPinInvalidKeyAgreementResponse[] = {
     1271    // Success
     1272    0x00,
     1273    // map(1)
     1274    0xA1,
     1275    // key(1) - keyAgreement
     1276    0x01,
     1277    // Map(5)
     1278    0xA5,
     1279    // kty: EC key type
     1280    0x01, 0x02,
     1281    // alg: ECDH256 signature algorithm
     1282    0x03, 0x38, 0x18,
     1283    // crv: P-256 curve
     1284    0x20, 0x01,
     1285    // x-coordinate
     1286    0x21,
     1287    // Bytes(32)
     1288    0x58, 0x20,
     1289    // Byte array content
     1290    0xE8, 0x76, 0x25, 0x89, 0x6E, 0xE4, 0xE4, 0x66, 0xC0, 0x32, 0x76, 0x6E,
     1291    0x80, 0x87, 0x96, 0x2F, 0x36, 0xDF, 0x9D, 0xFF, 0x8B, 0x56, 0x7F, 0x37,
     1292    0x63, 0x01, 0x5B, 0x19, 0x90, 0xA6, 0x0E, 0x14,
     1293    // y-coordinate
     1294    0x22,
     1295    // Bytes(32)
     1296    0x58, 0x20,
     1297    // Byte array content
     1298    0x27, 0xDE, 0x61, 0x2D, 0x66, 0x41, 0x8B, 0xDA, 0x19, 0x50, 0x58, 0x1E,
     1299    0xBC, 0x5C, 0x8C, 0x1D, 0xAD, 0x71, 0x0C, 0xB1, 0x4C, 0x22, 0xF8, 0xC9,
     1300    0x70, 0x45, 0xF4, 0x61, 0x2F, 0xB2, 0x0C, 0x91,
     1301};
     1302
    12711303constexpr uint8_t kCtapClientPinRetriesResponse[] = {
    12721304    // Success
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm

    r252248 r254439  
    4646static bool webAuthenticationPanelUpdateNoCredentialsFound = false;
    4747static bool webAuthenticationPanelCancelImmediately = false;
     48static String webAuthenticationPanelPin;
    4849
    4950@interface TestWebAuthenticationPanelDelegate : NSObject <_WKWebAuthenticationPanelDelegate>
     
    8283        return;
    8384    }
     85}
     86
     87- (void)panel:(_WKWebAuthenticationPanel *)panel requestPINWithRemainingRetries:(NSUInteger)retries completionHandler:(void (^)(NSString *))completionHandler
     88{
     89    ASSERT_NE(panel, nil);
     90    EXPECT_EQ(retries, 8ul);
     91    completionHandler(webAuthenticationPanelPin);
    8492}
    8593
     
    741749}
    742750
     751TEST(WebAuthenticationPanel, PinGetRetriesError)
     752{
     753    reset();
     754    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-retries-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     755
     756    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     757    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     758
     759    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     760    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     761    [webView waitForMessage:@"Unknown internal error. Error code: 2"];
     762}
     763
     764TEST(WebAuthenticationPanel, PinGetKeyAgreementError)
     765{
     766    reset();
     767    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-key-agreement-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     768
     769    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     770    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     771
     772    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     773    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     774    [webView waitForMessage:@"Unknown internal error. Error code: 2"];
     775}
     776
     777TEST(WebAuthenticationPanel, PinRequestPinErrorNoDelegate)
     778{
     779    reset();
     780    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     781
     782    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     783    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     784
     785    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     786    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     787    [webView waitForMessage:@"Pin is not valid: "];
     788}
     789
     790TEST(WebAuthenticationPanel, PinRequestPinErrorNullDelegate)
     791{
     792    reset();
     793    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     794
     795    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     796    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     797
     798    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     799    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
     800    [delegate setIsNull:true];
     801    [webView setUIDelegate:delegate.get()];
     802
     803    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     804    [webView waitForMessage:@"Pin is not valid: "];
     805}
     806
     807TEST(WebAuthenticationPanel, PinRequestPinError)
     808{
     809    reset();
     810    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     811
     812    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     813    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     814
     815    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     816    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
     817    [webView setUIDelegate:delegate.get()];
     818
     819    webAuthenticationPanelPin = "123";
     820    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     821    [webView waitForMessage:@"Pin is not valid: 123"];
     822}
     823
     824TEST(WebAuthenticationPanel, PinGetPinTokenError)
     825{
     826    reset();
     827    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     828
     829    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     830    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     831
     832    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     833    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
     834    [webView setUIDelegate:delegate.get()];
     835
     836    webAuthenticationPanelPin = "1234";
     837    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     838    [webView waitForMessage:@"Unknown internal error. Error code: 2"];
     839}
     840
     841TEST(WebAuthenticationPanel, MakeCredentialPin)
     842{
     843    reset();
     844    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     845
     846    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     847    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     848
     849    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     850    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
     851    [webView setUIDelegate:delegate.get()];
     852
     853    webAuthenticationPanelPin = "1234";
     854    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     855    [webView waitForMessage:@"Succeeded!"];
     856}
     857
     858TEST(WebAuthenticationPanel, GetAssertionPin)
     859{
     860    reset();
     861    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     862
     863    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     864    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
     865
     866    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
     867    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
     868    [webView setUIDelegate:delegate.get()];
     869
     870    webAuthenticationPanelPin = "1234";
     871    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     872    [webView waitForMessage:@"Succeeded!"];
     873}
     874
    743875} // namespace TestWebKitAPI
    744876
Note: See TracChangeset for help on using the changeset viewer.