Changeset 239752 in webkit


Ignore:
Timestamp:
Jan 8, 2019 4:35:39 PM (5 years ago)
Author:
jiewen_tan@apple.com
Message:

[WebAuthN] Support U2F HID Authenticators on macOS
https://bugs.webkit.org/show_bug.cgi?id=191535
<rdar://problem/47102027>

Reviewed by Brent Fulgham.

Source/WebCore:

This patch changes U2fCommandConstructor to produce register commands with
enforcing test of user presence. Otherwise, authenticators would silently
generate credentials. It also renames readFromU2fSignResponse to
readU2fSignResponse.

Tests: http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html

http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html
http/wpt/webauthn/public-key-credential-create-success-u2f.https.html
http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html
http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html
http/wpt/webauthn/public-key-credential-get-success-u2f.https.html

  • Modules/webauthn/fido/U2fCommandConstructor.cpp:

(fido::WebCore::constructU2fRegisterCommand):

  • Modules/webauthn/fido/U2fResponseConverter.cpp:

(fido::readU2fSignResponse):
(fido::readFromU2fSignResponse): Deleted.

  • Modules/webauthn/fido/U2fResponseConverter.h:

Source/WebKit:

This patch implements the support for U2F authenticators, and enables it for hid devices.
It follows the CTAP spec to map WebAuthN requests to U2F commands and return the responses:
https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-interoperability
Most of the parts are done before this patch, this patch focues on: 7.2.2 and 7.3.2.

Besides implementing the U2fHidAuthenticator, this patch also adds support in the mocking
environment for U2F authenticators. It is done by extending the stages in MockHidConnection
from 4 to indefinite as multi-round communications are expected to map WebAuthN requests
to U2F requests.

  • Sources.txt:
  • UIProcess/API/C/WKWebsiteDataStoreRef.cpp:

(WKWebsiteDataStoreSetWebAuthenticationMockConfiguration):

  • UIProcess/WebAuthentication/Cocoa/HidService.mm:

(WebKit::HidService::continueAddDeviceAfterGetInfo):

  • UIProcess/WebAuthentication/fido/CtapHidDriver.cpp:

(WebKit::CtapHidDriver::continueAfterChannelAllocated):

  • UIProcess/WebAuthentication/fido/CtapHidDriver.h:

(WebKit::CtapHidDriver::setProtocol):

  • UIProcess/WebAuthentication/fido/U2fHidAuthenticator.cpp: Added.

(WebKit::U2fHidAuthenticator::U2fHidAuthenticator):
(WebKit::U2fHidAuthenticator::makeCredential):
(WebKit::U2fHidAuthenticator::checkExcludeList):
(WebKit::U2fHidAuthenticator::issueRegisterCommand):
(WebKit::U2fHidAuthenticator::getAssertion):
(WebKit::U2fHidAuthenticator::issueSignCommand):
(WebKit::U2fHidAuthenticator::issueNewCommand):
(WebKit::U2fHidAuthenticator::issueCommand):
(WebKit::U2fHidAuthenticator::responseReceived):
(WebKit::U2fHidAuthenticator::continueRegisterCommandAfterResponseReceived):
(WebKit::U2fHidAuthenticator::continueCheckOnlyCommandAfterResponseReceived):
(WebKit::U2fHidAuthenticator::continueBogusCommandAfterResponseReceived):
(WebKit::U2fHidAuthenticator::continueSignCommandAfterResponseReceived):

  • UIProcess/WebAuthentication/fido/U2fHidAuthenticator.h: Added.
  • UIProcess/WebAuthentication/Mock/MockHidConnection.cpp:

(WebKit::MockHidConnection::parseRequest):
(WebKit::MockHidConnection::feedReports):

  • UIProcess/WebAuthentication/Mock/MockHidConnection.h:
  • UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h:
  • WebKit.xcodeproj/project.pbxproj:

Tools:

This patch:
1) adds support for U2F mocking mechanism;
2) updates tests to reflect U2fCommandConstructor changes.

  • TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp:

(TestWebKitAPI::TEST):

  • TestWebKitAPI/Tests/WebCore/FidoTestData.h:
  • WebKitTestRunner/InjectedBundle/TestRunner.cpp:

(WTR::TestRunner::setWebAuthenticationMockConfiguration):

LayoutTests:

Besiding adding tests for U2F authenticators, it also changes payloadBase64 from
a string to a vector of strings. New tests are skipped for iOS.

  • http/wpt/webauthn/ctap-hid-failure.https.html:
  • http/wpt/webauthn/ctap-hid-success.https.html:
  • http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html:
  • http/wpt/webauthn/public-key-credential-create-failure-hid.https.html:
  • http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html: Added.
  • http/wpt/webauthn/public-key-credential-create-failure-u2f.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html: Added.
  • http/wpt/webauthn/public-key-credential-create-success-hid.https.html:
  • http/wpt/webauthn/public-key-credential-create-success-u2f.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-create-success-u2f.https.html: Copied from LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html.
  • http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html:
  • http/wpt/webauthn/public-key-credential-get-failure-hid.https.html:
  • http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html: Added.
  • http/wpt/webauthn/public-key-credential-get-failure-u2f.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html: Added.
  • http/wpt/webauthn/public-key-credential-get-success-hid.https.html:
  • http/wpt/webauthn/public-key-credential-get-success-u2f.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-get-success-u2f.https.html: Added.
  • http/wpt/webauthn/resources/util.js:
  • platform/ios-wk2/TestExpectations:
Location:
trunk
Files:
13 added
29 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r239749 r239752  
     12019-01-08  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Support U2F HID Authenticators on macOS
     4        https://bugs.webkit.org/show_bug.cgi?id=191535
     5        <rdar://problem/47102027>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Besiding adding tests for U2F authenticators, it also changes payloadBase64 from
     10        a string to a vector of strings. New tests are skipped for iOS.
     11
     12        * http/wpt/webauthn/ctap-hid-failure.https.html:
     13        * http/wpt/webauthn/ctap-hid-success.https.html:
     14        * http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html:
     15        * http/wpt/webauthn/public-key-credential-create-failure-hid.https.html:
     16        * http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https-expected.txt: Added.
     17        * http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html: Added.
     18        * http/wpt/webauthn/public-key-credential-create-failure-u2f.https-expected.txt: Added.
     19        * http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html: Added.
     20        * http/wpt/webauthn/public-key-credential-create-success-hid.https.html:
     21        * http/wpt/webauthn/public-key-credential-create-success-u2f.https-expected.txt: Added.
     22        * http/wpt/webauthn/public-key-credential-create-success-u2f.https.html: Copied from LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html.
     23        * http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html:
     24        * http/wpt/webauthn/public-key-credential-get-failure-hid.https.html:
     25        * http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https-expected.txt: Added.
     26        * http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html: Added.
     27        * http/wpt/webauthn/public-key-credential-get-failure-u2f.https-expected.txt: Added.
     28        * http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html: Added.
     29        * http/wpt/webauthn/public-key-credential-get-success-hid.https.html:
     30        * http/wpt/webauthn/public-key-credential-get-success-u2f.https-expected.txt: Added.
     31        * http/wpt/webauthn/public-key-credential-get-success-u2f.https.html: Added.
     32        * http/wpt/webauthn/resources/util.js:
     33        * platform/ios-wk2/TestExpectations:
     34
    1352019-01-08  Youenn Fablet  <youenn@apple.com>
    236
  • trunk/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html

    r238246 r239752  
    6565    promise_test(function(t) {
    6666        if (window.testRunner)
    67             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "wrong-channel-id", payloadBase64:testDummyMessagePayloadBase64 } });
     67            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "wrong-channel-id", payloadBase64:[testDummyMessagePayloadBase64] } });
    6868        return promiseRejects(t, "UnknownError", navigator.credentials.create(defaultOptions), "Unknown internal error. Error code: -1");
    6969    }, "CTAP HID with request::msg stage wrong channel id error in a mock hid authenticator.");
  • trunk/LayoutTests/http/wpt/webauthn/ctap-hid-success.https.html

    r238246 r239752  
    2222    promise_test(function(t) {
    2323        if (window.testRunner)
    24             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testCreationMessageBase64, keepAlive: true } });
     24            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64], keepAlive: true } });
    2525        return navigator.credentials.create(defaultOptions).then(credential => {
    2626            assert_not_equals(credential, undefined);
     
    3131    promise_test(function(t) {
    3232        if (window.testRunner)
    33             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testCreationMessageBase64, fastDataArrival: true } });
     33            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64], fastDataArrival: true } });
    3434        return navigator.credentials.create(defaultOptions).then(credential => {
    3535            assert_not_equals(credential, undefined);
     
    4040    promise_test(function(t) {
    4141        if (window.testRunner)
    42             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "empty-report", payloadBase64: testCreationMessageBase64, continueAfterErrorData: true } });
     42            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "empty-report", payloadBase64: [testCreationMessageBase64], continueAfterErrorData: true } });
    4343        return navigator.credentials.create(defaultOptions).then(credential => {
    4444            assert_not_equals(credential, undefined);
     
    4949    promise_test(function(t) {
    5050        if (window.testRunner)
    51             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-channel-id", payloadBase64: testCreationMessageBase64, continueAfterErrorData: true } });
     51            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-channel-id", payloadBase64: [testCreationMessageBase64], continueAfterErrorData: true } });
    5252        return navigator.credentials.create(defaultOptions).then(credential => {
    5353            assert_not_equals(credential, undefined);
     
    5858    promise_test(function(t) {
    5959        if (window.testRunner)
    60             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-nonce", payloadBase64: testCreationMessageBase64, continueAfterErrorData: true } });
     60            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-nonce", payloadBase64: [testCreationMessageBase64], continueAfterErrorData: true } });
    6161        return navigator.credentials.create(defaultOptions).then(credential => {
    6262            assert_not_equals(credential, undefined);
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html

    r238166 r239752  
    2323
    2424        if (window.testRunner)
    25             testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
     25            testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
    2626        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
    2727    }, "PublicKeyCredential's [[create]] with malicious payload in a mock hid authenticator.");
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html

    r238166 r239752  
    4747
    4848        if (window.testRunner)
    49             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
     49            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
    5050        return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error. Error code: -1");
    5151    }, "PublicKeyCredential's [[create]] with malicious payload in a mock hid authenticator.");
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html

    r239665 r239752  
    88    // Default mock configuration. Tests need to override if they need different configuration.
    99    if (window.testRunner)
    10         testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testCreationMessageBase64 } });
     10        testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64] } });
    1111
    1212    function checkResult(credential)
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-u2f.https.html

    r239750 r239752  
    11<!DOCTYPE html>
    2 <title>Web Authentication API: PublicKeyCredential's [[create]] success cases with a mock hid authenticator.</title>
     2<title>Web Authentication API: PublicKeyCredential's [[create]] success cases with a mock u2f authenticator.</title>
    33<script src="/resources/testharness.js"></script>
    44<script src="/resources/testharnessreport.js"></script>
     
    66<script src="./resources/cbor.js"></script>
    77<script>
    8     // Default mock configuration. Tests need to override if they need different configuration.
    9     if (window.testRunner)
    10         testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testCreationMessageBase64 } });
    11 
    128    function checkResult(credential)
    139    {
    1410        // Check response
    15         assert_array_equals(Base64URL.parse(credential.id), Base64URL.parse(testHidCredentialIdBase64));
     11        assert_array_equals(Base64URL.parse(credential.id), Base64URL.parse(testU2fCredentialIdBase64));
    1612        assert_equals(credential.type, 'public-key');
    17         assert_array_equals(new Uint8Array(credential.rawId), Base64URL.parse(testHidCredentialIdBase64));
     13        assert_array_equals(new Uint8Array(credential.rawId), Base64URL.parse(testU2fCredentialIdBase64));
    1814        assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.create","challenge":"MTIzNDU2","origin":"https://localhost:9443"}');
    1915        assert_throws("NotSupportedError", () => { credential.getClientExtensionResults() });
     
    2117        // Check attestation
    2218        const attestationObject = CBOR.decode(credential.response.attestationObject);
    23         assert_equals(attestationObject.fmt, "packed");
     19        assert_equals(attestationObject.fmt, "fido-u2f");
    2420        // Check authData
    2521        const authData = decodeAuthData(attestationObject.authData);
    26         assert_equals(bytesToHexString(authData.rpIdHash), "46cc7fb9679d55b2db9092e1c8d9e5e1d02b7580f0b4812c770962e1e48f5ad8");
     22        assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763");
    2723        assert_equals(authData.flags, 65);
    28         assert_equals(authData.counter, 78);
    29         assert_equals(bytesToHexString(authData.aaguid), "f8a011f38c0a4d15800617111f9edc7d");
    30         assert_array_equals(authData.credentialID, Base64URL.parse(testHidCredentialIdBase64));
    31         // Check packed attestation
    32         assert_equals(attestationObject.attStmt.alg, -7);
     24        assert_equals(authData.counter, 0);
     25        assert_equals(bytesToHexString(authData.aaguid), "00000000000000000000000000000000");
     26        assert_array_equals(authData.credentialID, Base64URL.parse(testU2fCredentialIdBase64));
     27        // Check fido-u2f attestation
    3328        assert_true(checkPublicKey(authData.publicKey));
    3429        assert_equals(attestationObject.attStmt.x5c.length, 1);
     
    5247        };
    5348
     49        if (window.testRunner)
     50            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fRegisterResponse] } });
    5451        return navigator.credentials.create(options).then(credential => {
    5552            checkResult(credential);
    5653        });
    57     }, "PublicKeyCredential's [[create]] with minimum options in a mock local authenticator.");
     54    }, "PublicKeyCredential's [[create]] with minimum options in a mock u2f authenticator.");
    5855
    5956    promise_test(t => {
     
    7067                challenge: Base64URL.parse("MTIzNDU2"),
    7168                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    72                 authenticatorSelection: { authenticatorAttachment: "cross-platform" },
     69                excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
    7370                timeout: 10
    7471            }
    7572        };
    7673
     74        if (window.testRunner)
     75            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fRegisterResponse] } });
    7776        return navigator.credentials.create(options).then(credential => {
    7877            checkResult(credential);
    7978        });
    80     }, "PublicKeyCredential's [[create]] with authenticatorSelection { 'cross-platform' } in a mock local authenticator.");
     79    }, "PublicKeyCredential's [[create]] with excludeCredentials in a mock u2f authenticator.");
    8180
    8281    promise_test(t => {
     
    9392                challenge: Base64URL.parse("MTIzNDU2"),
    9493                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    95                 authenticatorSelection: { requireResidentKey: false },
     94                excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }, { type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }], // The content doesn't matter.
    9695                timeout: 10
    9796            }
    9897        };
    9998
     99        if (window.testRunner)
     100            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fApduWrongDataOnlyResponseBase64, testU2fRegisterResponse] } });
    100101        return navigator.credentials.create(options).then(credential => {
    101102            checkResult(credential);
    102103        });
    103     }, "PublicKeyCredential's [[create]] with requireResidentKey { false } in a mock local authenticator.");
     104    }, "PublicKeyCredential's [[create]] with excludeCredentials in a mock u2f authenticator. 2");
    104105
    105106    promise_test(t => {
     
    116117                challenge: Base64URL.parse("MTIzNDU2"),
    117118                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    118                 authenticatorSelection: { userVerification: "preferred" },
    119                 timeout: 10
     119                timeout: 500
    120120            }
    121121        };
    122122
     123        if (window.testRunner)
     124            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fRegisterResponse] } });
    123125        return navigator.credentials.create(options).then(credential => {
    124126            checkResult(credential);
    125127        });
    126     }, "PublicKeyCredential's [[create]] with userVerification { 'preferred' } in a mock local authenticator.");
    127 
    128     promise_test(t => {
    129         const options = {
    130             publicKey: {
    131                 rp: {
    132                     name: "localhost",
    133                 },
    134                 user: {
    135                     name: "John Appleseed",
    136                     id: Base64URL.parse(testUserhandleBase64),
    137                     displayName: "Appleseed",
    138                 },
    139                 challenge: Base64URL.parse("MTIzNDU2"),
    140                 pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    141                 authenticatorSelection: { userVerification: "discouraged" },
    142                 timeout: 10
    143             }
    144         };
    145 
    146         return navigator.credentials.create(options).then(credential => {
    147             checkResult(credential);
    148         });
    149     }, "PublicKeyCredential's [[create]] with userVerification { 'discouraged' } in a mock local authenticator.");
    150 
    151     promise_test(t => {
    152         const options = {
    153             publicKey: {
    154                 rp: {
    155                     name: "localhost",
    156                 },
    157                 user: {
    158                     name: "John Appleseed",
    159                     id: Base64URL.parse(testUserhandleBase64),
    160                     displayName: "Appleseed",
    161                 },
    162                 challenge: Base64URL.parse("MTIzNDU2"),
    163                 pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    164                 authenticatorSelection: { authenticatorAttachment: "cross-platform", requireResidentKey: false, userVerification: "preferred" },
    165                 timeout: 10
    166             }
    167         };
    168 
    169         return navigator.credentials.create(options).then(credential => {
    170             checkResult(credential);
    171         });
    172     }, "PublicKeyCredential's [[create]] with mixed options in a mock local authenticator.");
     128    }, "PublicKeyCredential's [[create]] with test of user presence in a mock u2f authenticator.");
    173129</script>
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html

    r238166 r239752  
    1414
    1515        if (window.testRunner)
    16             testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
     16            testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
    1717        return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.");
    1818    }, "PublicKeyCredential's [[get]] with malicious payload in a mock hid authenticator.");
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html

    r238166 r239752  
    3333
    3434        if (window.testRunner)
    35             testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
     35            testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
    3636        return promiseRejects(t, "UnknownError", navigator.credentials.get(options), "Unknown internal error. Error code: -1");
    3737    }, "PublicKeyCredential's [[get]] with malicious payload in a mock hid authenticator.");
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html

    r239665 r239752  
    77    // Default mock configuration. Tests need to override if they need different configuration.
    88    if (window.testRunner)
    9         testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testAssertionMessageBase64 } });
     9        testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testAssertionMessageBase64] } });
    1010
    1111    function checkResult(credential)
  • trunk/LayoutTests/http/wpt/webauthn/resources/util.js

    r239665 r239752  
    7070    "4/F0VB7DlUVM09IHPmxe1MzHUwRoCRZbCAIgGKov6xoAx2MEf6/6qNs8OutzhP2C" +
    7171    "QoJ1L7Fe64G9uBc=";
     72const testU2fApduNoErrorOnlyResponseBase64 = "kAA=";
     73const testU2fApduInsNotSupportedOnlyResponseBase64 = "bQA=";
     74const testU2fApduWrongDataOnlyResponseBase64 = "aoA=";
     75const testU2fApduConditionsNotSatisfiedOnlyResponseBase64 = "aYU=";
     76const testU2fRegisterResponse =
     77    "BQTodiWJbuTkbcAydm6Ah5YvNt+d/otWfzdjAVsZkKYOFCfeYS1mQYvaGVBYHrxc" +
     78    "jB2tcQyxTCL4yXBF9GEvsgyRQD69ib937FCXVe6cJjXvqqx7K5xc7xc2w3F9pIU0" +
     79    "yMa2VNf/lF9QtcxOeAVb3TlrZPeNosX5YgDM1BXNCP5CADgwggJKMIIBMqADAgEC" +
     80    "AgQEbIgiMA0GCSqGSIb3DQEBCwUAMC4xLDAqBgNVBAMTI1l1YmljbyBVMkYgUm9v" +
     81    "dCBDQSBTZXJpYWwgNDU3MjAwNjMxMCAXDTE0MDgwMTAwMDAwMFoYDzIwNTAwOTA0" +
     82    "MDAwMDAwWjAsMSowKAYDVQQDDCFZdWJpY28gVTJGIEVFIFNlcmlhbCAyNDkxODIz" +
     83    "MjQ3NzAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ8yrksy5cofujmOUN+IfzW" +
     84    "tvFlstWj89sTHTHBa3QrtHbY0emQgOtUbJu99VbmIQ/UJ4WJnnjMWJ6+MQ9s25/0" +
     85    "ozswOTAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4xLjQxNDgyLjEuMjATBgsrBgEE" +
     86    "AYLlHAIBAQQEAwIEMDANBgkqhkiG9w0BAQsFAAOCAQEAn5sFIki8TPQsxZkfyqus" +
     87    "m2Ubvlvc3I7wrSwcH/s20YcV1C54skkiT5LH5uegXEnw5+TIgb8ulPReSiGDPXRW" +
     88    "hR0PbBRaKVQMh08wksk0tD0iK4liwPQQzvHbdYkq8Ra0Spb101reo4IvxxRvYAQ4" +
     89    "W8tptlyZ5+tpGXhnA8DYzUHo91zKRKqKtyWtjnmf86hpam8bJlbmMbHkAYPAj9pT" +
     90    "+kqPhaBWk5RK4XmhM50ALRXKvYEAkOxyLvXe+ZZaNx1BXWJLaKJwfK2XvN0Xha+X" +
     91    "4ljzPfVqAxqgNW2OjV68rcdOBxY2xrEQrOXMm5Df6srmQP8bsPH+XbTv96lfBgcz" +
     92    "9TBFAiAyR3nGjzOAKIoRl7YJX3puubGxwSf2auEqmf6FMuwjuQIhAOOVFqxNYe5k" +
     93    "BE1QtBWmpNTYS6bYlctat6GqfQgd40H6kAA=";
     94const testU2fCredentialIdBase64 =
     95    "Pr2Jv3fsUJdV7pwmNe-qrHsrnFzvFzbDcX2khTTIxrZU1_-UX1C1zE54BVvdOWtk" +
     96    "942ixfliAMzUFc0I_kIAOA";
     97const testU2fSignResponse =
     98    "AQAAADswRAIge94KUqwfTIsn4AOjcM1mpMcRjdItVEeDX0W5nGhCP/cCIDxRe0eH" +
     99    "f4V4LeEAhqeD0effTjY553H19q+jWq1Tc4WOkAA=";
    72100
    73101const RESOURCES_DIR = "/WebKit/webauthn/resources/";
  • trunk/LayoutTests/platform/ios-wk2/TestExpectations

    r239749 r239752  
    13261326http/wpt/webauthn/public-key-credential-get-failure-hid.https.html [ Skip ]
    13271327http/wpt/webauthn/public-key-credential-get-success-hid.https.html [ Skip ]
     1328http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html [ Skip ]
     1329http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html [ Skip ]
     1330http/wpt/webauthn/public-key-credential-create-success-u2f.https.html [ Skip ]
     1331http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html [ Skip ]
     1332http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html [ Skip ]
     1333http/wpt/webauthn/public-key-credential-get-success-u2f.https.html [ Skip ]
    13281334
    13291335# FIXME: Unskip these tests once we have the fix for <rdar://problem/44930119>.
  • trunk/Source/WebCore/ChangeLog

    r239750 r239752  
     12019-01-08  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Support U2F HID Authenticators on macOS
     4        https://bugs.webkit.org/show_bug.cgi?id=191535
     5        <rdar://problem/47102027>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        This patch changes U2fCommandConstructor to produce register commands with
     10        enforcing test of user presence. Otherwise, authenticators would silently
     11        generate credentials. It also renames readFromU2fSignResponse to
     12        readU2fSignResponse.
     13
     14        Tests: http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html
     15               http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html
     16               http/wpt/webauthn/public-key-credential-create-success-u2f.https.html
     17               http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html
     18               http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html
     19               http/wpt/webauthn/public-key-credential-get-success-u2f.https.html
     20
     21        * Modules/webauthn/fido/U2fCommandConstructor.cpp:
     22        (fido::WebCore::constructU2fRegisterCommand):
     23        * Modules/webauthn/fido/U2fResponseConverter.cpp:
     24        (fido::readU2fSignResponse):
     25        (fido::readFromU2fSignResponse): Deleted.
     26        * Modules/webauthn/fido/U2fResponseConverter.h:
     27
    1282019-01-08  Wenson Hsieh  <wenson_hsieh@apple.com>
    229
  • trunk/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.cpp

    r239665 r239752  
    5555    apdu::ApduCommand command;
    5656    command.setIns(static_cast<uint8_t>(U2fApduInstruction::kRegister));
     57    // This is needed for test of user presence even though the spec doesn't specify it.
     58    command.setP1(kP1EnforceUserPresenceAndSign);
    5759    command.setData(WTFMove(data));
    5860    command.setResponseLength(apdu::ApduCommand::kApduMaxResponseLength);
  • trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.cpp

    r239665 r239752  
    174174}
    175175
    176 Optional<PublicKeyCredentialData> readFromU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData)
     176Optional<PublicKeyCredentialData> readU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData)
    177177{
    178178    if (keyHandle.isEmpty() || u2fData.size() <= signatureIndex)
  • trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.h

    r239665 r239752  
    4343// Converts a U2F authentication response to WebAuthN getAssertion response.
    4444// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-authenticatorGetAssertion-interoperability
    45 WEBCORE_EXPORT Optional<WebCore::PublicKeyCredentialData> readFromU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData);
     45WEBCORE_EXPORT Optional<WebCore::PublicKeyCredentialData> readU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData);
    4646
    4747} // namespace fido
  • trunk/Source/WebKit/ChangeLog

    r239749 r239752  
     12019-01-08  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Support U2F HID Authenticators on macOS
     4        https://bugs.webkit.org/show_bug.cgi?id=191535
     5        <rdar://problem/47102027>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        This patch implements the support for U2F authenticators, and enables it for hid devices.
     10        It follows the CTAP spec to map WebAuthN requests to U2F commands and return the responses:
     11        https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-interoperability
     12        Most of the parts are done before this patch, this patch focues on: 7.2.2 and 7.3.2.
     13
     14        Besides implementing the U2fHidAuthenticator, this patch also adds support in the mocking
     15        environment for U2F authenticators. It is done by extending the stages in MockHidConnection
     16        from 4 to indefinite as multi-round communications are expected to map WebAuthN requests
     17        to U2F requests.
     18
     19        * Sources.txt:
     20        * UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
     21        (WKWebsiteDataStoreSetWebAuthenticationMockConfiguration):
     22        * UIProcess/WebAuthentication/Cocoa/HidService.mm:
     23        (WebKit::HidService::continueAddDeviceAfterGetInfo):
     24        * UIProcess/WebAuthentication/fido/CtapHidDriver.cpp:
     25        (WebKit::CtapHidDriver::continueAfterChannelAllocated):
     26        * UIProcess/WebAuthentication/fido/CtapHidDriver.h:
     27        (WebKit::CtapHidDriver::setProtocol):
     28        * UIProcess/WebAuthentication/fido/U2fHidAuthenticator.cpp: Added.
     29        (WebKit::U2fHidAuthenticator::U2fHidAuthenticator):
     30        (WebKit::U2fHidAuthenticator::makeCredential):
     31        (WebKit::U2fHidAuthenticator::checkExcludeList):
     32        (WebKit::U2fHidAuthenticator::issueRegisterCommand):
     33        (WebKit::U2fHidAuthenticator::getAssertion):
     34        (WebKit::U2fHidAuthenticator::issueSignCommand):
     35        (WebKit::U2fHidAuthenticator::issueNewCommand):
     36        (WebKit::U2fHidAuthenticator::issueCommand):
     37        (WebKit::U2fHidAuthenticator::responseReceived):
     38        (WebKit::U2fHidAuthenticator::continueRegisterCommandAfterResponseReceived):
     39        (WebKit::U2fHidAuthenticator::continueCheckOnlyCommandAfterResponseReceived):
     40        (WebKit::U2fHidAuthenticator::continueBogusCommandAfterResponseReceived):
     41        (WebKit::U2fHidAuthenticator::continueSignCommandAfterResponseReceived):
     42        * UIProcess/WebAuthentication/fido/U2fHidAuthenticator.h: Added.
     43        * UIProcess/WebAuthentication/Mock/MockHidConnection.cpp:
     44        (WebKit::MockHidConnection::parseRequest):
     45        (WebKit::MockHidConnection::feedReports):
     46        * UIProcess/WebAuthentication/Mock/MockHidConnection.h:
     47        * UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h:
     48        * WebKit.xcodeproj/project.pbxproj:
     49
    1502019-01-08  Youenn Fablet  <youenn@apple.com>
    251
  • trunk/Source/WebKit/Sources.txt

    r239747 r239752  
    386386UIProcess/UserContent/WebUserContentControllerProxy.cpp
    387387
     388UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp
     389UIProcess/WebAuthentication/fido/CtapHidDriver.cpp
     390UIProcess/WebAuthentication/fido/U2fHidAuthenticator.cpp
     391
    388392UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp
    389393UIProcess/WebAuthentication/Mock/MockHidConnection.cpp
  • trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp

    r239747 r239752  
    628628            hid.error = WebKit::MockWebAuthenticationConfiguration::Hid::Error::WrongNonce;
    629629
    630         if (auto payloadBase64 = static_cast<WKStringRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")).get())))
    631             hid.payloadBase64 = WebKit::toImpl(payloadBase64)->string();
     630        if (auto payloadBase64 = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")).get())))
     631            hid.payloadBase64 = WebKit::toImpl(payloadBase64)->toStringVector();
     632
     633        if (auto isU2f = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("IsU2f")).get())))
     634            hid.isU2f = WKBooleanGetValue(isU2f);
    632635
    633636        if (auto keepAlive = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("KeepAlive")).get())))
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/HidService.mm

    r239235 r239752  
    3232#import "CtapHidDriver.h"
    3333#import "HidConnection.h"
     34#import "U2fHidAuthenticator.h"
    3435#import <WebCore/DeviceRequestConverter.h>
    3536#import <WebCore/DeviceResponseConverter.h>
     
    109110{
    110111    std::unique_ptr<CtapHidDriver> driver = m_drivers.take(ptr);
    111     if (!driver || !observer())
     112    if (!driver || !observer() || response.isEmpty())
    112113        return;
    113114
     
    117118        return;
    118119    }
    119     // FIXME(191535): Support U2F authenticators.
    120120    LOG_ERROR("Couldn't parse a ctap get info response.");
     121    driver->setProtocol(ProtocolVersion::kU2f);
     122    observer()->authenticatorAdded(U2fHidAuthenticator::create(WTFMove(driver)));
    121123}
    122124
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp

    r239665 r239752  
    128128            m_stage = Mock::Stage::Request;
    129129    }
    130     if (m_requestMessage->cmd() == FidoHidDeviceCommand::kCbor)
     130    if (m_requestMessage->cmd() == FidoHidDeviceCommand::kCbor || m_requestMessage->cmd() == FidoHidDeviceCommand::kMsg)
    131131        m_subStage = Mock::SubStage::Msg;
    132132
    133     // Set options.
    134133    if (m_stage == Mock::Stage::Request && m_subStage == Mock::SubStage::Msg) {
    135         m_requireResidentKey = false;
    136         m_requireUserVerification = false;
    137 
    138         auto payload = m_requestMessage->getMessagePayload();
    139         ASSERT(payload.size());
    140         auto cmd = static_cast<CtapRequestCommand>(payload[0]);
    141         payload.remove(0);
    142         auto requestMap = CBORReader::read(payload);
    143         ASSERT(requestMap);
    144 
    145         if (cmd == CtapRequestCommand::kAuthenticatorMakeCredential) {
    146             auto it = requestMap->getMap().find(CBORValue(CtapMakeCredentialRequestOptionsKey)); // Find options.
    147             if (it != requestMap->getMap().end()) {
    148                 auto& optionMap = it->second.getMap();
    149 
    150                 auto itr = optionMap.find(CBORValue(kResidentKeyMapKey));
    151                 if (itr != optionMap.end())
    152                     m_requireResidentKey = itr->second.getBool();
    153 
    154                 itr = optionMap.find(CBORValue(kUserVerificationMapKey));
    155                 if (itr != optionMap.end())
    156                     m_requireUserVerification = itr->second.getBool();
     134        // Make sure we issue different msg cmd for CTAP and U2F.
     135        ASSERT(m_configuration.hid->isU2f ^ (m_requestMessage->cmd() != FidoHidDeviceCommand::kMsg));
     136
     137        // Set options.
     138        if (m_requestMessage->cmd() == FidoHidDeviceCommand::kCbor) {
     139            m_requireResidentKey = false;
     140            m_requireUserVerification = false;
     141
     142            auto payload = m_requestMessage->getMessagePayload();
     143            ASSERT(payload.size());
     144            auto cmd = static_cast<CtapRequestCommand>(payload[0]);
     145            payload.remove(0);
     146            auto requestMap = CBORReader::read(payload);
     147            ASSERT(requestMap);
     148
     149            if (cmd == CtapRequestCommand::kAuthenticatorMakeCredential) {
     150                auto it = requestMap->getMap().find(CBORValue(CtapMakeCredentialRequestOptionsKey)); // Find options.
     151                if (it != requestMap->getMap().end()) {
     152                    auto& optionMap = it->second.getMap();
     153
     154                    auto itr = optionMap.find(CBORValue(kResidentKeyMapKey));
     155                    if (itr != optionMap.end())
     156                        m_requireResidentKey = itr->second.getBool();
     157
     158                    itr = optionMap.find(CBORValue(kUserVerificationMapKey));
     159                    if (itr != optionMap.end())
     160                        m_requireUserVerification = itr->second.getBool();
     161                }
    157162            }
    158         }
    159 
    160         if (cmd == CtapRequestCommand::kAuthenticatorGetAssertion) {
    161             auto it = requestMap->getMap().find(CBORValue(CtapGetAssertionRequestOptionsKey)); // Find options.
    162             if (it != requestMap->getMap().end()) {
    163                 auto& optionMap = it->second.getMap();
    164                 auto itr = optionMap.find(CBORValue(kUserVerificationMapKey));
    165                 if (itr != optionMap.end())
    166                     m_requireUserVerification = itr->second.getBool();
     163
     164            if (cmd == CtapRequestCommand::kAuthenticatorGetAssertion) {
     165                auto it = requestMap->getMap().find(CBORValue(CtapGetAssertionRequestOptionsKey)); // Find options.
     166                if (it != requestMap->getMap().end()) {
     167                    auto& optionMap = it->second.getMap();
     168                    auto itr = optionMap.find(CBORValue(kUserVerificationMapKey));
     169                    if (itr != optionMap.end())
     170                        m_requireUserVerification = itr->second.getBool();
     171                }
    167172            }
    168173        }
     
    208213        if (stagesMatch() && m_configuration.hid->error == Mock::Error::WrongChannelId)
    209214            message = FidoHidMessage::create(m_currentChannel - 1, FidoHidDeviceCommand::kCbor, infoData);
    210         else
    211             message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, infoData);
     215        else {
     216            if (!m_configuration.hid->isU2f)
     217                message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, infoData);
     218            else
     219                message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kError, { static_cast<uint8_t>(CtapDeviceResponseCode::kCtap1ErrInvalidCommand) });
     220        }
    212221    }
    213222
     
    224233        else {
    225234            Vector<uint8_t> payload;
    226             auto status = base64Decode(m_configuration.hid->payloadBase64, payload);
     235            ASSERT(!m_configuration.hid->payloadBase64.isEmpty());
     236            auto status = base64Decode(m_configuration.hid->payloadBase64[0], payload);
     237            m_configuration.hid->payloadBase64.remove(0);
    227238            ASSERT_UNUSED(status, status);
    228             message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, payload);
     239            if (!m_configuration.hid->isU2f)
     240                message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, payload);
     241            else
     242                message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kMsg, payload);
    229243        }
    230244    }
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.h

    r239427 r239752  
    3636
    3737// The following basically simulates an external HID token that:
    38 //    1. Only supports CTAP2 protocol,
     38//    1. Supports only one protocol, either CTAP2 or U2F.
    3939//    2. Doesn't support resident keys,
    4040//    3. Doesn't support user verification.
    41 // There are four stages for each WebAuthN request:
     41// There are four stages for each CTAP request:
    4242// FSM: Info::Init => Info::Msg => Request::Init => Request::Msg
     43// There are indefinite stages for each U2F request:
     44// FSM: Info::Init => Info::Msg => [Request::Init => Request::Msg]+
    4345// According to different combinations of error and stages, error will manifest differently.
    4446class MockHidConnection final : public CanMakeWeakPtr<MockHidConnection>, public HidConnection {
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h

    r239427 r239752  
    6262        };
    6363
    64         String payloadBase64;
     64        Vector<String> payloadBase64;
    6565        Stage stage { Stage::Info };
    6666        SubStage subStage { SubStage::Init };
    6767        Error error { Error::Success };
     68        bool isU2f { false };
    6869        bool keepAlive { false };
    6970        bool fastDataArrival { false };
  • trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.cpp

    r239427 r239752  
    198198    // FIXME(192061)
    199199    LOG_ERROR("Start sending the request.");
    200     auto cmd = FidoHidMessage::create(m_channelId, FidoHidDeviceCommand::kCbor, m_requestData);
     200    auto cmd = FidoHidMessage::create(m_channelId, m_protocol == ProtocolVersion::kCtap ? FidoHidDeviceCommand::kCbor : FidoHidDeviceCommand::kMsg, m_requestData);
    201201    ASSERT(cmd);
    202202    m_worker->transact(WTFMove(*cmd), [weakThis = makeWeakPtr(*this)](Optional<FidoHidMessage>&& response) mutable {
  • trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.h

    r239427 r239752  
    5858    explicit CtapHidDriver(UniqueRef<HidConnection>&&);
    5959
     60    void setProtocol(fido::ProtocolVersion protocol) { m_protocol = protocol; }
    6061    void transact(Vector<uint8_t>&& data, ResponseCallback&&);
    6162
     
    104105    ResponseCallback m_responseCallback;
    105106    Vector<uint8_t> m_nonce;
     107    fido::ProtocolVersion m_protocol { fido::ProtocolVersion::kCtap };
    106108};
    107109
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r239747 r239752  
    10141014                57597EB921811D9A0037F924 /* CtapHidDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 57597EB721811D9A0037F924 /* CtapHidDriver.h */; };
    10151015                57597EBD218184900037F924 /* CtapHidAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57597EBB2181848F0037F924 /* CtapHidAuthenticator.h */; };
    1016                 57597EBE218184900037F924 /* CtapHidAuthenticator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57597EBC2181848F0037F924 /* CtapHidAuthenticator.cpp */; };
    1017                 57597EC121818BE20037F924 /* CtapHidDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57597EC021818BE20037F924 /* CtapHidDriver.cpp */; };
    10181016                5772F206217DBD6A0056BF2C /* HidService.h in Headers */ = {isa = PBXBuildFile; fileRef = 5772F204217DBD6A0056BF2C /* HidService.h */; };
    10191017                578DC2982155A0020074E815 /* LocalAuthenticationSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 578DC2972155A0010074E815 /* LocalAuthenticationSoftLink.h */; };
     
    10371035                57DCEDC7214F18300016B847 /* MockLocalConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC5214F18300016B847 /* MockLocalConnection.h */; };
    10381036                57DCEDCB214F4E420016B847 /* MockAuthenticatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC9214F4E420016B847 /* MockAuthenticatorManager.h */; };
     1037                57EB2E3A21E1983E00B89CDF /* U2fHidAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57EB2E3821E1983E00B89CDF /* U2fHidAuthenticator.h */; };
    10391038                587743A621C30BBE00AE9084 /* HTTPSUpgradeList.db in Resources */ = {isa = PBXBuildFile; fileRef = 587743A421C30AD800AE9084 /* HTTPSUpgradeList.db */; };
    10401039                58E977DF21C49A00005D92A6 /* NetworkHTTPSUpgradeChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 58E977DD21C49A00005D92A6 /* NetworkHTTPSUpgradeChecker.h */; };
     
    34053404                57DCEDC9214F4E420016B847 /* MockAuthenticatorManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockAuthenticatorManager.h; sourceTree = "<group>"; };
    34063405                57DCEDCD214F51680016B847 /* MockAuthenticatorManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockAuthenticatorManager.cpp; sourceTree = "<group>"; };
     3406                57EB2E3821E1983E00B89CDF /* U2fHidAuthenticator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = U2fHidAuthenticator.h; sourceTree = "<group>"; };
     3407                57EB2E3921E1983E00B89CDF /* U2fHidAuthenticator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = U2fHidAuthenticator.cpp; sourceTree = "<group>"; };
    34073408                587743A421C30AD800AE9084 /* HTTPSUpgradeList.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = HTTPSUpgradeList.db; path = DerivedSources/WebKit2/HTTPSUpgradeList.db; sourceTree = BUILT_PRODUCTS_DIR; };
    34083409                58E977DC21C499FE005D92A6 /* NetworkHTTPSUpgradeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkHTTPSUpgradeChecker.cpp; sourceTree = "<group>"; };
     
    67156716                                57597EC021818BE20037F924 /* CtapHidDriver.cpp */,
    67166717                                57597EB721811D9A0037F924 /* CtapHidDriver.h */,
     6718                                57EB2E3921E1983E00B89CDF /* U2fHidAuthenticator.cpp */,
     6719                                57EB2E3821E1983E00B89CDF /* U2fHidAuthenticator.h */,
    67176720                        );
    67186721                        path = fido;
     
    93249327                                1AF05D8714688348008B1E81 /* TiledCoreAnimationDrawingAreaProxy.h in Headers */,
    93259328                                2F8336861FA139DF00C6E080 /* TouchBarMenuData.h in Headers */,
     9329                                57EB2E3A21E1983E00B89CDF /* U2fHidAuthenticator.h in Headers */,
    93269330                                1AFE436618B6C081009C7A48 /* UIDelegate.h in Headers */,
    93279331                                515BE1B51D5917FF00DD7C68 /* UIGamepad.h in Headers */,
     
    1075510759                                51FAEC3B1B0657680009C4E7 /* ChildProcessMessageReceiver.cpp in Sources */,
    1075610760                                2D92A77D212B6A7100F493FD /* Connection.cpp in Sources */,
    10757                                 57597EBE218184900037F924 /* CtapHidAuthenticator.cpp in Sources */,
    10758                                 57597EC121818BE20037F924 /* CtapHidDriver.cpp in Sources */,
    1075910761                                2D92A77E212B6A7100F493FD /* DataReference.cpp in Sources */,
    1076010762                                2D92A77F212B6A7100F493FD /* Decoder.cpp in Sources */,
  • trunk/Tools/ChangeLog

    r239750 r239752  
     12019-01-08  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Support U2F HID Authenticators on macOS
     4        https://bugs.webkit.org/show_bug.cgi?id=191535
     5        <rdar://problem/47102027>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        This patch:
     10        1) adds support for U2F mocking mechanism;
     11        2) updates tests to reflect U2fCommandConstructor changes.
     12
     13        * TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp:
     14        (TestWebKitAPI::TEST):
     15        * TestWebKitAPI/Tests/WebCore/FidoTestData.h:
     16        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
     17        (WTR::TestRunner::setWebAuthenticationMockConfiguration):
     18
    1192019-01-08  Wenson Hsieh  <wenson_hsieh@apple.com>
    220
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp

    r239665 r239752  
    521521TEST(CTAPResponseTest, TestParseSignResponseData)
    522522{
    523     auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestSignResponse());
     523    auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestSignResponse());
    524524    ASSERT_TRUE(response);
    525525    EXPECT_EQ(response->rawId->byteLength(), sizeof(TestData::kU2fSignKeyHandle));
     
    534534TEST(CTAPResponseTest, TestParseU2fSignWithNullKeyHandle)
    535535{
    536     auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, Vector<uint8_t>(), getTestSignResponse());
     536    auto response = readU2fSignResponse(TestData::kRelyingPartyId, Vector<uint8_t>(), getTestSignResponse());
    537537    EXPECT_FALSE(response);
    538538}
     
    540540TEST(CTAPResponseTest, TestParseU2fSignWithNullResponse)
    541541{
    542     auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), Vector<uint8_t>());
     542    auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), Vector<uint8_t>());
    543543    EXPECT_FALSE(response);
    544544}
     
    547547{
    548548    // A sign response of less than 5 bytes.
    549     auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(3));
     549    auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(3));
    550550    EXPECT_FALSE(response);
    551551}
     
    554554{
    555555    // A sign response no more than 5 bytes.
    556     auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(5));
     556    auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(5));
    557557    EXPECT_FALSE(response);
    558558}
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h

    r239665 r239752  
    5252constexpr uint8_t kU2fRegisterCommandApdu[] = {
    5353    // CLA, INS, P1, P2 APDU instructions
    54     0x00, 0x01, 0x00, 0x00,
     54    0x00, 0x01, 0x03, 0x00,
    5555    // Data length in 3 bytes in big endian order.
    5656    0x00, 0x00, 0x40,
     
    142142constexpr uint8_t kU2fFakeRegisterCommand[] = {
    143143    // CLA, INS, P1, P2 APDU instructions
    144     0x00, 0x01, 0x00, 0x00,
     144    0x00, 0x01, 0x03, 0x00,
    145145    // Data length in 3 bytes in big endian order.
    146146    0x00, 0x00, 0x40,
  • trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp

    r239427 r239752  
    25102510        JSValueRef payloadBase64Value = JSObjectGetProperty(context, hid, payloadBase64PropertyName.get(), 0);
    25112511        if (!JSValueIsUndefined(context, payloadBase64Value) && !JSValueIsNull(context, payloadBase64Value)) {
    2512             if (!JSValueIsString(context, payloadBase64Value))
     2512            if (!JSValueIsArray(context, payloadBase64Value))
    25132513                return;
     2514
     2515            JSObjectRef payloadBase64 = JSValueToObject(context, payloadBase64Value, nullptr);
     2516            static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
     2517            JSValueRef payloadBase64LengthValue = JSObjectGetProperty(context, payloadBase64, lengthProperty.get(), nullptr);
     2518            if (!JSValueIsNumber(context, payloadBase64LengthValue))
     2519                return;
     2520
     2521            auto payloadBase64s = adoptWK(WKMutableArrayCreate());
     2522            auto payloadBase64Length = static_cast<size_t>(JSValueToNumber(context, payloadBase64LengthValue, nullptr));
     2523            for (size_t i = 0; i < payloadBase64Length; ++i) {
     2524                JSValueRef payloadBase64Value = JSObjectGetPropertyAtIndex(context, payloadBase64, i, nullptr);
     2525                if (!JSValueIsString(context, payloadBase64Value))
     2526                    continue;
     2527                WKArrayAppendItem(payloadBase64s.get(), toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()).get());
     2528            }
     2529
    25142530            hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("PayloadBase64") });
    2515             hidValues.append(toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()));
     2531            hidValues.append(payloadBase64s);
     2532        }
     2533
     2534        JSRetainPtr<JSStringRef> isU2fPropertyName(Adopt, JSStringCreateWithUTF8CString("isU2f"));
     2535        JSValueRef isU2fValue = JSObjectGetProperty(context, hid, isU2fPropertyName.get(), 0);
     2536        if (!JSValueIsUndefined(context, isU2fValue) && !JSValueIsNull(context, isU2fValue)) {
     2537            if (!JSValueIsBoolean(context, isU2fValue))
     2538                return;
     2539            bool isU2f = JSValueToBoolean(context, isU2fValue);
     2540            hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("IsU2f") });
     2541            hidValues.append(adoptWK(WKBooleanCreate(isU2f)).get());
    25162542        }
    25172543
Note: See TracChangeset for help on using the changeset viewer.