Changeset 287116 in webkit


Ignore:
Timestamp:
Dec 15, 2021, 4:52:57 PM (4 years ago)
Author:
J Pascoe
Message:

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

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

    r287102 r287116  
     12021-12-15  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=234309
     5        rdar://problem/86486313
     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-15  Ryan Haddad  <ryanhaddad@apple.com>
    217
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287110 r287116  
     12021-12-15  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=234309
     5        rdar://problem/86486313
     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-15  Brent Fulgham  <bfulgham@apple.com>
    234
  • trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.cpp

    r287002 r287116  
    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;
    5453
     54    bool isSameOrigin = true;
     55    bool isSameSite = true;
    5556    auto& origin = m_document->securityOrigin();
     57    auto& url = m_document->url();
    5658    for (auto* document = m_document->parentDocument(); document; document = document->parentDocument()) {
     59        if (!origin.isSameOriginDomain(document->securityOrigin()) && !areRegistrableDomainsEqual(url, document->url()))
     60            isSameSite = false;
    5761        if (!origin.isSameOriginAs(document->securityOrigin()))
    58             return false;
     62            isSameOrigin = false;
    5963    }
    60     return true;
     64
     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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287002 r287116  
    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

    r287106 r287116  
     12021-12-15  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=234309
     5        rdar://problem/86486313
     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-15  Alex Christensen  <achristensen@webkit.org>
    229
  • trunk/Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h

    r287002 r287116  
    2626#pragma once
    2727
    28 #if HAVE(UNIFIED_ASC_AUTH_UI)
    29 #import <AuthenticationServicesCore/AuthenticationServicesCore.h>
    30 #import <AuthenticationServicesCore/AuthenticationServicesCorePrivate.h>
    31 #elif HAVE(ASC_AUTH_UI)
     28#if HAVE(ASC_AUTH_UI) || HAVE(UNIFIED_ASC_AUTH_UI)
    3229
    3330NS_ASSUME_NONNULL_BEGIN
     
    7269@end
    7370
     71@interface ASCAuthorizationRemotePresenter : NSObject
     72
     73#if TARGET_OS_OSX
     74- (void)presentWithWindow:(NSWindow *)window daemonEndpoint:(NSXPCListenerEndpoint *)daemonEndpoint completionHandler:(void (^)(id <ASCCredentialProtocol>, NSError *))completionHandler;
     75#endif
     76
     77@end
     78
    7479@class ASCCredentialRequestContext;
    7580
     
    106111};
    107112
     113@class ASCPublicKeyCredentialDescriptor;
     114
     115@interface ASCPublicKeyCredentialDescriptor : NSObject <NSSecureCoding>
     116
     117- (instancetype)initWithCredentialID:(NSData *)credentialID transports:(nullable NSArray<NSString *> *)allowedTransports;
     118
     119@property (nonatomic, readonly) NSData *credentialID;
     120@property (nonatomic, nullable, readonly) NSArray<NSString *> *transports;
     121
     122@end
     123
     124@class ASCPublicKeyCredentialDescriptor;
     125
     126typedef NS_ENUM(NSUInteger, ASCPublicKeyCredentialKind) {
     127    ASCPublicKeyCredentialKindPlatform = 1,
     128    ASCPublicKeyCredentialKindSecurityKey,
     129};
     130
     131@interface ASCPublicKeyCredentialAssertionOptions : NSObject <NSSecureCoding>
     132
     133- (instancetype)initWithKind:(ASCPublicKeyCredentialKind)credentialKind relyingPartyIdentifier:(NSString *)relyingPartyIdentifier challenge:(NSData *)challenge userVerificationPreference:(nullable NSString *)userVerificationPreference allowedCredentials:(nullable NSArray<ASCPublicKeyCredentialDescriptor *> *)allowedCredentials;
     134
     135- (instancetype)initWithKind:(ASCPublicKeyCredentialKind)credentialKind relyingPartyIdentifier:(NSString *)relyingPartyIdentifier clientDataHash:(NSData *)clientDataHash userVerificationPreference:(nullable NSString *)userVerificationPreference allowedCredentials:(nullable NSArray<ASCPublicKeyCredentialDescriptor *> *)allowedCredentials;
     136
     137@property (nonatomic, readonly) ASCPublicKeyCredentialKind credentialKind;
     138@property (nonatomic, copy, readonly) NSString *relyingPartyIdentifier;
     139@property (nonatomic, nullable, copy, readonly) NSData *challenge;
     140// If clientDataHash is null, then gets generated from challenge and relyingPartyIdentifier.
     141@property (nonatomic, nullable, copy) NSData *clientDataHash;
     142@property (nonatomic, nullable, readonly, copy) NSString *userVerificationPreference;
     143
     144@property (nonatomic, nullable, readonly, copy) NSArray<ASCPublicKeyCredentialDescriptor *> *allowedCredentials;
     145
     146@end
     147
     148
     149typedef NS_OPTIONS(NSUInteger, ASCCredentialRequestTypes) {
     150    ASCCredentialRequestTypeNone = 0,
     151    ASCCredentialRequestTypePassword = 1 << 0,
     152    ASCCredentialRequestTypeAppleID = 1 << 1,
     153    ASCCredentialRequestTypePlatformPublicKeyRegistration = 1 << 2,
     154    ASCCredentialRequestTypePlatformPublicKeyAssertion = 1 << 3,
     155    ASCCredentialRequestTypeSecurityKeyPublicKeyRegistration = 1 << 4,
     156    ASCCredentialRequestTypeSecurityKeyPublicKeyAssertion = 1 << 5,
     157};
     158
    108159@interface ASCPublicKeyCredentialCreationOptions : NSObject <NSSecureCoding>
    109160
    110 @property (nonatomic, copy) NSData *challenge;
     161@property (nonatomic, nullable, copy) NSData *challenge;
     162@property (nonatomic, nullable, copy) NSData *clientDataHash;
    111163@property (nonatomic, copy) NSString *relyingPartyIdentifier;
    112164@property (nonatomic, copy) NSString *userName;
     
    114166@property (nonatomic, copy) NSString *userDisplayName;
    115167@property (nonatomic, copy) NSArray<NSNumber *> *supportedAlgorithmIdentifiers;
     168@property (nonatomic, nullable, copy) NSString *userVerificationPreference;
    116169
    117170@property (nonatomic) BOOL shouldRequireResidentKey;
     171@property (nonatomic, copy) NSArray<ASCPublicKeyCredentialDescriptor *> *excludedCredentials;
    118172
    119173@end
     
    150204@end
    151205
     206@interface ASCCredentialRequestContext : NSObject <NSSecureCoding>
     207
     208- (instancetype)init NS_UNAVAILABLE;
     209+ (instancetype)new NS_UNAVAILABLE;
     210
     211- (instancetype)initWithRequestTypes:(ASCCredentialRequestTypes)requestTypes;
     212
     213@property (nonatomic, readonly) NSUInteger requestTypes;
     214@property (nonatomic, nullable, copy) NSString *relyingPartyIdentifier;
     215
     216@property (nonatomic, nullable, copy) ASCPublicKeyCredentialCreationOptions *platformKeyCredentialCreationOptions;
     217@property (nonatomic, nullable, copy) ASCPublicKeyCredentialCreationOptions *securityKeyCredentialCreationOptions;
     218
     219@property (nonatomic, nullable, copy) ASCPublicKeyCredentialAssertionOptions *platformKeyCredentialAssertionOptions;
     220@property (nonatomic, nullable, copy) ASCPublicKeyCredentialAssertionOptions *securityKeyCredentialAssertionOptions;
     221
     222@end
     223
    152224@protocol ASCCredentialProtocol <NSObject, NSSecureCoding>
     225
     226@end
     227
     228@class _WKAuthenticatorAttestationResponse;
     229
     230@interface ASCPlatformPublicKeyCredentialRegistration : NSObject <ASCCredentialProtocol>
     231
     232- (instancetype)initWithRelyingPartyIdentifier:(NSString *)relyingPartyIdentifier attestationObject:(NSData *)attestationObject rawClientDataJSON:(NSData *)rawClientDataJSON credentialID:(NSData *)credentialID;
     233
     234- (instancetype)initWithRelyingPartyIdentifier:(NSString *)relyingPartyIdentifier authenticatorAttestationResponse:(_WKAuthenticatorAttestationResponse *)attestationResponse rawClientDataJSON:(NSData *)rawClientDataJSON;
     235
     236@property (nonatomic, copy, readonly) NSData *credentialID;
     237@property (nonatomic, copy, readonly) NSString *relyingPartyIdentifier;
     238@property (nonatomic, copy, readonly) NSData *attestationObject;
     239@property (nonatomic, copy, readonly) NSData *rawClientDataJSON;
     240
     241+ (instancetype)new NS_UNAVAILABLE;
     242- (instancetype)init NS_UNAVAILABLE;
     243
     244@end
     245
     246@interface ASCSecurityKeyPublicKeyCredentialRegistration : NSObject <ASCCredentialProtocol>
     247
     248- (instancetype)initWithRelyingPartyIdentifier:(NSString *)relyingPartyIdentifier authenticatorAttestationResponse:(_WKAuthenticatorAttestationResponse *)attestationResponse;
     249
     250@property (nonatomic, copy, readonly) NSData *credentialID;
     251@property (nonatomic, copy, readonly) NSData *rawClientDataJSON;
     252@property (nonatomic, copy, readonly) NSString *relyingPartyIdentifier;
     253@property (nonatomic, copy, readonly) NSData *attestationObject;
     254
     255@end
     256
     257@class _WKAuthenticatorAssertionResponse;
     258
     259@interface ASCPlatformPublicKeyCredentialAssertion : NSObject <ASCCredentialProtocol>
     260
     261- (instancetype)initWithRelyingPartyIdentifier:(NSString *)relyingPartyIdentifier authenticatorAssertionResponse:(_WKAuthenticatorAssertionResponse *)assertionResponse;
     262
     263@property (nonatomic, copy, readonly) NSData *credentialID;
     264@property (nonatomic, copy, readonly) NSData *rawClientDataJSON;
     265@property (nonatomic, copy, readonly) NSString *relyingPartyIdentifier;
     266@property (nonatomic, copy, readonly) NSData *authenticatorData;
     267@property (nonatomic, copy, readonly) NSData *signature;
     268@property (nonatomic, copy, readonly, nullable) NSData *userHandle;
     269
     270@end
     271
     272@interface ASCSecurityKeyPublicKeyCredentialAssertion : NSObject <ASCCredentialProtocol>
     273
     274- (instancetype)initWithRelyingPartyIdentifier:(NSString *)relyingPartyIdentifier authenticatorAssertionResponse:(_WKAuthenticatorAssertionResponse *)assertionResponse;
     275
     276@property (nonatomic, copy, readonly) NSData *credentialID;
     277@property (nonatomic, copy, readonly) NSString *relyingPartyIdentifier;
     278@property (nonatomic, copy, readonly) NSData *authenticatorData;
     279@property (nonatomic, copy, readonly) NSData *signature;
     280@property (nonatomic, copy, readonly, nullable) NSData *userHandle;
     281@property (nonatomic, copy, readonly) NSData *rawClientDataJSON;
     282
     283@end
     284
     285@protocol ASCAgentProtocol <NSObject>
     286
     287#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
     288- (void)performAuthorizationRequestsForContext:(ASCCredentialRequestContext *)context withCompletionHandler:(void (^)(id <ASCCredentialProtocol> _Nullable credential, NSError * _Nullable error))completionHandler;
     289#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST
     290- (void)performAuthorizationRequestsForContext:(ASCCredentialRequestContext *)context withClearanceHandler:(void (^)(NSXPCListenerEndpoint * _Nullable daemonEndpoint, NSError * _Nullable error))clearanceHandler;
     291
     292- (void)beginAuthorizationForApplicationIdentifier:(NSString *)applicationIdentifier fromEndpoint:(NSXPCListenerEndpoint *)listenerEndpoint;
     293
     294- (void)userSelectedLoginChoice:(id <ASCLoginChoiceProtocol>)loginChoice authenticatedContext:(LAContext *)context completionHandler:(void (^)(id <ASCCredentialProtocol> _Nullable, NSError * _Nullable))completionHandler;
     295
     296- (void)requestCompletedWithCredential:(nullable id<ASCCredentialProtocol>)credential error:(nullable NSError *)error;
     297#endif
     298
     299@end
     300
     301@interface ASCAgentProxy : NSObject <ASCAgentProtocol>
     302
     303- (instancetype)init;
     304
     305#if TARGET_OS_OSX
     306- (instancetype)initWithEndpoint:(NSXPCListenerEndpoint *)endpoint;
     307#endif
     308
     309- (void)invalidate;
     310
     311- (void)reconnectIfNecessary;
    153312
    154313@end
  • trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm

    r287002 r287116  
    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

    r287002 r287116  
    4949{
    5050    return ArrayBuffer::create(reinterpret_cast<const uint8_t*>(data.bytes), data.length);
     51}
     52
     53static inline RetainPtr<NSData> toNSData(const Vector<uint8_t>& data)
     54{
     55    return adoptNS([[NSData alloc] initWithBytes:data.data() length:data.size()]);
    5156}
    5257
     
    146151}
    147152
    148 static RetainPtr<ASCCredentialRequestContext> configureRegistrationRequestContext(const PublicKeyCredentialCreationOptions& options)
     153static RetainPtr<ASCCredentialRequestContext> configureRegistrationRequestContext(const PublicKeyCredentialCreationOptions& options, Vector<uint8_t> hash)
    149154{
    150155    ASCCredentialRequestTypes requestTypes = ASCCredentialRequestTypePlatformPublicKeyRegistration | ASCCredentialRequestTypeSecurityKeyPublicKeyRegistration;
     
    170175    auto credentialCreationOptions = adoptNS([allocASCPublicKeyCredentialCreationOptionsInstance() init]);
    171176
    172     [credentialCreationOptions setChallenge:WebCore::toNSData(options.challenge).get()];
     177    if ([credentialCreationOptions respondsToSelector:@selector(setClientDataHash:)])
     178        [credentialCreationOptions setClientDataHash:toNSData(hash).get()];
     179    else
     180        [credentialCreationOptions setChallenge:WebCore::toNSData(options.challenge).get()];
    173181    [credentialCreationOptions setRelyingPartyIdentifier:options.rp.id];
    174182    [credentialCreationOptions setUserName:options.user.name];
     
    203211}
    204212
    205 static RetainPtr<ASCCredentialRequestContext> configurationAssertionRequestContext(const PublicKeyCredentialRequestOptions& options)
     213static RetainPtr<ASCCredentialRequestContext> configurationAssertionRequestContext(const PublicKeyCredentialRequestOptions& options, Vector<uint8_t> hash)
    206214{
    207215    ASCCredentialRequestTypes requestTypes = ASCCredentialRequestTypePlatformPublicKeyAssertion | ASCCredentialRequestTypeSecurityKeyPublicKeyAssertion;
     
    228236    [requestContext setRelyingPartyIdentifier:options.rpId];
    229237
    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()]];
     238    if (requestTypes & ASCCredentialRequestTypePlatformPublicKeyAssertion) {
     239        auto assertionOptions = adoptNS(allocASCPublicKeyCredentialAssertionOptionsInstance());
     240        if ([assertionOptions respondsToSelector:@selector(initWithKind:relyingPartyIdentifier:clientDataHash:userVerificationPreference:allowedCredentials:)]) {
     241            auto nsHash = toNSData(hash);
     242            [assertionOptions initWithKind:ASCPublicKeyCredentialKindPlatform relyingPartyIdentifier:options.rpId clientDataHash:nsHash.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()];
     243        } else {
     244            auto challenge = WebCore::toNSData(options.challenge);
     245            [assertionOptions initWithKind:ASCPublicKeyCredentialKindPlatform relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()];
     246        }
     247
     248        [requestContext setPlatformKeyCredentialAssertionOptions:assertionOptions.get()];
     249    }
     250
     251    if (requestTypes & ASCCredentialRequestTypeSecurityKeyPublicKeyAssertion) {
     252        auto assertionOptions = adoptNS(allocASCPublicKeyCredentialAssertionOptionsInstance());
     253        if ([assertionOptions respondsToSelector:@selector(initWithKind:relyingPartyIdentifier:clientDataHash:userVerificationPreference:allowedCredentials:)]) {
     254            auto nsHash = toNSData(hash);
     255            [assertionOptions initWithKind:ASCPublicKeyCredentialKindSecurityKey relyingPartyIdentifier:options.rpId clientDataHash:nsHash.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()];
     256        } else {
     257            auto challenge = WebCore::toNSData(options.challenge);
     258            [assertionOptions initWithKind:ASCPublicKeyCredentialKindSecurityKey relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()];
     259        }
     260        [requestContext setSecurityKeyCredentialAssertionOptions:assertionOptions.get()];
     261    }
    237262
    238263    return requestContext;
     
    243268    RetainPtr<ASCCredentialRequestContext> result;
    244269    WTF::switchOn(requestData.options, [&](const PublicKeyCredentialCreationOptions& options) {
    245         result = configureRegistrationRequestContext(options);
     270        result = configureRegistrationRequestContext(options, requestData.hash);
    246271    }, [&](const PublicKeyCredentialRequestOptions& options) {
    247         result = configurationAssertionRequestContext(options);
     272        result = configurationAssertionRequestContext(options, requestData.hash);
    248273    });
    249274    return result;
Note: See TracChangeset for help on using the changeset viewer.