Diff
Modified: trunk/LayoutTests/ChangeLog (239751 => 239752)
--- trunk/LayoutTests/ChangeLog 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/ChangeLog 2019-01-09 00:35:39 UTC (rev 239752)
@@ -1,3 +1,37 @@
+2019-01-08 Jiewen Tan <jiewen_...@apple.com>
+
+ [WebAuthN] Support U2F HID Authenticators on macOS
+ https://bugs.webkit.org/show_bug.cgi?id=191535
+ <rdar://problem/47102027>
+
+ Reviewed by Brent Fulgham.
+
+ 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:
+
2019-01-08 Youenn Fablet <you...@apple.com>
service worker fetch handler results in bad referrer
Modified: trunk/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -64,7 +64,7 @@
promise_test(function(t) {
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "wrong-channel-id", payloadBase64:testDummyMessagePayloadBase64 } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "wrong-channel-id", payloadBase64:[testDummyMessagePayloadBase64] } });
return promiseRejects(t, "UnknownError", navigator.credentials.create(defaultOptions), "Unknown internal error. Error code: -1");
}, "CTAP HID with request::msg stage wrong channel id error in a mock hid authenticator.");
</script>
Modified: trunk/LayoutTests/http/wpt/webauthn/ctap-hid-success.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/ctap-hid-success.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/ctap-hid-success.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -21,7 +21,7 @@
promise_test(function(t) {
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testCreationMessageBase64, keepAlive: true } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64], keepAlive: true } });
return navigator.credentials.create(defaultOptions).then(credential => {
assert_not_equals(credential, undefined);
assert_not_equals(credential, null);
@@ -30,7 +30,7 @@
promise_test(function(t) {
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testCreationMessageBase64, fastDataArrival: true } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64], fastDataArrival: true } });
return navigator.credentials.create(defaultOptions).then(credential => {
assert_not_equals(credential, undefined);
assert_not_equals(credential, null);
@@ -39,7 +39,7 @@
promise_test(function(t) {
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "empty-report", payloadBase64: testCreationMessageBase64, continueAfterErrorData: true } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "empty-report", payloadBase64: [testCreationMessageBase64], continueAfterErrorData: true } });
return navigator.credentials.create(defaultOptions).then(credential => {
assert_not_equals(credential, undefined);
assert_not_equals(credential, null);
@@ -48,7 +48,7 @@
promise_test(function(t) {
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-channel-id", payloadBase64: testCreationMessageBase64, continueAfterErrorData: true } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-channel-id", payloadBase64: [testCreationMessageBase64], continueAfterErrorData: true } });
return navigator.credentials.create(defaultOptions).then(credential => {
assert_not_equals(credential, undefined);
assert_not_equals(credential, null);
@@ -57,7 +57,7 @@
promise_test(function(t) {
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-nonce", payloadBase64: testCreationMessageBase64, continueAfterErrorData: true } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "info", subStage: "init", error: "wrong-nonce", payloadBase64: [testCreationMessageBase64], continueAfterErrorData: true } });
return navigator.credentials.create(defaultOptions).then(credential => {
assert_not_equals(credential, undefined);
assert_not_equals(credential, null);
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -22,7 +22,7 @@
};
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
}, "PublicKeyCredential's [[create]] with malicious payload in a mock hid authenticator.");
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -46,7 +46,7 @@
};
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error. Error code: -1");
}, "PublicKeyCredential's [[create]] with malicious payload in a mock hid authenticator.");
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https-expected.txt (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https-expected.txt 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,9 @@
+
+PASS PublicKeyCredential's [[create]] with malformed APDU payload in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with malformed U2F register response in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with register command error in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with bogus command error in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with second exclude credential matched in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator. Test of user presence.
+
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,165 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[create]] failure cases with a mock u2f authenticator.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: ["AQ=="] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[create]] with malformed APDU payload in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[create]] with malformed U2F register response in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduInsNotSupportedOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[create]] with register command error in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64, testU2fApduInsNotSupportedOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[create]] with bogus command error in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator.");
+
+ // Match the second exclude credential.
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }, { type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }], // The content doesn't matter.
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[create]] with second exclude credential matched in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator. Test of user presence.");
+</script>
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f.https-expected.txt (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f.https-expected.txt 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,9 @@
+
+PASS PublicKeyCredential's [[create]] with malformed APDU payload in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with malformed U2F register response in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with register command error in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with bogus command error in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with second exclude credential matched in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator. Test of user presence.
+
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,158 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[create]] failure cases with a mock u2f authenticator.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: ["AQ=="] } });
+ return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Couldn't parse the APDU response.");
+ }, "PublicKeyCredential's [[create]] with malformed APDU payload in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Couldn't parse the U2F register response.");
+ }, "PublicKeyCredential's [[create]] with malformed U2F register response in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduInsNotSupportedOnlyResponseBase64] } });
+ return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error. Error code: 27904");
+ }, "PublicKeyCredential's [[create]] with register command error in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64, testU2fApduInsNotSupportedOnlyResponseBase64] } });
+ return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error. Error code: 27904");
+ }, "PublicKeyCredential's [[create]] with bogus command error in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "InvalidStateError", navigator.credentials.create(options), "At least one credential matches an entry of the excludeCredentials list in the authenticator.");
+ }, "PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator.");
+
+ // Match the second exclude credential.
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }, { type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }] // The content doesn't matter.
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "InvalidStateError", navigator.credentials.create(options), "At least one credential matches an entry of the excludeCredentials list in the authenticator.");
+ }, "PublicKeyCredential's [[create]] with second exclude credential matched in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "example.com"
+ },
+ user: {
+ name: "John Appleseed",
+ id: asciiToUint8Array("123456"),
+ displayName: "John",
+ },
+ challenge: asciiToUint8Array("123456"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "InvalidStateError", navigator.credentials.create(options), "At least one credential matches an entry of the excludeCredentials list in the authenticator.");
+ }, "PublicKeyCredential's [[create]] with first exclude credential matched in a mock hid authenticator. Test of user presence.");
+</script>
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -7,7 +7,7 @@
<script>
// Default mock configuration. Tests need to override if they need different configuration.
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testCreationMessageBase64 } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64] } });
function checkResult(credential)
{
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-u2f.https-expected.txt (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-u2f.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-u2f.https-expected.txt 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,6 @@
+
+PASS PublicKeyCredential's [[create]] with minimum options in a mock u2f authenticator.
+PASS PublicKeyCredential's [[create]] with excludeCredentials in a mock u2f authenticator.
+PASS PublicKeyCredential's [[create]] with excludeCredentials in a mock u2f authenticator. 2
+PASS PublicKeyCredential's [[create]] with test of user presence in a mock u2f authenticator.
+
Copied: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-u2f.https.html (from rev 239750, trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html) (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-u2f.https.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-u2f.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[create]] success cases with a mock u2f authenticator.</title>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script>
+ function checkResult(credential)
+ {
+ // Check response
+ assert_array_equals(Base64URL.parse(credential.id), Base64URL.parse(testU2fCredentialIdBase64));
+ assert_equals(credential.type, 'public-key');
+ assert_array_equals(new Uint8Array(credential.rawId), Base64URL.parse(testU2fCredentialIdBase64));
+ assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.create","challenge":"MTIzNDU2","origin":"https://localhost:9443"}');
+ assert_throws("NotSupportedError", () => { credential.getClientExtensionResults() });
+
+ // Check attestation
+ const attestationObject = CBOR.decode(credential.response.attestationObject);
+ assert_equals(attestationObject.fmt, "fido-u2f");
+ // Check authData
+ const authData = decodeAuthData(attestationObject.authData);
+ assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763");
+ assert_equals(authData.flags, 65);
+ assert_equals(authData.counter, 0);
+ assert_equals(bytesToHexString(authData.aaguid), "00000000000000000000000000000000");
+ assert_array_equals(authData.credentialID, Base64URL.parse(testU2fCredentialIdBase64));
+ // Check fido-u2f attestation
+ assert_true(checkPublicKey(authData.publicKey));
+ assert_equals(attestationObject.attStmt.x5c.length, 1);
+ }
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "localhost",
+ },
+ user: {
+ name: "John Appleseed",
+ id: Base64URL.parse(testUserhandleBase64),
+ displayName: "Appleseed",
+ },
+ challenge: Base64URL.parse("MTIzNDU2"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fRegisterResponse] } });
+ return navigator.credentials.create(options).then(credential => {
+ checkResult(credential);
+ });
+ }, "PublicKeyCredential's [[create]] with minimum options in a mock u2f authenticator.");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "localhost",
+ },
+ user: {
+ name: "John Appleseed",
+ id: Base64URL.parse(testUserhandleBase64),
+ displayName: "Appleseed",
+ },
+ challenge: Base64URL.parse("MTIzNDU2"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fRegisterResponse] } });
+ return navigator.credentials.create(options).then(credential => {
+ checkResult(credential);
+ });
+ }, "PublicKeyCredential's [[create]] with excludeCredentials in a mock u2f authenticator.");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "localhost",
+ },
+ user: {
+ name: "John Appleseed",
+ id: Base64URL.parse(testUserhandleBase64),
+ displayName: "Appleseed",
+ },
+ challenge: Base64URL.parse("MTIzNDU2"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }, { type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }], // The content doesn't matter.
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fApduWrongDataOnlyResponseBase64, testU2fRegisterResponse] } });
+ return navigator.credentials.create(options).then(credential => {
+ checkResult(credential);
+ });
+ }, "PublicKeyCredential's [[create]] with excludeCredentials in a mock u2f authenticator. 2");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "localhost",
+ },
+ user: {
+ name: "John Appleseed",
+ id: Base64URL.parse(testUserhandleBase64),
+ displayName: "Appleseed",
+ },
+ challenge: Base64URL.parse("MTIzNDU2"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+ timeout: 500
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fRegisterResponse] } });
+ return navigator.credentials.create(options).then(credential => {
+ checkResult(credential);
+ });
+ }, "PublicKeyCredential's [[create]] with test of user presence in a mock u2f authenticator.");
+</script>
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -13,7 +13,7 @@
};
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.");
}, "PublicKeyCredential's [[get]] with malicious payload in a mock hid authenticator.");
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -32,7 +32,7 @@
};
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: testDummyMessagePayloadBase64 } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64] } });
return promiseRejects(t, "UnknownError", navigator.credentials.get(options), "Unknown internal error. Error code: -1");
}, "PublicKeyCredential's [[get]] with malicious payload in a mock hid authenticator.");
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https-expected.txt (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https-expected.txt 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,5 @@
+
+PASS PublicKeyCredential's [[get]] with malformed sign response in a mock hid authenticator.
+PASS PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator.
+PASS PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator. 2
+
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[get]] failure cases with a mock u2f authenticator.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ challenge: asciiToUint8Array("123456"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[get]] with malformed sign response in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ challenge: asciiToUint8Array("123456"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ challenge: asciiToUint8Array("123456"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }, { type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fApduWrongDataOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.");
+ }, "PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator. 2");
+</script>
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f.https-expected.txt (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f.https-expected.txt 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,5 @@
+
+PASS PublicKeyCredential's [[get]] with malformed sign response in a mock hid authenticator.
+PASS PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator.
+PASS PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator. 2
+
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[get]] failure cases with a mock u2f authenticator.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ challenge: asciiToUint8Array("123456"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduNoErrorOnlyResponseBase64] } });
+ return promiseRejects(t, "UnknownError", navigator.credentials.get(options), "Couldn't parse the U2F sign response.");
+ }, "PublicKeyCredential's [[get]] with malformed sign response in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ challenge: asciiToUint8Array("123456"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "No credentials from the allowCredentials list is found in the authenticator.");
+ }, "PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ challenge: asciiToUint8Array("123456"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }, { type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }]
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fApduWrongDataOnlyResponseBase64] } });
+ return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "No credentials from the allowCredentials list is found in the authenticator.");
+ }, "PublicKeyCredential's [[get]] with no matched allow credentials in a mock hid authenticator. 2");
+</script>
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -6,7 +6,7 @@
<script>
// Default mock configuration. Tests need to override if they need different configuration.
if (window.testRunner)
- testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: testAssertionMessageBase64 } });
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testAssertionMessageBase64] } });
function checkResult(credential)
{
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-u2f.https-expected.txt (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-u2f.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-u2f.https-expected.txt 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,5 @@
+
+PASS PublicKeyCredential's [[get]] with minimum options in a mock hid authenticator.
+PASS PublicKeyCredential's [[get]] with more allow credentials in a mock hid authenticator.
+PASS PublicKeyCredential's [[get]] with test of user presence in a mock hid authenticator.
+
Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-u2f.https.html (0 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-u2f.https.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-u2f.https.html 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[get]] success cases with a mock u2f authenticator.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+ function checkResult(credential)
+ {
+ // Check respond
+ assert_array_equals(Base64URL.parse(credential.id), Base64URL.parse(testU2fCredentialIdBase64));
+ assert_equals(credential.type, 'public-key');
+ assert_array_equals(new Uint8Array(credential.rawId), Base64URL.parse(testU2fCredentialIdBase64));
+ assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.get","challenge":"MTIzNDU2","origin":"https://localhost:9443"}');
+ assert_equals(credential.response.userHandle, null);
+
+ // Check authData
+ const authData = decodeAuthData(new Uint8Array(credential.response.authenticatorData));
+ assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763");
+ assert_equals(authData.flags, 1);
+ assert_equals(authData.counter, 59);
+ }
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ challenge: Base64URL.parse("MTIzNDU2"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testU2fCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fSignResponse] } });
+ return navigator.credentials.get(options).then(credential => {
+ return checkResult(credential);
+ });
+ }, "PublicKeyCredential's [[get]] with minimum options in a mock hid authenticator.");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ challenge: Base64URL.parse("MTIzNDU2"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }, { type: "public-key", id: Base64URL.parse(testU2fCredentialIdBase64) }],
+ timeout: 10
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduWrongDataOnlyResponseBase64, testU2fSignResponse] } });
+ return navigator.credentials.get(options).then(credential => {
+ return checkResult(credential);
+ });
+ }, "PublicKeyCredential's [[get]] with more allow credentials in a mock hid authenticator.");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ challenge: Base64URL.parse("MTIzNDU2"),
+ allowCredentials: [{ type: "public-key", id: Base64URL.parse(testU2fCredentialIdBase64) }],
+ timeout: 500
+ }
+ };
+
+ if (window.testRunner)
+ testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", isU2f: true, payloadBase64: [testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fApduConditionsNotSatisfiedOnlyResponseBase64, testU2fSignResponse] } });
+ return navigator.credentials.get(options).then(credential => {
+ return checkResult(credential);
+ });
+ }, "PublicKeyCredential's [[get]] with test of user presence in a mock hid authenticator.");
+</script>
Modified: trunk/LayoutTests/http/wpt/webauthn/resources/util.js (239751 => 239752)
--- trunk/LayoutTests/http/wpt/webauthn/resources/util.js 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/http/wpt/webauthn/resources/util.js 2019-01-09 00:35:39 UTC (rev 239752)
@@ -69,6 +69,34 @@
"Z51VstuQkuHI2eXh0Ct1gPC0gSx3CWLh5I9a2AEAAABQA1hHMEUCIQCSFTuuBWgB" +
"4/F0VB7DlUVM09IHPmxe1MzHUwRoCRZbCAIgGKov6xoAx2MEf6/6qNs8OutzhP2C" +
"QoJ1L7Fe64G9uBc=";
+const testU2fApduNoErrorOnlyResponseBase64 = "kAA=";
+const testU2fApduInsNotSupportedOnlyResponseBase64 = "bQA=";
+const testU2fApduWrongDataOnlyResponseBase64 = "aoA=";
+const testU2fApduConditionsNotSatisfiedOnlyResponseBase64 = "aYU=";
+const testU2fRegisterResponse =
+ "BQTodiWJbuTkbcAydm6Ah5YvNt+d/otWfzdjAVsZkKYOFCfeYS1mQYvaGVBYHrxc" +
+ "jB2tcQyxTCL4yXBF9GEvsgyRQD69ib937FCXVe6cJjXvqqx7K5xc7xc2w3F9pIU0" +
+ "yMa2VNf/lF9QtcxOeAVb3TlrZPeNosX5YgDM1BXNCP5CADgwggJKMIIBMqADAgEC" +
+ "AgQEbIgiMA0GCSqGSIb3DQEBCwUAMC4xLDAqBgNVBAMTI1l1YmljbyBVMkYgUm9v" +
+ "dCBDQSBTZXJpYWwgNDU3MjAwNjMxMCAXDTE0MDgwMTAwMDAwMFoYDzIwNTAwOTA0" +
+ "MDAwMDAwWjAsMSowKAYDVQQDDCFZdWJpY28gVTJGIEVFIFNlcmlhbCAyNDkxODIz" +
+ "MjQ3NzAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ8yrksy5cofujmOUN+IfzW" +
+ "tvFlstWj89sTHTHBa3QrtHbY0emQgOtUbJu99VbmIQ/UJ4WJnnjMWJ6+MQ9s25/0" +
+ "ozswOTAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4xLjQxNDgyLjEuMjATBgsrBgEE" +
+ "AYLlHAIBAQQEAwIEMDANBgkqhkiG9w0BAQsFAAOCAQEAn5sFIki8TPQsxZkfyqus" +
+ "m2Ubvlvc3I7wrSwcH/s20YcV1C54skkiT5LH5uegXEnw5+TIgb8ulPReSiGDPXRW" +
+ "hR0PbBRaKVQMh08wksk0tD0iK4liwPQQzvHbdYkq8Ra0Spb101reo4IvxxRvYAQ4" +
+ "W8tptlyZ5+tpGXhnA8DYzUHo91zKRKqKtyWtjnmf86hpam8bJlbmMbHkAYPAj9pT" +
+ "+kqPhaBWk5RK4XmhM50ALRXKvYEAkOxyLvXe+ZZaNx1BXWJLaKJwfK2XvN0Xha+X" +
+ "4ljzPfVqAxqgNW2OjV68rcdOBxY2xrEQrOXMm5Df6srmQP8bsPH+XbTv96lfBgcz" +
+ "9TBFAiAyR3nGjzOAKIoRl7YJX3puubGxwSf2auEqmf6FMuwjuQIhAOOVFqxNYe5k" +
+ "BE1QtBWmpNTYS6bYlctat6GqfQgd40H6kAA=";
+const testU2fCredentialIdBase64 =
+ "Pr2Jv3fsUJdV7pwmNe-qrHsrnFzvFzbDcX2khTTIxrZU1_-UX1C1zE54BVvdOWtk" +
+ "942ixfliAMzUFc0I_kIAOA";
+const testU2fSignResponse =
+ "AQAAADswRAIge94KUqwfTIsn4AOjcM1mpMcRjdItVEeDX0W5nGhCP/cCIDxRe0eH" +
+ "f4V4LeEAhqeD0effTjY553H19q+jWq1Tc4WOkAA=";
const RESOURCES_DIR = "/WebKit/webauthn/resources/";
Modified: trunk/LayoutTests/platform/ios-wk2/TestExpectations (239751 => 239752)
--- trunk/LayoutTests/platform/ios-wk2/TestExpectations 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/LayoutTests/platform/ios-wk2/TestExpectations 2019-01-09 00:35:39 UTC (rev 239752)
@@ -1325,6 +1325,12 @@
http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html [ Skip ]
http/wpt/webauthn/public-key-credential-get-failure-hid.https.html [ Skip ]
http/wpt/webauthn/public-key-credential-get-success-hid.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-create-failure-u2f.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-create-success-u2f.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-get-failure-u2f-silent.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-get-failure-u2f.https.html [ Skip ]
+http/wpt/webauthn/public-key-credential-get-success-u2f.https.html [ Skip ]
# FIXME: Unskip these tests once we have the fix for <rdar://problem/44930119>.
fast/forms/auto-fill-button/caps-lock-indicator-should-be-visible-after-hiding-auto-fill-strong-password-button.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (239751 => 239752)
--- trunk/Source/WebCore/ChangeLog 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebCore/ChangeLog 2019-01-09 00:35:39 UTC (rev 239752)
@@ -1,3 +1,30 @@
+2019-01-08 Jiewen Tan <jiewen_...@apple.com>
+
+ [WebAuthN] Support U2F HID Authenticators on macOS
+ https://bugs.webkit.org/show_bug.cgi?id=191535
+ <rdar://problem/47102027>
+
+ Reviewed by Brent Fulgham.
+
+ 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:
+
2019-01-08 Wenson Hsieh <wenson_hs...@apple.com>
[iOS] Dispatch a synthetic mousedown event prior to starting drags
Modified: trunk/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.cpp (239751 => 239752)
--- trunk/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.cpp 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -54,6 +54,8 @@
apdu::ApduCommand command;
command.setIns(static_cast<uint8_t>(U2fApduInstruction::kRegister));
+ // This is needed for test of user presence even though the spec doesn't specify it.
+ command.setP1(kP1EnforceUserPresenceAndSign);
command.setData(WTFMove(data));
command.setResponseLength(apdu::ApduCommand::kApduMaxResponseLength);
return command.getEncodedCommand();
Modified: trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.cpp (239751 => 239752)
--- trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.cpp 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -173,7 +173,7 @@
return PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), true, nullptr, ArrayBuffer::create(attestationObject.data(), attestationObject.size()), nullptr, nullptr, nullptr };
}
-Optional<PublicKeyCredentialData> readFromU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData)
+Optional<PublicKeyCredentialData> readU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData)
{
if (keyHandle.isEmpty() || u2fData.size() <= signatureIndex)
return WTF::nullopt;
Modified: trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.h (239751 => 239752)
--- trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.h 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.h 2019-01-09 00:35:39 UTC (rev 239752)
@@ -42,7 +42,7 @@
// Converts a U2F authentication response to WebAuthN getAssertion response.
// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-authenticatorGetAssertion-interoperability
-WEBCORE_EXPORT Optional<WebCore::PublicKeyCredentialData> readFromU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData);
+WEBCORE_EXPORT Optional<WebCore::PublicKeyCredentialData> readU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData);
} // namespace fido
Modified: trunk/Source/WebKit/ChangeLog (239751 => 239752)
--- trunk/Source/WebKit/ChangeLog 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/ChangeLog 2019-01-09 00:35:39 UTC (rev 239752)
@@ -1,3 +1,52 @@
+2019-01-08 Jiewen Tan <jiewen_...@apple.com>
+
+ [WebAuthN] Support U2F HID Authenticators on macOS
+ https://bugs.webkit.org/show_bug.cgi?id=191535
+ <rdar://problem/47102027>
+
+ Reviewed by Brent Fulgham.
+
+ 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:
+
2019-01-08 Youenn Fablet <you...@apple.com>
service worker fetch handler results in bad referrer
Modified: trunk/Source/WebKit/Sources.txt (239751 => 239752)
--- trunk/Source/WebKit/Sources.txt 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/Sources.txt 2019-01-09 00:35:39 UTC (rev 239752)
@@ -385,6 +385,10 @@
UIProcess/UserContent/WebScriptMessageHandler.cpp
UIProcess/UserContent/WebUserContentControllerProxy.cpp
+UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp
+UIProcess/WebAuthentication/fido/CtapHidDriver.cpp
+UIProcess/WebAuthentication/fido/U2fHidAuthenticator.cpp
+
UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp
UIProcess/WebAuthentication/Mock/MockHidConnection.cpp
UIProcess/WebAuthentication/Mock/MockHidService.cpp
Modified: trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp (239751 => 239752)
--- trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -627,9 +627,12 @@
if (error == "wrong-nonce")
hid.error = WebKit::MockWebAuthenticationConfiguration::Hid::Error::WrongNonce;
- if (auto payloadBase64 = static_cast<WKStringRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")).get())))
- hid.payloadBase64 = WebKit::toImpl(payloadBase64)->string();
+ if (auto payloadBase64 = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("PayloadBase64")).get())))
+ hid.payloadBase64 = WebKit::toImpl(payloadBase64)->toStringVector();
+ if (auto isU2f = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("IsU2f")).get())))
+ hid.isU2f = WKBooleanGetValue(isU2f);
+
if (auto keepAlive = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(hidRef, adoptWK(WKStringCreateWithUTF8CString("KeepAlive")).get())))
hid.keepAlive = WKBooleanGetValue(keepAlive);
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/HidService.mm (239751 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/HidService.mm 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/HidService.mm 2019-01-09 00:35:39 UTC (rev 239752)
@@ -31,6 +31,7 @@
#import "CtapHidAuthenticator.h"
#import "CtapHidDriver.h"
#import "HidConnection.h"
+#import "U2fHidAuthenticator.h"
#import <WebCore/DeviceRequestConverter.h>
#import <WebCore/DeviceResponseConverter.h>
#import <WebCore/FidoConstants.h>
@@ -108,7 +109,7 @@
void HidService::continueAddDeviceAfterGetInfo(CtapHidDriver* ptr, Vector<uint8_t>&& response)
{
std::unique_ptr<CtapHidDriver> driver = m_drivers.take(ptr);
- if (!driver || !observer())
+ if (!driver || !observer() || response.isEmpty())
return;
auto info = readCTAPGetInfoResponse(response);
@@ -116,8 +117,9 @@
observer()->authenticatorAdded(CtapHidAuthenticator::create(WTFMove(driver), WTFMove(*info)));
return;
}
- // FIXME(191535): Support U2F authenticators.
LOG_ERROR("Couldn't parse a ctap get info response.");
+ driver->setProtocol(ProtocolVersion::kU2f);
+ observer()->authenticatorAdded(U2fHidAuthenticator::create(WTFMove(driver)));
}
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp (239751 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -127,43 +127,48 @@
if (previousSubStage == Mock::SubStage::Msg)
m_stage = Mock::Stage::Request;
}
- if (m_requestMessage->cmd() == FidoHidDeviceCommand::kCbor)
+ if (m_requestMessage->cmd() == FidoHidDeviceCommand::kCbor || m_requestMessage->cmd() == FidoHidDeviceCommand::kMsg)
m_subStage = Mock::SubStage::Msg;
- // Set options.
if (m_stage == Mock::Stage::Request && m_subStage == Mock::SubStage::Msg) {
- m_requireResidentKey = false;
- m_requireUserVerification = false;
+ // Make sure we issue different msg cmd for CTAP and U2F.
+ ASSERT(m_configuration.hid->isU2f ^ (m_requestMessage->cmd() != FidoHidDeviceCommand::kMsg));
- auto payload = m_requestMessage->getMessagePayload();
- ASSERT(payload.size());
- auto cmd = static_cast<CtapRequestCommand>(payload[0]);
- payload.remove(0);
- auto requestMap = CBORReader::read(payload);
- ASSERT(requestMap);
+ // Set options.
+ if (m_requestMessage->cmd() == FidoHidDeviceCommand::kCbor) {
+ m_requireResidentKey = false;
+ m_requireUserVerification = false;
- if (cmd == CtapRequestCommand::kAuthenticatorMakeCredential) {
- auto it = requestMap->getMap().find(CBORValue(CtapMakeCredentialRequestOptionsKey)); // Find options.
- if (it != requestMap->getMap().end()) {
- auto& optionMap = it->second.getMap();
+ auto payload = m_requestMessage->getMessagePayload();
+ ASSERT(payload.size());
+ auto cmd = static_cast<CtapRequestCommand>(payload[0]);
+ payload.remove(0);
+ auto requestMap = CBORReader::read(payload);
+ ASSERT(requestMap);
- auto itr = optionMap.find(CBORValue(kResidentKeyMapKey));
- if (itr != optionMap.end())
- m_requireResidentKey = itr->second.getBool();
+ if (cmd == CtapRequestCommand::kAuthenticatorMakeCredential) {
+ auto it = requestMap->getMap().find(CBORValue(CtapMakeCredentialRequestOptionsKey)); // Find options.
+ if (it != requestMap->getMap().end()) {
+ auto& optionMap = it->second.getMap();
- itr = optionMap.find(CBORValue(kUserVerificationMapKey));
- if (itr != optionMap.end())
- m_requireUserVerification = itr->second.getBool();
+ auto itr = optionMap.find(CBORValue(kResidentKeyMapKey));
+ if (itr != optionMap.end())
+ m_requireResidentKey = itr->second.getBool();
+
+ itr = optionMap.find(CBORValue(kUserVerificationMapKey));
+ if (itr != optionMap.end())
+ m_requireUserVerification = itr->second.getBool();
+ }
}
- }
- if (cmd == CtapRequestCommand::kAuthenticatorGetAssertion) {
- auto it = requestMap->getMap().find(CBORValue(CtapGetAssertionRequestOptionsKey)); // Find options.
- if (it != requestMap->getMap().end()) {
- auto& optionMap = it->second.getMap();
- auto itr = optionMap.find(CBORValue(kUserVerificationMapKey));
- if (itr != optionMap.end())
- m_requireUserVerification = itr->second.getBool();
+ if (cmd == CtapRequestCommand::kAuthenticatorGetAssertion) {
+ auto it = requestMap->getMap().find(CBORValue(CtapGetAssertionRequestOptionsKey)); // Find options.
+ if (it != requestMap->getMap().end()) {
+ auto& optionMap = it->second.getMap();
+ auto itr = optionMap.find(CBORValue(kUserVerificationMapKey));
+ if (itr != optionMap.end())
+ m_requireUserVerification = itr->second.getBool();
+ }
}
}
}
@@ -207,8 +212,12 @@
infoData.insert(0, static_cast<uint8_t>(CtapDeviceResponseCode::kSuccess)); // Prepend status code.
if (stagesMatch() && m_configuration.hid->error == Mock::Error::WrongChannelId)
message = FidoHidMessage::create(m_currentChannel - 1, FidoHidDeviceCommand::kCbor, infoData);
- else
- message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, infoData);
+ else {
+ if (!m_configuration.hid->isU2f)
+ message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, infoData);
+ else
+ message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kError, { static_cast<uint8_t>(CtapDeviceResponseCode::kCtap1ErrInvalidCommand) });
+ }
}
if (m_stage == Mock::Stage::Request && m_subStage == Mock::SubStage::Msg) {
@@ -223,9 +232,14 @@
message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, { static_cast<uint8_t>(CtapDeviceResponseCode::kCtap2ErrUnsupportedOption) });
else {
Vector<uint8_t> payload;
- auto status = base64Decode(m_configuration.hid->payloadBase64, payload);
+ ASSERT(!m_configuration.hid->payloadBase64.isEmpty());
+ auto status = base64Decode(m_configuration.hid->payloadBase64[0], payload);
+ m_configuration.hid->payloadBase64.remove(0);
ASSERT_UNUSED(status, status);
- message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, payload);
+ if (!m_configuration.hid->isU2f)
+ message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kCbor, payload);
+ else
+ message = FidoHidMessage::create(m_currentChannel, FidoHidDeviceCommand::kMsg, payload);
}
}
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.h (239751 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.h 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.h 2019-01-09 00:35:39 UTC (rev 239752)
@@ -35,11 +35,13 @@
namespace WebKit {
// The following basically simulates an external HID token that:
-// 1. Only supports CTAP2 protocol,
+// 1. Supports only one protocol, either CTAP2 or U2F.
// 2. Doesn't support resident keys,
// 3. Doesn't support user verification.
-// There are four stages for each WebAuthN request:
+// There are four stages for each CTAP request:
// FSM: Info::Init => Info::Msg => Request::Init => Request::Msg
+// There are indefinite stages for each U2F request:
+// FSM: Info::Init => Info::Msg => [Request::Init => Request::Msg]+
// According to different combinations of error and stages, error will manifest differently.
class MockHidConnection final : public CanMakeWeakPtr<MockHidConnection>, public HidConnection {
public:
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h (239751 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h 2019-01-09 00:35:39 UTC (rev 239752)
@@ -61,10 +61,11 @@
WrongNonce
};
- String payloadBase64;
+ Vector<String> payloadBase64;
Stage stage { Stage::Info };
SubStage subStage { SubStage::Init };
Error error { Error::Success };
+ bool isU2f { false };
bool keepAlive { false };
bool fastDataArrival { false };
bool continueAfterErrorData { false };
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.cpp (239751 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.cpp 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -197,7 +197,7 @@
// FIXME(191534): Check the reset of the payload.
// FIXME(192061)
LOG_ERROR("Start sending the request.");
- auto cmd = FidoHidMessage::create(m_channelId, FidoHidDeviceCommand::kCbor, m_requestData);
+ auto cmd = FidoHidMessage::create(m_channelId, m_protocol == ProtocolVersion::kCtap ? FidoHidDeviceCommand::kCbor : FidoHidDeviceCommand::kMsg, m_requestData);
ASSERT(cmd);
m_worker->transact(WTFMove(*cmd), [weakThis = makeWeakPtr(*this)](Optional<FidoHidMessage>&& response) mutable {
ASSERT(RunLoop::isMain());
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.h (239751 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.h 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidDriver.h 2019-01-09 00:35:39 UTC (rev 239752)
@@ -57,6 +57,7 @@
explicit CtapHidDriver(UniqueRef<HidConnection>&&);
+ void setProtocol(fido::ProtocolVersion protocol) { m_protocol = protocol; }
void transact(Vector<uint8_t>&& data, ResponseCallback&&);
private:
@@ -103,6 +104,7 @@
Vector<uint8_t> m_requestData;
ResponseCallback m_responseCallback;
Vector<uint8_t> m_nonce;
+ fido::ProtocolVersion m_protocol { fido::ProtocolVersion::kCtap };
};
} // namespace WebKit
Added: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fHidAuthenticator.cpp (0 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fHidAuthenticator.cpp (rev 0)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fHidAuthenticator.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "U2fHidAuthenticator.h"
+
+#if ENABLE(WEB_AUTHN) && PLATFORM(MAC)
+
+#include "CtapHidDriver.h"
+#include <WebCore/ApduResponse.h>
+#include <WebCore/ExceptionData.h>
+#include <WebCore/U2fCommandConstructor.h>
+#include <WebCore/U2fResponseConverter.h>
+#include <wtf/RunLoop.h>
+#include <wtf/text/StringConcatenateNumbers.h>
+
+namespace WebKit {
+using namespace WebCore;
+using namespace apdu;
+using namespace fido;
+
+namespace {
+const unsigned retryTimeOutValueMs = 200;
+}
+
+U2fHidAuthenticator::U2fHidAuthenticator(std::unique_ptr<CtapHidDriver>&& driver)
+ : m_driver(WTFMove(driver))
+ , m_retryTimer(RunLoop::main(), this, &U2fHidAuthenticator::retryLastCommand)
+{
+ // FIXME(191520): We need a way to convert std::unique_ptr to UniqueRef.
+ ASSERT(m_driver);
+}
+
+void U2fHidAuthenticator::makeCredential()
+{
+ if (!isConvertibleToU2fRegisterCommand(requestData().creationOptions)) {
+ receiveRespond(ExceptionData { NotSupportedError, "Cannot convert the request to U2F command."_s });
+ return;
+ }
+ if (!requestData().creationOptions.excludeCredentials.isEmpty()) {
+ ASSERT(!m_nextListIndex);
+ checkExcludeList(m_nextListIndex++);
+ return;
+ }
+ issueRegisterCommand();
+}
+
+void U2fHidAuthenticator::checkExcludeList(size_t index)
+{
+ if (index >= requestData().creationOptions.excludeCredentials.size()) {
+ issueRegisterCommand();
+ return;
+ }
+ auto u2fCmd = convertToU2fCheckOnlySignCommand(requestData().hash, requestData().creationOptions, requestData().creationOptions.excludeCredentials[index]);
+ ASSERT(u2fCmd);
+ issueNewCommand(WTFMove(*u2fCmd), CommandType::CheckOnlyCommand);
+}
+
+void U2fHidAuthenticator::issueRegisterCommand()
+{
+ auto u2fCmd = convertToU2fRegisterCommand(requestData().hash, requestData().creationOptions);
+ ASSERT(u2fCmd);
+ issueNewCommand(WTFMove(*u2fCmd), CommandType::RegisterCommand);
+}
+
+void U2fHidAuthenticator::getAssertion()
+{
+ if (!isConvertibleToU2fSignCommand(requestData().requestOptions)) {
+ receiveRespond(ExceptionData { NotSupportedError, "Cannot convert the request to U2F command."_s });
+ return;
+ }
+ ASSERT(!m_nextListIndex);
+ issueSignCommand(m_nextListIndex++);
+}
+
+void U2fHidAuthenticator::issueSignCommand(size_t index)
+{
+ if (index >= requestData().requestOptions.allowCredentials.size()) {
+ receiveRespond(ExceptionData { NotAllowedError, "No credentials from the allowCredentials list is found in the authenticator."_s });
+ return;
+ }
+ auto u2fCmd = convertToU2fSignCommand(requestData().hash, requestData().requestOptions, requestData().requestOptions.allowCredentials[index].idVector);
+ ASSERT(u2fCmd);
+ issueNewCommand(WTFMove(*u2fCmd), CommandType::SignCommand);
+}
+
+void U2fHidAuthenticator::issueNewCommand(Vector<uint8_t>&& command, CommandType type)
+{
+ m_lastCommand = WTFMove(command);
+ m_lastCommandType = type;
+ issueCommand(m_lastCommand, m_lastCommandType);
+}
+
+void U2fHidAuthenticator::issueCommand(const Vector<uint8_t>& command, CommandType type)
+{
+ m_driver->transact(Vector<uint8_t>(command), [weakThis = makeWeakPtr(*this), type](Vector<uint8_t>&& data) {
+ ASSERT(RunLoop::isMain());
+ if (!weakThis)
+ return;
+ weakThis->responseReceived(WTFMove(data), type);
+ });
+}
+
+void U2fHidAuthenticator::responseReceived(Vector<uint8_t>&& response, CommandType type)
+{
+ auto apduResponse = ApduResponse::createFromMessage(response);
+ if (!apduResponse) {
+ receiveRespond(ExceptionData { UnknownError, "Couldn't parse the APDU response."_s });
+ return;
+ }
+
+ switch (type) {
+ case CommandType::RegisterCommand:
+ continueRegisterCommandAfterResponseReceived(WTFMove(*apduResponse));
+ return;
+ case CommandType::CheckOnlyCommand:
+ continueCheckOnlyCommandAfterResponseReceived(WTFMove(*apduResponse));
+ return;
+ case CommandType::BogusCommand:
+ continueBogusCommandAfterResponseReceived(WTFMove(*apduResponse));
+ return;
+ case CommandType::SignCommand:
+ continueSignCommandAfterResponseReceived(WTFMove(*apduResponse));
+ return;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+void U2fHidAuthenticator::continueRegisterCommandAfterResponseReceived(ApduResponse&& apduResponse)
+{
+ switch (apduResponse.status()) {
+ case ApduResponse::Status::SW_NO_ERROR: {
+ auto response = readU2fRegisterResponse(requestData().creationOptions.rp.id, apduResponse.data());
+ if (!response) {
+ receiveRespond(ExceptionData { UnknownError, "Couldn't parse the U2F register response."_s });
+ return;
+ }
+ receiveRespond(WTFMove(*response));
+ return;
+ }
+ case ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED:
+ // Polling is required during test of user presence.
+ m_retryTimer.startOneShot(Seconds::fromMilliseconds(retryTimeOutValueMs));
+ return;
+ default:
+ receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<unsigned>(apduResponse.status())) });
+ }
+}
+
+void U2fHidAuthenticator::continueCheckOnlyCommandAfterResponseReceived(ApduResponse&& apduResponse)
+{
+ switch (apduResponse.status()) {
+ case ApduResponse::Status::SW_NO_ERROR:
+ case ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED:
+ issueNewCommand(constructBogusU2fRegistrationCommand(), CommandType::BogusCommand);
+ return;
+ default:
+ checkExcludeList(m_nextListIndex++);
+ }
+}
+
+void U2fHidAuthenticator::continueBogusCommandAfterResponseReceived(ApduResponse&& apduResponse)
+{
+ switch (apduResponse.status()) {
+ case ApduResponse::Status::SW_NO_ERROR:
+ receiveRespond(ExceptionData { InvalidStateError, "At least one credential matches an entry of the excludeCredentials list in the authenticator."_s });
+ return;
+ case ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED:
+ // Polling is required during test of user presence.
+ m_retryTimer.startOneShot(Seconds::fromMilliseconds(retryTimeOutValueMs));
+ return;
+ default:
+ receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<unsigned>(apduResponse.status())) });
+ }
+}
+
+void U2fHidAuthenticator::continueSignCommandAfterResponseReceived(ApduResponse&& apduResponse)
+{
+ switch (apduResponse.status()) {
+ case ApduResponse::Status::SW_NO_ERROR: {
+ auto response = readU2fSignResponse(requestData().requestOptions.rpId, requestData().requestOptions.allowCredentials[m_nextListIndex - 1].idVector, apduResponse.data());
+ if (!response) {
+ receiveRespond(ExceptionData { UnknownError, "Couldn't parse the U2F sign response."_s });
+ return;
+ }
+ receiveRespond(WTFMove(*response));
+ return;
+ }
+ case ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED:
+ // Polling is required during test of user presence.
+ m_retryTimer.startOneShot(Seconds::fromMilliseconds(retryTimeOutValueMs));
+ return;
+ default:
+ issueSignCommand(m_nextListIndex++);
+ }
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN) && PLATFORM(MAC)
Added: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fHidAuthenticator.h (0 => 239752)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fHidAuthenticator.h (rev 0)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fHidAuthenticator.h 2019-01-09 00:35:39 UTC (rev 239752)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN) && PLATFORM(MAC)
+
+#include "Authenticator.h"
+#include <wtf/RunLoop.h>
+
+namespace apdu {
+class ApduResponse;
+}
+
+namespace WebKit {
+
+class CtapHidDriver;
+
+class U2fHidAuthenticator final : public Authenticator {
+public:
+ static Ref<U2fHidAuthenticator> create(std::unique_ptr<CtapHidDriver>&& driver)
+ {
+ return adoptRef(*new U2fHidAuthenticator(WTFMove(driver)));
+ }
+
+private:
+ explicit U2fHidAuthenticator(std::unique_ptr<CtapHidDriver>&&);
+
+ void makeCredential() final;
+ void checkExcludeList(size_t index);
+ void issueRegisterCommand();
+ void getAssertion() final;
+ void issueSignCommand(size_t index);
+
+ enum class CommandType : uint8_t {
+ RegisterCommand,
+ CheckOnlyCommand,
+ BogusCommand,
+ SignCommand
+ };
+ void issueNewCommand(Vector<uint8_t>&& command, CommandType);
+ void retryLastCommand() { issueCommand(m_lastCommand, m_lastCommandType); }
+ void issueCommand(const Vector<uint8_t>& command, CommandType);
+ void responseReceived(Vector<uint8_t>&& response, CommandType);
+ void continueRegisterCommandAfterResponseReceived(apdu::ApduResponse&&);
+ void continueCheckOnlyCommandAfterResponseReceived(apdu::ApduResponse&&);
+ void continueBogusCommandAfterResponseReceived(apdu::ApduResponse&&);
+ void continueSignCommandAfterResponseReceived(apdu::ApduResponse&&);
+
+ std::unique_ptr<CtapHidDriver> m_driver;
+ RunLoop::Timer<U2fHidAuthenticator> m_retryTimer;
+ Vector<uint8_t> m_lastCommand;
+ CommandType m_lastCommandType;
+ size_t m_nextListIndex { 0 };
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN) && PLATFORM(MAC)
Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (239751 => 239752)
--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2019-01-09 00:35:39 UTC (rev 239752)
@@ -1013,8 +1013,6 @@
570AB8F320AE3BD700B8BE87 /* SecKeyProxyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 570AB8F220AE3BD700B8BE87 /* SecKeyProxyStore.h */; };
57597EB921811D9A0037F924 /* CtapHidDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 57597EB721811D9A0037F924 /* CtapHidDriver.h */; };
57597EBD218184900037F924 /* CtapHidAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57597EBB2181848F0037F924 /* CtapHidAuthenticator.h */; };
- 57597EBE218184900037F924 /* CtapHidAuthenticator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57597EBC2181848F0037F924 /* CtapHidAuthenticator.cpp */; };
- 57597EC121818BE20037F924 /* CtapHidDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57597EC021818BE20037F924 /* CtapHidDriver.cpp */; };
5772F206217DBD6A0056BF2C /* HidService.h in Headers */ = {isa = PBXBuildFile; fileRef = 5772F204217DBD6A0056BF2C /* HidService.h */; };
578DC2982155A0020074E815 /* LocalAuthenticationSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 578DC2972155A0010074E815 /* LocalAuthenticationSoftLink.h */; };
57AC8F50217FEED90055438C /* HidConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 57AC8F4E217FEED90055438C /* HidConnection.h */; };
@@ -1036,6 +1034,7 @@
57DCEDC3214F114C0016B847 /* MockLocalService.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC1214F114C0016B847 /* MockLocalService.h */; };
57DCEDC7214F18300016B847 /* MockLocalConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC5214F18300016B847 /* MockLocalConnection.h */; };
57DCEDCB214F4E420016B847 /* MockAuthenticatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 57DCEDC9214F4E420016B847 /* MockAuthenticatorManager.h */; };
+ 57EB2E3A21E1983E00B89CDF /* U2fHidAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57EB2E3821E1983E00B89CDF /* U2fHidAuthenticator.h */; };
587743A621C30BBE00AE9084 /* HTTPSUpgradeList.db in Resources */ = {isa = PBXBuildFile; fileRef = 587743A421C30AD800AE9084 /* HTTPSUpgradeList.db */; };
58E977DF21C49A00005D92A6 /* NetworkHTTPSUpgradeChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 58E977DD21C49A00005D92A6 /* NetworkHTTPSUpgradeChecker.h */; };
5C0B17781E7C880E00E9123C /* NetworkSocketStreamMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C0B17741E7C879C00E9123C /* NetworkSocketStreamMessageReceiver.cpp */; };
@@ -3404,6 +3403,8 @@
57DCEDC6214F18300016B847 /* MockLocalConnection.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MockLocalConnection.mm; sourceTree = "<group>"; };
57DCEDC9214F4E420016B847 /* MockAuthenticatorManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockAuthenticatorManager.h; sourceTree = "<group>"; };
57DCEDCD214F51680016B847 /* MockAuthenticatorManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockAuthenticatorManager.cpp; sourceTree = "<group>"; };
+ 57EB2E3821E1983E00B89CDF /* U2fHidAuthenticator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = U2fHidAuthenticator.h; sourceTree = "<group>"; };
+ 57EB2E3921E1983E00B89CDF /* U2fHidAuthenticator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = U2fHidAuthenticator.cpp; sourceTree = "<group>"; };
587743A421C30AD800AE9084 /* HTTPSUpgradeList.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = HTTPSUpgradeList.db; path = DerivedSources/WebKit2/HTTPSUpgradeList.db; sourceTree = BUILT_PRODUCTS_DIR; };
58E977DC21C499FE005D92A6 /* NetworkHTTPSUpgradeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkHTTPSUpgradeChecker.cpp; sourceTree = "<group>"; };
58E977DD21C49A00005D92A6 /* NetworkHTTPSUpgradeChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkHTTPSUpgradeChecker.h; sourceTree = "<group>"; };
@@ -6714,6 +6715,8 @@
57597EBB2181848F0037F924 /* CtapHidAuthenticator.h */,
57597EC021818BE20037F924 /* CtapHidDriver.cpp */,
57597EB721811D9A0037F924 /* CtapHidDriver.h */,
+ 57EB2E3921E1983E00B89CDF /* U2fHidAuthenticator.cpp */,
+ 57EB2E3821E1983E00B89CDF /* U2fHidAuthenticator.h */,
);
path = fido;
sourceTree = "<group>";
@@ -9323,6 +9326,7 @@
1AAF263914687C39004A1E8A /* TiledCoreAnimationDrawingArea.h in Headers */,
1AF05D8714688348008B1E81 /* TiledCoreAnimationDrawingAreaProxy.h in Headers */,
2F8336861FA139DF00C6E080 /* TouchBarMenuData.h in Headers */,
+ 57EB2E3A21E1983E00B89CDF /* U2fHidAuthenticator.h in Headers */,
1AFE436618B6C081009C7A48 /* UIDelegate.h in Headers */,
515BE1B51D5917FF00DD7C68 /* UIGamepad.h in Headers */,
515BE1A91D55293400DD7C68 /* UIGamepadProvider.h in Headers */,
@@ -10754,8 +10758,6 @@
2D92A786212B6AB100F493FD /* ChildProcess.cpp in Sources */,
51FAEC3B1B0657680009C4E7 /* ChildProcessMessageReceiver.cpp in Sources */,
2D92A77D212B6A7100F493FD /* Connection.cpp in Sources */,
- 57597EBE218184900037F924 /* CtapHidAuthenticator.cpp in Sources */,
- 57597EC121818BE20037F924 /* CtapHidDriver.cpp in Sources */,
2D92A77E212B6A7100F493FD /* DataReference.cpp in Sources */,
2D92A77F212B6A7100F493FD /* Decoder.cpp in Sources */,
1AB7D6191288B9D900CFD08C /* DownloadProxyMessageReceiver.cpp in Sources */,
Modified: trunk/Tools/ChangeLog (239751 => 239752)
--- trunk/Tools/ChangeLog 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Tools/ChangeLog 2019-01-09 00:35:39 UTC (rev 239752)
@@ -1,3 +1,21 @@
+2019-01-08 Jiewen Tan <jiewen_...@apple.com>
+
+ [WebAuthN] Support U2F HID Authenticators on macOS
+ https://bugs.webkit.org/show_bug.cgi?id=191535
+ <rdar://problem/47102027>
+
+ Reviewed by Brent Fulgham.
+
+ 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):
+
2019-01-08 Wenson Hsieh <wenson_hs...@apple.com>
[iOS] Dispatch a synthetic mousedown event prior to starting drags
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp (239751 => 239752)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -520,7 +520,7 @@
// Tests that U2F authenticator data is properly serialized.
TEST(CTAPResponseTest, TestParseSignResponseData)
{
- auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestSignResponse());
+ auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestSignResponse());
ASSERT_TRUE(response);
EXPECT_EQ(response->rawId->byteLength(), sizeof(TestData::kU2fSignKeyHandle));
EXPECT_EQ(memcmp(response->rawId->data(), TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle)), 0);
@@ -533,13 +533,13 @@
TEST(CTAPResponseTest, TestParseU2fSignWithNullKeyHandle)
{
- auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, Vector<uint8_t>(), getTestSignResponse());
+ auto response = readU2fSignResponse(TestData::kRelyingPartyId, Vector<uint8_t>(), getTestSignResponse());
EXPECT_FALSE(response);
}
TEST(CTAPResponseTest, TestParseU2fSignWithNullResponse)
{
- auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), Vector<uint8_t>());
+ auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), Vector<uint8_t>());
EXPECT_FALSE(response);
}
@@ -546,7 +546,7 @@
TEST(CTAPResponseTest, TestParseU2fSignWithCorruptedCounter)
{
// A sign response of less than 5 bytes.
- auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(3));
+ auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(3));
EXPECT_FALSE(response);
}
@@ -553,7 +553,7 @@
TEST(CTAPResponseTest, TestParseU2fSignWithCorruptedSignature)
{
// A sign response no more than 5 bytes.
- auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(5));
+ auto response = readU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(5));
EXPECT_FALSE(response);
}
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h (239751 => 239752)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h 2019-01-09 00:35:39 UTC (rev 239752)
@@ -51,7 +51,7 @@
constexpr uint8_t kU2fRegisterCommandApdu[] = {
// CLA, INS, P1, P2 APDU instructions
- 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x03, 0x00,
// Data length in 3 bytes in big endian order.
0x00, 0x00, 0x40,
// Challenge parameter -- see kClientDataHash
@@ -141,7 +141,7 @@
constexpr uint8_t kU2fFakeRegisterCommand[] = {
// CLA, INS, P1, P2 APDU instructions
- 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x03, 0x00,
// Data length in 3 bytes in big endian order.
0x00, 0x00, 0x40,
// Bogus challenge parameter
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp (239751 => 239752)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp 2019-01-09 00:16:32 UTC (rev 239751)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp 2019-01-09 00:35:39 UTC (rev 239752)
@@ -2509,12 +2509,38 @@
JSRetainPtr<JSStringRef> payloadBase64PropertyName(Adopt, JSStringCreateWithUTF8CString("payloadBase64"));
JSValueRef payloadBase64Value = JSObjectGetProperty(context, hid, payloadBase64PropertyName.get(), 0);
if (!JSValueIsUndefined(context, payloadBase64Value) && !JSValueIsNull(context, payloadBase64Value)) {
- if (!JSValueIsString(context, payloadBase64Value))
+ if (!JSValueIsArray(context, payloadBase64Value))
return;
+
+ JSObjectRef payloadBase64 = JSValueToObject(context, payloadBase64Value, nullptr);
+ static auto lengthProperty = adopt(JSStringCreateWithUTF8CString("length"));
+ JSValueRef payloadBase64LengthValue = JSObjectGetProperty(context, payloadBase64, lengthProperty.get(), nullptr);
+ if (!JSValueIsNumber(context, payloadBase64LengthValue))
+ return;
+
+ auto payloadBase64s = adoptWK(WKMutableArrayCreate());
+ auto payloadBase64Length = static_cast<size_t>(JSValueToNumber(context, payloadBase64LengthValue, nullptr));
+ for (size_t i = 0; i < payloadBase64Length; ++i) {
+ JSValueRef payloadBase64Value = JSObjectGetPropertyAtIndex(context, payloadBase64, i, nullptr);
+ if (!JSValueIsString(context, payloadBase64Value))
+ continue;
+ WKArrayAppendItem(payloadBase64s.get(), toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()).get());
+ }
+
hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("PayloadBase64") });
- hidValues.append(toWK(adopt(JSValueToStringCopy(context, payloadBase64Value, 0)).get()));
+ hidValues.append(payloadBase64s);
}
+ JSRetainPtr<JSStringRef> isU2fPropertyName(Adopt, JSStringCreateWithUTF8CString("isU2f"));
+ JSValueRef isU2fValue = JSObjectGetProperty(context, hid, isU2fPropertyName.get(), 0);
+ if (!JSValueIsUndefined(context, isU2fValue) && !JSValueIsNull(context, isU2fValue)) {
+ if (!JSValueIsBoolean(context, isU2fValue))
+ return;
+ bool isU2f = JSValueToBoolean(context, isU2fValue);
+ hidKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("IsU2f") });
+ hidValues.append(adoptWK(WKBooleanCreate(isU2f)).get());
+ }
+
JSRetainPtr<JSStringRef> keepAlivePropertyName(Adopt, JSStringCreateWithUTF8CString("keepAlive"));
JSValueRef keepAliveValue = JSObjectGetProperty(context, hid, keepAlivePropertyName.get(), 0);
if (!JSValueIsUndefined(context, keepAliveValue) && !JSValueIsNull(context, keepAliveValue)) {