Changeset 286993 in webkit


Ignore:
Timestamp:
Dec 13, 2021 3:58:25 PM (7 months ago)
Author:
J Pascoe
Message:

[WebAuthn] Allow same-site, cross-origin iframe get()
https://bugs.webkit.org/show_bug.cgi?id=234180
rdar://85161142

Reviewed by Brent Fulgham.

Source/WebCore:

The Web Authentication level 2 specifies a feature policy to allow get calls in
cross-origin i-frames. This patch implements this feature policy partially. Only
same-site, cross-origin i-frames are supported instead. This is for tracking prevention
purposes. https://w3c.github.io/webauthn/#sctn-iframe-guidance

This patch also starts passing ClientDataJSON hashes to ASC to avoid the situation
where WebKit includes crossOrigin or other fields in ClientDataJSON that ASC is
unaware of when generating ClientDataJSON.

Added layout test cases for same-site, cross-origin get calls.

  • Modules/webauthn/AuthenticatorCoordinator.cpp:

(WebCore::AuthenticatorCoordinator::create const):
(WebCore::doesHaveSameSiteAsAncestors):
(WebCore::AuthenticatorCoordinator::discoverFromExternalSource const):

  • Modules/webauthn/WebAuthenticationUtils.cpp:

(WebCore::buildClientDataJson):

  • Modules/webauthn/WebAuthenticationUtils.h:
  • html/FeaturePolicy.cpp:

(WebCore::policyTypeName):
(WebCore::FeaturePolicy::parse):
(WebCore::FeaturePolicy::allows const):

  • html/FeaturePolicy.h:

Source/WebKit:

The Web Authentication level 2 specifies a feature policy to allow get calls in
cross-origin i-frames. This patch implements this feature policy partially. Only
same-site, cross-origin i-frames are supported instead. This is for tracking prevention
purposes. https://w3c.github.io/webauthn/#sctn-iframe-guidance

This patch also starts passing ClientDataJSON hashes to ASC to avoid the situation
where WebKit includes crossOrigin or other fields in ClientDataJSON that ASC is
unaware of when generating ClientDataJSON.

Added layout test cases for same-site, cross-origin get calls.

  • Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h:
  • UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm:

(produceClientDataJson):

  • UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm:

(WebKit::configureRegistrationRequestContext):
(WebKit::configurationAssertionRequestContext):
(WebKit::WebAuthenticatorCoordinatorProxy::contextForRequest):

LayoutTests:

Add layout test for WebAuthn get assertions on cross-site, same-sites i-frames with
publickey-credentials-get feature policy.

  • http/wpt/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt:
  • http/wpt/webauthn/public-key-credential-same-origin-with-ancestors.https.html:
  • http/wpt/webauthn/resources/util.js:
Location:
trunk
Files:
1 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r286990 r286993  
     12021-12-13  J Pascoe  <j_pascoe@apple.com>
     2
     3        [WebAuthn] Allow same-site, cross-origin iframe get()
     4        https://bugs.webkit.org/show_bug.cgi?id=234180
     5        rdar://85161142
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Add layout test for WebAuthn get assertions on cross-site, same-sites i-frames with
     10        publickey-credentials-get feature policy.
     11
     12        * http/wpt/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt:
     13        * http/wpt/webauthn/public-key-credential-same-origin-with-ancestors.https.html:
     14        * http/wpt/webauthn/resources/util.js:
     15
    1162021-12-13  Ryan Haddad  <ryanhaddad@apple.com>
    217
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt

    r267644 r286993  
    33PASS Tests that a frame that doesn't share the same origin with all its ancestors could not access the API.
    44PASS Tests that a frame that doesn't share the same origin with all its ancestors could not access the API. 2
     5PASS Tests that a frame that is same-site, cross-origin without publickey-credentials-get feature policy cannot use get().
     6PASS Tests that a frame that is same-site, cross-origin with publickey-credentials-get feature policy can use get().
     7PASS Tests that a frame that is cross-origin, NOT same-site  with publickey-credentials-get feature policy cannot use get().
    58
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-same-origin-with-ancestors.https.html

    r269360 r286993  
    2323            });
    2424        }, "Tests that a frame that doesn't share the same origin with all its ancestors could not access the API. 2");
     25
     26        promise_test(t => {
     27            return withSameSiteIframe("samesite-iframe.html").then((message) => {
     28                assert_equals(message.data, "Throw NotAllowedError: The origin of the document is not the same as its ancestors.");
     29            });
     30        }, "Tests that a frame that is same-site, cross-origin without publickey-credentials-get feature policy cannot use get().");
     31
     32        promise_test(t => {
     33            return withSameSiteIframe("samesite-iframe.html", "publickey-credentials-get").then((message) => {
     34                assert_equals(message.data, "PASS!");
     35            });
     36        }, "Tests that a frame that is same-site, cross-origin with publickey-credentials-get feature policy can use get().");
     37
     38        promise_test(t => {
     39            return withCrossOriginIframe("samesite-iframe.html", "publickey-credentials-get").then((message) => {
     40                assert_equals(message.data, "Throw NotAllowedError: The origin of the document is not the same as its ancestors.");
     41            });
     42        }, "Tests that a frame that is cross-origin, NOT same-site  with publickey-credentials-get feature policy cannot use get().");
    2543    </script>
    2644</body>
  • trunk/LayoutTests/http/wpt/webauthn/resources/util.js

    r263438 r286993  
    305305}
    306306
    307 function withCrossOriginIframe(resourceFile)
     307function withCrossOriginIframe(resourceFile, allow = "")
    308308{
    309309    return new Promise((resolve) => {
     
    312312        });
    313313        const frame = document.createElement("iframe");
     314        frame.allow = allow;
    314315        frame.src = get_host_info().HTTPS_REMOTE_ORIGIN + RESOURCES_DIR + resourceFile;
    315316        document.body.appendChild(frame);
     317    });
     318}
     319
     320function withSameSiteIframe(resourceFile, allow = "")
     321{
     322    return new Promise((resolve) => {
     323        waitForLoad().then((message) => {
     324            resolve(message);
     325       });
     326       const frame = document.createElement("iframe");
     327       const host = get_host_info();
     328       frame.allow = allow;
     329       frame.src = "https://" + host.ORIGINAL_HOST + ":" + host.HTTPS_PORT2 + RESOURCES_DIR + resourceFile;
     330       document.body.appendChild(frame);
    316331    });
    317332}
  • trunk/Source/WebCore/ChangeLog

    r286988 r286993  
     12021-12-13  J Pascoe  <j_pascoe@apple.com>
     2
     3        [WebAuthn] Allow same-site, cross-origin iframe get()
     4        https://bugs.webkit.org/show_bug.cgi?id=234180
     5        rdar://85161142
     6
     7        Reviewed by Brent Fulgham.
     8
     9        The Web Authentication level 2 specifies a feature policy to allow get calls in
     10        cross-origin i-frames. This patch implements this feature policy partially. Only
     11        same-site, cross-origin i-frames are supported instead. This is for tracking prevention
     12        purposes. https://w3c.github.io/webauthn/#sctn-iframe-guidance
     13
     14        This patch also starts passing ClientDataJSON hashes to ASC to avoid the situation
     15        where WebKit includes crossOrigin or other fields in ClientDataJSON that ASC is
     16        unaware of when generating ClientDataJSON.
     17
     18        Added layout test cases for same-site, cross-origin get calls.
     19
     20        * Modules/webauthn/AuthenticatorCoordinator.cpp:
     21        (WebCore::AuthenticatorCoordinator::create const):
     22        (WebCore::doesHaveSameSiteAsAncestors):
     23        (WebCore::AuthenticatorCoordinator::discoverFromExternalSource const):
     24        * Modules/webauthn/WebAuthenticationUtils.cpp:
     25        (WebCore::buildClientDataJson):
     26        * Modules/webauthn/WebAuthenticationUtils.h:
     27        * html/FeaturePolicy.cpp:
     28        (WebCore::policyTypeName):
     29        (WebCore::FeaturePolicy::parse):
     30        (WebCore::FeaturePolicy::allows const):
     31        * html/FeaturePolicy.h:
     32
    1332021-12-13  Andreu Botella  <andreu@andreubotella.com>
    234
  • trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.cpp

    r251295 r286993  
    3838#include "Page.h"
    3939#include "SecurityOrigin.h"
     40#include "WebAuthenticationConstants.h"
    4041
    4142namespace WebCore {
     
    4647}
    4748
    48 bool CredentialsContainer::doesHaveSameOriginAsItsAncestors()
     49WebAuthn::Scope CredentialsContainer::scope()
    4950{
    50     // The following implements https://w3c.github.io/webappsec-credential-management/#same-origin-with-its-ancestors
    51     // as of 14 November 2017.
    5251    if (!m_document)
    53         return false;
     52        return WebAuthn::Scope::CrossOrigin;
     53   
     54    bool isSameOrigin = true;
     55    bool isSameSite = true;
     56    auto& origin = m_document->securityOrigin();
     57    auto& url = m_document->url();
     58    for (auto* document = m_document->parentDocument(); document; document = document->parentDocument()) {
     59        if (!origin.isSameOriginDomain(document->securityOrigin()) && !areRegistrableDomainsEqual(url, document->url()))
     60            isSameSite = false;
     61        if (!origin.isSameOriginAs(document->securityOrigin()))
     62            isSameOrigin = false;
     63    }
    5464
    55     auto& origin = m_document->securityOrigin();
    56     for (auto* document = m_document->parentDocument(); document; document = document->parentDocument()) {
    57         if (!origin.isSameOriginAs(document->securityOrigin()))
    58             return false;
    59     }
    60     return true;
     65    if (isSameOrigin)
     66        return WebAuthn::Scope::SameOrigin;
     67    if (isSameSite)
     68        return WebAuthn::Scope::SameSite;
     69    return WebAuthn::Scope::CrossOrigin;
    6170}
    6271
     
    9099    }
    91100
    92     m_document->page()->authenticatorCoordinator().discoverFromExternalSource(*m_document, options.publicKey.value(), doesHaveSameOriginAsItsAncestors(), WTFMove(options.signal), WTFMove(promise));
     101    m_document->page()->authenticatorCoordinator().discoverFromExternalSource(*m_document, options.publicKey.value(), scope(), WTFMove(options.signal), WTFMove(promise));
    93102}
    94103
     
    125134    }
    126135
    127     m_document->page()->authenticatorCoordinator().create(*m_document, options.publicKey.value(), doesHaveSameOriginAsItsAncestors(), WTFMove(options.signal), WTFMove(promise));
     136    m_document->page()->authenticatorCoordinator().create(*m_document, options.publicKey.value(), scope(), WTFMove(options.signal), WTFMove(promise));
    128137}
    129138
  • trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.h

    r235888 r286993  
    3333#include <wtf/WeakPtr.h>
    3434
     35namespace WebAuthn {
     36enum class Scope;
     37}
     38
    3539namespace WebCore {
    3640
     
    5559    CredentialsContainer(WeakPtr<Document>&&);
    5660
    57     bool doesHaveSameOriginAsItsAncestors();
     61    WebAuthn::Scope scope();
    5862
    5963    WeakPtr<Document> m_document;
  • trunk/Source/WebCore/Modules/webauthn/AuthenticatorCoordinator.cpp

    r285617 r286993  
    3535#include "AuthenticatorResponseData.h"
    3636#include "Document.h"
     37#include "FeaturePolicy.h"
    3738#include "JSBasicCredential.h"
    3839#include "JSDOMPromiseDeferred.h"
     
    105106}
    106107
    107 void AuthenticatorCoordinator::create(const Document& document, const PublicKeyCredentialCreationOptions& options, bool sameOriginWithAncestors, RefPtr<AbortSignal>&& abortSignal, CredentialPromise&& promise) const
     108void AuthenticatorCoordinator::create(const Document& document, const PublicKeyCredentialCreationOptions& options, WebAuthn::Scope scope, RefPtr<AbortSignal>&& abortSignal, CredentialPromise&& promise) const
    108109{
    109110    using namespace AuthenticatorCoordinatorInternal;
     
    115116    // Step 1, 3, 16 are handled by the caller.
    116117    // Step 2.
    117     if (!sameOriginWithAncestors) {
     118    if (scope != WebAuthn::Scope::SameOrigin) {
    118119        promise.reject(Exception { NotAllowedError, "The origin of the document is not the same as its ancestors."_s });
    119120        return;
     
    149150
    150151    // Step 13-15.
    151     auto clientDataJson = buildClientDataJson(ClientDataType::Create, options.challenge, callerOrigin);
     152    auto clientDataJson = buildClientDataJson(ClientDataType::Create, options.challenge, callerOrigin, scope);
    152153    auto clientDataJsonHash = buildClientDataJsonHash(clientDataJson);
    153154
     
    176177}
    177178
    178 void AuthenticatorCoordinator::discoverFromExternalSource(const Document& document, const PublicKeyCredentialRequestOptions& options, bool sameOriginWithAncestors, RefPtr<AbortSignal>&& abortSignal, CredentialPromise&& promise) const
     179void AuthenticatorCoordinator::discoverFromExternalSource(const Document& document, const PublicKeyCredentialRequestOptions& options, WebAuthn::Scope scope, RefPtr<AbortSignal>&& abortSignal, CredentialPromise&& promise) const
    179180{
    180181    using namespace AuthenticatorCoordinatorInternal;
     
    186187    // Step 1, 3, 13 are handled by the caller.
    187188    // Step 2.
    188     if (!sameOriginWithAncestors) {
     189    // This implements https://www.w3.org/TR/webauthn-2/#sctn-permissions-policy except only same-site, cross-origin is permitted.
     190    if (scope != WebAuthn::Scope::SameOrigin && !(scope == WebAuthn::Scope::SameSite && isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::PublickeyCredentialsGetRule, document, LogFeaturePolicyFailure::No))) {
    189191        promise.reject(Exception { NotAllowedError, "The origin of the document is not the same as its ancestors."_s });
    190192        return;
     
    220222
    221223    // Step 10-12.
    222     auto clientDataJson = buildClientDataJson(ClientDataType::Get, options.challenge, callerOrigin);
     224    auto clientDataJson = buildClientDataJson(ClientDataType::Get, options.challenge, callerOrigin, scope);
    223225    auto clientDataJsonHash = buildClientDataJsonHash(clientDataJson);
    224226
  • trunk/Source/WebCore/Modules/webauthn/AuthenticatorCoordinator.h

    r272345 r286993  
    3232#include <wtf/Noncopyable.h>
    3333
     34namespace WebAuthn {
     35enum class Scope;
     36}
     37
    3438namespace WebCore {
    3539
     
    5458
    5559    // The following methods implement static methods of PublicKeyCredential.
    56     void create(const Document&, const PublicKeyCredentialCreationOptions&, bool sameOriginWithAncestors, RefPtr<AbortSignal>&&, CredentialPromise&&) const;
    57     void discoverFromExternalSource(const Document&, const PublicKeyCredentialRequestOptions&, bool sameOriginWithAncestors, RefPtr<AbortSignal>&&, CredentialPromise&&) const;
     60    void create(const Document&, const PublicKeyCredentialCreationOptions&, WebAuthn::Scope, RefPtr<AbortSignal>&&, CredentialPromise&&) const;
     61    void discoverFromExternalSource(const Document&, const PublicKeyCredentialRequestOptions&, WebAuthn::Scope, RefPtr<AbortSignal>&&, CredentialPromise&&) const;
    5862    void isUserVerifyingPlatformAuthenticatorAvailable(DOMPromiseDeferred<IDLBoolean>&&) const;
    5963
  • trunk/Source/WebCore/Modules/webauthn/WebAuthenticationConstants.h

    r261118 r286993  
    8181
    8282} // namespace WebCore
     83
     84namespace WebAuthn {
     85
     86enum class Scope {
     87    CrossOrigin,
     88    SameOrigin,
     89    SameSite
     90};
     91
     92} // namespace WebAuthn
  • trunk/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.cpp

    r285617 r286993  
    135135
    136136// FIXME(181948): Add token binding ID.
    137 Ref<ArrayBuffer> buildClientDataJson(ClientDataType type, const BufferSource& challenge, const SecurityOrigin& origin)
     137Ref<ArrayBuffer> buildClientDataJson(ClientDataType type, const BufferSource& challenge, const SecurityOrigin& origin, WebAuthn::Scope scope)
    138138{
    139139    auto object = JSON::Object::create();
     
    148148    object->setString("challenge"_s, base64URLEncodeToString(challenge.data(), challenge.length()));
    149149    object->setString("origin"_s, origin.toRawString());
     150    if (scope != WebAuthn::Scope::SameOrigin)
     151        object->setBoolean("crossOrigin"_s, scope != WebAuthn::Scope::SameOrigin);
    150152
    151153    auto utf8JSONString = object->toJSONString().utf8();
  • trunk/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.h

    r285617 r286993  
    5353WEBCORE_EXPORT Vector<uint8_t> buildAttestationObject(Vector<uint8_t>&& authData, String&& format, cbor::CBORValue::MapValue&& statementMap, const AttestationConveyancePreference&);
    5454
    55 WEBCORE_EXPORT Ref<ArrayBuffer> buildClientDataJson(ClientDataType /*type*/, const BufferSource& challenge, const SecurityOrigin& /*origin*/);
     55WEBCORE_EXPORT Ref<ArrayBuffer> buildClientDataJson(ClientDataType /*type*/, const BufferSource& challenge, const SecurityOrigin& /*origin*/, WebAuthn::Scope);
    5656
    5757WEBCORE_EXPORT Vector<uint8_t> buildClientDataJsonHash(const ArrayBuffer& clientDataJson);
  • trunk/Source/WebCore/html/FeaturePolicy.cpp

    r283851 r286993  
    6868        return "Magnetometer";
    6969#endif
     70#if ENABLE(WEB_AUTHN)
     71    case FeaturePolicy::Type::PublickeyCredentialsGetRule:
     72        return "PublickeyCredentialsGet";
     73#endif
    7074#if ENABLE(WEBXR)
    7175    case FeaturePolicy::Type::XRSpatialTracking:
     
    185189    bool isMagnetometerInitialized = false;
    186190#endif
     191#if ENABLE(WEB_AUTHN)
     192    bool isPublickeyCredentialsGetInitialized = false;
     193#endif
    187194#if ENABLE(WEBXR)
    188195    bool isXRSpatialTrackingInitialized = false;
     
    249256            isMagnetometerInitialized = true;
    250257            updateList(document, policy.m_magnetometerRule, item.substring(13));
     258            continue;
     259        }
     260#endif
     261#if ENABLE(WEB_AUTHN)
     262        if (item.startsWith("publickey-credentials-get")) {
     263            isPublickeyCredentialsGetInitialized = true;
     264            updateList(document, policy.m_publickeyCredentialsGetRule, item.substring(26));
    251265            continue;
    252266        }
     
    283297    if (!isMagnetometerInitialized)
    284298        policy.m_magnetometerRule.allowedList.add(document.securityOrigin().data());
     299#endif
     300#if ENABLE(WEB_AUTHN)
     301    if (!isPublickeyCredentialsGetInitialized)
     302        policy.m_publickeyCredentialsGetRule.allowedList.add(document.securityOrigin().data());
    285303#endif
    286304#if ENABLE(WEBXR)
     
    339357        return isAllowedByFeaturePolicy(m_magnetometerRule, origin);
    340358#endif
     359#if ENABLE(WEB_AUTHN)
     360    case Type::PublickeyCredentialsGetRule:
     361        return isAllowedByFeaturePolicy(m_publickeyCredentialsGetRule, origin);
     362#endif
    341363#if ENABLE(WEBXR)
    342364    case Type::XRSpatialTracking:
  • trunk/Source/WebCore/html/FeaturePolicy.h

    r282746 r286993  
    5454        Magnetometer,
    5555#endif
     56#if ENABLE(WEB_AUTHN)
     57        PublickeyCredentialsGetRule,
     58#endif
    5659#if ENABLE(WEBXR)
    5760        XRSpatialTracking,
     
    8285    AllowRule m_magnetometerRule;
    8386#endif
     87#if ENABLE(WEB_AUTHN)
     88    AllowRule m_publickeyCredentialsGetRule;
     89#endif
    8490#if ENABLE(WEBXR)
    8591    AllowRule m_xrSpatialTrackingRule;
  • trunk/Source/WebKit/ChangeLog

    r286983 r286993  
     12021-12-13  J Pascoe  <j_pascoe@apple.com>
     2
     3        [WebAuthn] Allow same-site, cross-origin iframe get()
     4        https://bugs.webkit.org/show_bug.cgi?id=234180
     5        rdar://85161142
     6
     7        Reviewed by Brent Fulgham.
     8
     9        The Web Authentication level 2 specifies a feature policy to allow get calls in
     10        cross-origin i-frames. This patch implements this feature policy partially. Only
     11        same-site, cross-origin i-frames are supported instead. This is for tracking prevention
     12        purposes. https://w3c.github.io/webauthn/#sctn-iframe-guidance
     13
     14        This patch also starts passing ClientDataJSON hashes to ASC to avoid the situation
     15        where WebKit includes crossOrigin or other fields in ClientDataJSON that ASC is
     16        unaware of when generating ClientDataJSON.
     17
     18        Added layout test cases for same-site, cross-origin get calls.
     19
     20        * Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h:
     21        * UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm:
     22        (produceClientDataJson):
     23        * UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm:
     24        (WebKit::configureRegistrationRequestContext):
     25        (WebKit::configurationAssertionRequestContext):
     26        (WebKit::WebAuthenticatorCoordinatorProxy::contextForRequest):
     27
    1282021-12-13  Jean-Yves Avenard  <jya@apple.com>
    229
  • trunk/Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h

    r284268 r286993  
    108108@interface ASCPublicKeyCredentialCreationOptions : NSObject <NSSecureCoding>
    109109
    110 @property (nonatomic, copy) NSData *challenge;
     110@property (nonatomic, nullable, copy) NSData *challenge;
     111@property (nonatomic, nullable, copy) NSData *clientDataHash;
    111112@property (nonatomic, copy) NSString *relyingPartyIdentifier;
    112113@property (nonatomic, copy) NSString *userName;
     
    117118@property (nonatomic) BOOL shouldRequireResidentKey;
    118119
     120@end
     121
     122@interface ASCPublicKeyCredentialAssertionOptions : NSObject <NSSecureCoding>
     123@property (nonatomic, copy, readonly) NSString *relyingPartyIdentifier;
     124@property (nonatomic, nullable, copy, readonly) NSData *challenge;
     125@property (nonatomic, nullable, copy) NSData *clientDataHash;
     126@property (nonatomic, nullable, readonly, copy) NSString *userVerificationPreference;
    119127@end
    120128
  • trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm

    r286746 r286993  
    8888    auto securityOrigin = WebCore::SecurityOrigin::createFromString(origin);
    8989
    90     auto clientDataJson = buildClientDataJson(clientDataType, WebCore::BufferSource(challengeBuffer), securityOrigin);
     90    auto clientDataJson = buildClientDataJson(clientDataType, WebCore::BufferSource(challengeBuffer), securityOrigin, WebAuthn::Scope::SameOrigin);
    9191    return adoptNS([[NSData alloc] initWithBytes:clientDataJson->data() length:clientDataJson->byteLength()]);
    9292}
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm

    r285864 r286993  
    146146}
    147147
    148 static RetainPtr<ASCCredentialRequestContext> configureRegistrationRequestContext(const PublicKeyCredentialCreationOptions& options)
     148static RetainPtr<ASCCredentialRequestContext> configureRegistrationRequestContext(const PublicKeyCredentialCreationOptions& options, NSData *hash)
    149149{
    150150    ASCCredentialRequestTypes requestTypes = ASCCredentialRequestTypePlatformPublicKeyRegistration | ASCCredentialRequestTypeSecurityKeyPublicKeyRegistration;
     
    170170    auto credentialCreationOptions = adoptNS([allocASCPublicKeyCredentialCreationOptionsInstance() init]);
    171171
    172     [credentialCreationOptions setChallenge:WebCore::toNSData(options.challenge).get()];
     172    if ([credentialCreationOptions respondsToSelector:@selector(setClientDataHash:)])
     173        [credentialCreationOptions setClientDataHash:toNSData(hash).get()];
     174    else
     175        [credentialCreationOptions setChallenge:WebCore::toNSData(options.challenge).get()];
    173176    [credentialCreationOptions setRelyingPartyIdentifier:options.rp.id];
    174177    [credentialCreationOptions setUserName:options.user.name];
     
    203206}
    204207
    205 static RetainPtr<ASCCredentialRequestContext> configurationAssertionRequestContext(const PublicKeyCredentialRequestOptions& options)
     208static RetainPtr<ASCCredentialRequestContext> configurationAssertionRequestContext(const PublicKeyCredentialRequestOptions& options, Vector<uint_8> hash)
    206209{
    207210    ASCCredentialRequestTypes requestTypes = ASCCredentialRequestTypePlatformPublicKeyAssertion | ASCCredentialRequestTypeSecurityKeyPublicKeyAssertion;
     
    228231    [requestContext setRelyingPartyIdentifier:options.rpId];
    229232
    230     auto challenge = WebCore::toNSData(options.challenge);
    231 
    232     if (requestTypes & ASCCredentialRequestTypePlatformPublicKeyAssertion)
    233         [requestContext setPlatformKeyCredentialAssertionOptions:[allocASCPublicKeyCredentialAssertionOptionsInstance() initWithKind:ASCPublicKeyCredentialKindPlatform relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()]];
    234 
    235     if (requestTypes & ASCCredentialRequestTypeSecurityKeyPublicKeyAssertion)
    236         [requestContext setSecurityKeyCredentialAssertionOptions:[allocASCPublicKeyCredentialAssertionOptionsInstance() initWithKind:ASCPublicKeyCredentialKindSecurityKey relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()]];
     233    if (requestTypes & ASCCredentialRequestTypePlatformPublicKeyAssertion) {
     234        auto assertionOptions = adoptNS(allocASCPublicKeyCredentialAssertionOptionsInstance());
     235        if ([assertionOptions respondsToSelector:@selector(initWithKind:relyingPartyIdentifier:clientDataHash:userVerificationPreference:allowedCredentials:)]) {
     236            auto nsHash = toNSData(hash);
     237            [assertionOptions initWithKind:ASCPublicKeyCredentialKindPlatform relyingPartyIdentifier:options.rpId clientDataHash:nsHash userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()]
     238        } else {
     239            auto challenge = WebCore::toNSData(options.challenge);
     240            [assertionOptions initWithKind:ASCPublicKeyCredentialKindPlatform relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()]
     241        }
     242
     243        [requestContext setPlatformKeyCredentialAssertionOptions:assertionOptions.get()];
     244    }
     245
     246    if (requestTypes & ASCCredentialRequestTypeSecurityKeyPublicKeyAssertion) {
     247        auto assertionOptions = adoptNS(allocASCPublicKeyCredentialAssertionOptionsInstance());
     248        if ([assertionOptions respondsToSelector:@selector(initWithKind:relyingPartyIdentifier:clientDataHash:userVerificationPreference:allowedCredentials:)]) {
     249            auto nsHash = toNSData(hash);
     250            [assertionOptions initWithKind:ASCPublicKeyCredentialKindSecurityKey relyingPartyIdentifier:options.rpId clientDataHash:nsHash userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()]];
     251        } else {
     252            auto challenge = WebCore::toNSData(options.challenge);
     253            [assertionOptions initWithKind:ASCPublicKeyCredentialKindSecurityKey relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()]];
     254        }
     255        [requestContext setSecurityKeyCredentialAssertionOptions:assertionOptions.get()];
     256    }
    237257
    238258    return requestContext;
     
    243263    RetainPtr<ASCCredentialRequestContext> result;
    244264    WTF::switchOn(requestData.options, [&](const PublicKeyCredentialCreationOptions& options) {
    245         result = configureRegistrationRequestContext(options);
     265        result = configureRegistrationRequestContext(options, requestData.hash);
    246266    }, [&](const PublicKeyCredentialRequestOptions& options) {
    247         result = configurationAssertionRequestContext(options);
     267        result = configurationAssertionRequestContext(options, requestData.hash);
    248268    });
    249269    return result;
Note: See TracChangeset for help on using the changeset viewer.