⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 276180 in webkit


Ignore:
Timestamp:
Apr 16, 2021, 4:52:30 PM (5 years ago)
Author:
jiewen_tan@apple.com
Message:

Allow using the platform authenticator on non-Touch ID Macs according to Internal requirements
https://bugs.webkit.org/show_bug.cgi?id=224639
<rdar://74698346>

Reviewed by Daniel Bates.

Source/WebCore:

Covered by new tests within existing test files.

  • testing/MockWebAuthenticationConfiguration.h:
  • testing/MockWebAuthenticationConfiguration.idl:

Mock testing support.

Source/WebKit:

  • UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:

(WebKit::LocalAuthenticator::continueMakeCredentialAfterDecidePolicy):
(WebKit::LocalAuthenticator::continueMakeCredentialAfterUserVerification):
(WebKit::LocalAuthenticator::continueGetAssertionAfterResponseSelected):
(WebKit::LocalAuthenticator::continueGetAssertionAfterUserVerification):
Don't set the UserVerification bit if UserVerification is not done.

  • UIProcess/WebAuthentication/Cocoa/LocalConnection.h:
  • UIProcess/WebAuthentication/Cocoa/LocalConnection.mm:

(WebKit::LocalConnection::verifyUser):
Only check UserPresence on non-Touch ID Macs.

  • UIProcess/WebAuthentication/Cocoa/LocalService.mm:

(WebKit::LocalService::isAvailable):
Make the platform authenticator available according to Internal requirements.

  • UIProcess/WebAuthentication/Mock/MockLocalConnection.h:
  • UIProcess/WebAuthentication/Mock/MockLocalConnection.mm:

(WebKit::MockLocalConnection::verifyUser):
Mock testing support.

  • UIProcess/WebAuthentication/WebAuthenticationRequestData.cpp:

(WebKit::getUserVerificationRequirement):

  • UIProcess/WebAuthentication/WebAuthenticationRequestData.h:

Add a helper for extracting the UserVerification input.

LayoutTests:

  • http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt:
  • http/wpt/webauthn/public-key-credential-create-success-local.https.html:
  • http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt:
  • http/wpt/webauthn/public-key-credential-get-success-local.https.html:
Location:
trunk
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r276178 r276180  
     12021-04-16  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        Allow using the platform authenticator on non-Touch ID Macs according to Internal requirements
     4        https://bugs.webkit.org/show_bug.cgi?id=224639
     5        <rdar://74698346>
     6
     7        Reviewed by Daniel Bates.
     8
     9        * http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt:
     10        * http/wpt/webauthn/public-key-credential-create-success-local.https.html:
     11        * http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt:
     12        * http/wpt/webauthn/public-key-credential-get-success-local.https.html:
     13
    1142021-04-16  Robert Jenner  <jenner@apple.com>
    215
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https-expected.txt

    r272345 r276180  
     1CONSOLE MESSAGE: User gesture is not detected. To use the WebAuthn API, call 'navigator.credentials.create' within user activated events.
    12CONSOLE MESSAGE: User gesture is not detected. To use the WebAuthn API, call 'navigator.credentials.create' within user activated events.
    23CONSOLE MESSAGE: User gesture is not detected. To use the WebAuthn API, call 'navigator.credentials.create' within user activated events.
     
    1617PASS PublicKeyCredential's [[create]] with duplicate credential in a mock local authenticator.
    1718PASS PublicKeyCredential's [[create]] with duplicate credential in a mock local authenticator. 2
     19PASS PublicKeyCredential's [[create]] with user presence in a mock local authenticator.
    1820
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-local.https.html

    r269420 r276180  
    66<script src="./resources/cbor.js"></script>
    77<script>
    8     function checkResult(credential, credentialID, isNoneAttestation = true)
     8    function checkResult(credential, credentialID, isNoneAttestation = true, isUV = true)
    99    {
    1010        // Check keychain
     
    3030        const authData = decodeAuthData(attestationObject.authData);
    3131        assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763");
    32         assert_equals(authData.flags, 69);
     32        if (isUV)
     33            assert_equals(authData.flags, 69);
     34        else
     35            assert_equals(authData.flags, 65);
    3336        assert_equals(authData.counter, 0);
    3437        if (isNoneAttestation)
     
    345348        });
    346349    }, "PublicKeyCredential's [[create]] with duplicate credential in a mock local authenticator. 2");
     350
     351    promise_test(async t => {
     352        const privateKeyBase64 = await generatePrivateKeyBase64();
     353        const credentialID = await calculateCredentialID(privateKeyBase64);
     354        const userhandleBase64 = generateUserhandleBase64();
     355        if (window.internals)
     356            internals.setMockWebAuthenticationConfiguration({
     357                local: {
     358                    userVerification: "presence",
     359                    acceptAttestation: false,
     360                    privateKeyBase64: privateKeyBase64,
     361                }
     362            });
     363
     364        const options = {
     365            publicKey: {
     366                rp: {
     367                    name: "localhost",
     368                },
     369                user: {
     370                    name: userhandleBase64,
     371                    id: Base64URL.parse(userhandleBase64),
     372                    displayName: "Appleseed",
     373                },
     374                challenge: Base64URL.parse("MTIzNDU2"),
     375                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
     376            }
     377        };
     378
     379        return navigator.credentials.create(options).then(credential => {
     380            checkResult(credential, credentialID, true, false);
     381        });
     382    }, "PublicKeyCredential's [[create]] with user presence in a mock local authenticator.");
    347383</script>
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https-expected.txt

    r272345 r276180  
     1CONSOLE MESSAGE: User gesture is not detected. To use the WebAuthn API, call 'navigator.credentials.create' within user activated events.
    12CONSOLE MESSAGE: User gesture is not detected. To use the WebAuthn API, call 'navigator.credentials.create' within user activated events.
    23CONSOLE MESSAGE: User gesture is not detected. To use the WebAuthn API, call 'navigator.credentials.create' within user activated events.
     
    45PASS PublicKeyCredential's [[get]] with minimum options in a mock local authenticator.
    56PASS PublicKeyCredential's [[get]] with matched allow credentials in a mock local authenticator.
     7PASS PublicKeyCredential's [[get]] with user presence in a mock local authenticator.
    68
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-local.https.html

    r269360 r276180  
    55<script src="./resources/util.js"></script>
    66<script>
    7     function checkResult(credential, credentialID, privateKeyBase64)
     7    function checkResult(credential, credentialID, privateKeyBase64, isUV = true)
    88    {
    99        if (window.testRunner)
     
    2121        const authData = decodeAuthData(new Uint8Array(credential.response.authenticatorData));
    2222        assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763");
    23         assert_equals(authData.flags, 5);
     23        if (isUV)
     24            assert_equals(authData.flags, 5);
     25        else
     26            assert_equals(authData.flags, 1);
    2427        assert_equals(authData.counter, 0);
    2528
     
    8184        });
    8285    }, "PublicKeyCredential's [[get]] with matched allow credentials in a mock local authenticator.");
     86
     87    promise_test(async t => {
     88        const privateKeyBase64 = await generatePrivateKeyBase64();
     89        const credentialID = await calculateCredentialID(privateKeyBase64);
     90        const credentialIDBase64 = base64encode(credentialID);
     91        // Default mock configuration. Tests need to override if they need different configuration.
     92        if (window.internals)
     93            internals.setMockWebAuthenticationConfiguration({ local: { userVerification: "presence", acceptAttestation: false, preferredCredentialIdBase64: credentialIDBase64 } });
     94
     95        const options = {
     96            publicKey: {
     97                challenge: Base64URL.parse("MTIzNDU2")
     98            }
     99        };
     100
     101        if (window.testRunner)
     102            testRunner.addTestKeyToKeychain(privateKeyBase64, testRpId, testUserEntityBundleBase64);
     103        return navigator.credentials.get(options).then(credential => {
     104            return checkResult(credential, credentialID, privateKeyBase64, false);
     105        });
     106    }, "PublicKeyCredential's [[get]] with user presence in a mock local authenticator.");
    83107</script>
  • trunk/Source/WebCore/ChangeLog

    r276177 r276180  
     12021-04-16  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        Allow using the platform authenticator on non-Touch ID Macs according to Internal requirements
     4        https://bugs.webkit.org/show_bug.cgi?id=224639
     5        <rdar://74698346>
     6
     7        Reviewed by Daniel Bates.
     8
     9        Covered by new tests within existing test files.
     10
     11        * testing/MockWebAuthenticationConfiguration.h:
     12        * testing/MockWebAuthenticationConfiguration.idl:
     13        Mock testing support.
     14
    1152021-04-16  Peng Liu  <peng.liu6@apple.com>
    216
  • trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.h

    r262994 r276180  
    6565        No,
    6666        Yes,
    67         Cancel
     67        Cancel,
     68        Presence
    6869    };
    6970
     
    309310        WebCore::MockWebAuthenticationConfiguration::UserVerification::No,
    310311        WebCore::MockWebAuthenticationConfiguration::UserVerification::Yes,
    311         WebCore::MockWebAuthenticationConfiguration::UserVerification::Cancel
     312        WebCore::MockWebAuthenticationConfiguration::UserVerification::Cancel,
     313        WebCore::MockWebAuthenticationConfiguration::UserVerification::Presence
    312314    >;
    313315};
  • trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl

    r259680 r276180  
    6565    "no",
    6666    "yes",
    67     "cancel"
     67    "cancel",
     68    "presence"
    6869};
    6970
  • trunk/Source/WebKit/ChangeLog

    r276177 r276180  
     12021-04-16  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        Allow using the platform authenticator on non-Touch ID Macs according to Internal requirements
     4        https://bugs.webkit.org/show_bug.cgi?id=224639
     5        <rdar://74698346>
     6
     7        Reviewed by Daniel Bates.
     8
     9        * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:
     10        (WebKit::LocalAuthenticator::continueMakeCredentialAfterDecidePolicy):
     11        (WebKit::LocalAuthenticator::continueMakeCredentialAfterUserVerification):
     12        (WebKit::LocalAuthenticator::continueGetAssertionAfterResponseSelected):
     13        (WebKit::LocalAuthenticator::continueGetAssertionAfterUserVerification):
     14        Don't set the UserVerification bit if UserVerification is not done.
     15
     16        * UIProcess/WebAuthentication/Cocoa/LocalConnection.h:
     17        * UIProcess/WebAuthentication/Cocoa/LocalConnection.mm:
     18        (WebKit::LocalConnection::verifyUser):
     19        Only check UserPresence on non-Touch ID Macs.
     20
     21        * UIProcess/WebAuthentication/Cocoa/LocalService.mm:
     22        (WebKit::LocalService::isAvailable):
     23        Make the platform authenticator available according to Internal requirements.
     24
     25        * UIProcess/WebAuthentication/Mock/MockLocalConnection.h:
     26        * UIProcess/WebAuthentication/Mock/MockLocalConnection.mm:
     27        (WebKit::MockLocalConnection::verifyUser):
     28        Mock testing support.
     29
     30        * UIProcess/WebAuthentication/WebAuthenticationRequestData.cpp:
     31        (WebKit::getUserVerificationRequirement):
     32        * UIProcess/WebAuthentication/WebAuthenticationRequestData.h:
     33        Add a helper for extracting the UserVerification input.
     34
    1352021-04-16  Peng Liu  <peng.liu6@apple.com>
    236
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm

    r274689 r276180  
    6565// See https://www.w3.org/TR/webauthn/#flags.
    6666const uint8_t makeCredentialFlags = 0b01000101; // UP, UV and AT are set.
     67const uint8_t otherMakeCredentialFlags = 0b01000001; // UP and AT are set.
    6768const uint8_t getAssertionFlags = 0b00000101; // UP and UV are set.
     69const uint8_t otherGetAssertionFlags = 0b00000001; // UP is set.
    6870// Credential ID is currently SHA-1 of the corresponding public key.
    6971const uint16_t credentialIdLength = 20;
     
    307309        weakThis->continueMakeCredentialAfterUserVerification(accessControl.get(), verification, context);
    308310    };
    309     m_connection->verifyUser(creationOptions.rp.id, getClientDataType(requestData().options), accessControlRef, WTFMove(callback));
     311    m_connection->verifyUser(creationOptions.rp.id, getClientDataType(requestData().options), accessControlRef, getUserVerificationRequirement(requestData().options), WTFMove(callback));
    310312}
    311313
     
    426428    }
    427429
     430    auto flags = verification == LocalConnection::UserVerification::Presence ? otherMakeCredentialFlags : makeCredentialFlags;
    428431    // Step 12.
    429432    // Skip Apple Attestation for none attestation.
     
    431434        deleteDuplicateCredential();
    432435
    433         auto authData = buildAuthData(creationOptions.rp.id, makeCredentialFlags, counter, buildAttestedCredentialData(Vector<uint8_t>(aaguidLength, 0), credentialId, cosePublicKey));
     436        auto authData = buildAuthData(creationOptions.rp.id, flags, counter, buildAttestedCredentialData(Vector<uint8_t>(aaguidLength, 0), credentialId, cosePublicKey));
    434437        auto attestationObject = buildAttestationObject(WTFMove(authData), "", { }, AttestationConveyancePreference::None);
    435438        receiveRespond(AuthenticatorAttestationResponse::create(credentialId, attestationObject));
     
    438441
    439442    // Step 13. Apple Attestation
    440     auto authData = buildAuthData(creationOptions.rp.id, makeCredentialFlags, counter, buildAttestedCredentialData(aaguidVector(), credentialId, cosePublicKey));
     443    auto authData = buildAuthData(creationOptions.rp.id, flags, counter, buildAttestedCredentialData(aaguidVector(), credentialId, cosePublicKey));
    441444    auto nsAuthData = toNSData(authData);
    442445    auto callback = [credentialId = WTFMove(credentialId), authData = WTFMove(authData), weakThis = makeWeakPtr(*this)] (NSArray * _Nullable certificates, NSError * _Nullable error) mutable {
     
    580583        weakThis->continueGetAssertionAfterUserVerification(WTFMove(response), verification, context);
    581584    };
    582     m_connection->verifyUser(requestOptions.rpId, getClientDataType(requestData().options), accessControlRef, WTFMove(callback));
     585    m_connection->verifyUser(requestOptions.rpId, getClientDataType(requestData().options), accessControlRef, getUserVerificationRequirement(requestData().options), WTFMove(callback));
    583586}
    584587
     
    594597    // Step 10.
    595598    auto requestOptions = WTF::get<PublicKeyCredentialRequestOptions>(requestData().options);
    596     auto authData = buildAuthData(requestOptions.rpId, getAssertionFlags, counter, { });
     599    auto authData = buildAuthData(requestOptions.rpId, verification == LocalConnection::UserVerification::Presence ? otherGetAssertionFlags : getAssertionFlags, counter, { });
    597600
    598601    // Step 11.
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.h

    r270694 r276180  
    3939class AuthenticatorAssertionResponse;
    4040enum class ClientDataType : bool;
     41enum class UserVerificationRequirement;
    4142}
    4243
     
    5556        No,
    5657        Yes,
    57         Cancel
     58        Cancel,
     59        Presence
    5860    };
    5961
     
    6567
    6668    // Overrided by MockLocalConnection.
    67     virtual void verifyUser(const String& rpId, WebCore::ClientDataType, SecAccessControlRef, UserVerificationCallback&&);
     69    virtual void verifyUser(const String& rpId, WebCore::ClientDataType, SecAccessControlRef, WebCore::UserVerificationRequirement, UserVerificationCallback&&);
    6870    virtual void verifyUser(SecAccessControlRef, LAContext *, CompletionHandler<void(UserVerification)>&&);
    6971    virtual RetainPtr<SecKeyRef> createCredentialPrivateKey(LAContext *, SecAccessControlRef, const String& secAttrLabel, NSData *secAttrApplicationTag) const;
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.mm

    r275966 r276180  
    3030
    3131#import <WebCore/LocalizedStrings.h>
     32#import <WebCore/UserVerificationRequirement.h>
    3233#import <WebCore/WebAuthenticationConstants.h>
    3334#import <wtf/BlockPtr.h>
     
    6162}
    6263
    63 void LocalConnection::verifyUser(const String& rpId, ClientDataType type, SecAccessControlRef accessControl, UserVerificationCallback&& completionHandler)
     64void LocalConnection::verifyUser(const String& rpId, ClientDataType type, SecAccessControlRef accessControl, UserVerificationRequirement uv, UserVerificationCallback&& completionHandler)
    6465{
    6566    String title = genericTouchIDPromptTitle();
     
    8586    }
    8687
    87     auto reply = makeBlockPtr([context = m_context, completionHandler = WTFMove(completionHandler)] (NSDictionary *, NSError *error) mutable {
     88    auto reply = makeBlockPtr([context = m_context, completionHandler = WTFMove(completionHandler)] (NSDictionary *information, NSError *error) mutable {
    8889        UserVerification verification = UserVerification::Yes;
    8990        if (error) {
     
    9394                verification = UserVerification::Cancel;
    9495        }
     96        if (information[@"UserPresence"])
     97            verification = UserVerification::Presence;
    9598
    9699        // This block can be executed in another thread.
     
    102105#if USE(APPLE_INTERNAL_SDK)
    103106    // Depending on certain internal requirements, accessControl might not require user verifications.
    104     // Hence, here introduces a quirk to force the compatible mode to always require user verifications.
     107    // Hence, here introduces a quirk to force the compatible mode to require user verifications if necessary.
    105108    if (shouldUseAlternateAttributes()) {
    106         [m_context evaluatePolicy:LAPolicyDeviceOwnerAuthentication options:options.get() reply:reply.get()];
     109        if (uv == UserVerificationRequirement::Required || [m_context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil]) {
     110            [m_context evaluatePolicy:LAPolicyDeviceOwnerAuthentication options:options.get() reply:reply.get()];
     111            return;
     112        }
     113
     114        reply(@{ @"UserPresence": @YES }, nullptr);
    107115        return;
    108116    }
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalService.mm

    r275492 r276180  
    3535#import "LocalAuthenticationSoftLink.h"
    3636
     37#if USE(APPLE_INTERNAL_SDK)
     38#import <WebKitAdditions/LocalServiceAdditions.h>
     39#else
     40#define LOCAL_SERVICE_ADDITIONS
     41#endif
     42
    3743namespace WebKit {
    3844
     
    4450bool LocalService::isAvailable()
    4551{
     52LOCAL_SERVICE_ADDITIONS
     53
    4654    auto context = adoptNS([allocLAContextInstance() init]);
    4755    NSError *error = nil;
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h

    r272184 r276180  
    3838
    3939private:
    40     void verifyUser(const String&, WebCore::ClientDataType, SecAccessControlRef, UserVerificationCallback&&) final;
     40    void verifyUser(const String&, WebCore::ClientDataType, SecAccessControlRef, WebCore::UserVerificationRequirement,  UserVerificationCallback&&) final;
    4141    void verifyUser(SecAccessControlRef, LAContext *, CompletionHandler<void(UserVerification)>&&) final;
    4242    RetainPtr<SecKeyRef> createCredentialPrivateKey(LAContext *, SecAccessControlRef, const String& secAttrLabel, NSData *secAttrApplicationTag) const final;
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm

    r272184 r276180  
    4747}
    4848
    49 void MockLocalConnection::verifyUser(const String&, ClientDataType, SecAccessControlRef, UserVerificationCallback&& callback)
     49void MockLocalConnection::verifyUser(const String&, ClientDataType, SecAccessControlRef, WebCore::UserVerificationRequirement, UserVerificationCallback&& callback)
    5050{
    5151    // Mock async operations.
     
    6262        case MockWebAuthenticationConfiguration::UserVerification::Cancel:
    6363            userVerification = UserVerification::Cancel;
     64            break;
     65        case MockWebAuthenticationConfiguration::UserVerification::Presence:
     66            userVerification = UserVerification::Presence;
     67            break;
    6468        }
    6569
     
    8387        case MockWebAuthenticationConfiguration::UserVerification::Cancel:
    8488            userVerification = UserVerification::Cancel;
     89            break;
     90        case MockWebAuthenticationConfiguration::UserVerification::Presence:
     91            userVerification = UserVerification::Presence;
     92            break;
    8593        }
    8694
  • trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.cpp

    r258961 r276180  
    2929#if ENABLE(WEB_AUTHN)
    3030
     31#import <WebCore/UserVerificationRequirement.h>
     32
    3133namespace WebKit {
    3234using namespace WebCore;
     
    3941}
    4042
     43UserVerificationRequirement getUserVerificationRequirement(const Variant<PublicKeyCredentialCreationOptions, PublicKeyCredentialRequestOptions>& options)
     44{
     45    if (WTF::holds_alternative<PublicKeyCredentialCreationOptions>(options)) {
     46        if (auto authenticatorSelection = WTF::get<PublicKeyCredentialCreationOptions>(options).authenticatorSelection)
     47            return authenticatorSelection->userVerification;
     48        return UserVerificationRequirement::Preferred;
     49    }
     50
     51    return WTF::get<PublicKeyCredentialRequestOptions>(options).userVerification;
     52}
     53
    4154} // namespace WebKit
    4255
  • trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h

    r272184 r276180  
    6060
    6161WebCore::ClientDataType getClientDataType(const Variant<WebCore::PublicKeyCredentialCreationOptions, WebCore::PublicKeyCredentialRequestOptions>&);
     62WebCore::UserVerificationRequirement getUserVerificationRequirement(const Variant<WebCore::PublicKeyCredentialCreationOptions, WebCore::PublicKeyCredentialRequestOptions>&);
    6263
    6364} // namespace WebKit
Note: See TracChangeset for help on using the changeset viewer.