[WebAuthN] InvalidStateError should be reported to sites
https://bugs.webkit.org/show_bug.cgi?id=193269
<rdar://problem/48298264>
Reviewed by Brent Fulgham.
Source/WebKit:
This patch implements step 20 about InvalidStateError of the spec:
https://www.w3.org/TR/webauthn/#createCredential.
* UIProcess/WebAuthentication/AuthenticatorManager.cpp:
(WebKit::AuthenticatorManager::respondReceived):
* UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp:
(WebKit::CtapHidAuthenticator::continueMakeCredentialAfterResponseReceived const):
LayoutTests:
* http/wpt/webauthn/ctap-hid-failure.https.html:
* http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https-expected.txt:
* http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html:
* http/wpt/webauthn/public-key-credential-create-failure-hid.https-expected.txt:
* http/wpt/webauthn/public-key-credential-create-failure-hid.https.html:
* http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html:
* http/wpt/webauthn/resources/util.js:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@245262 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index e3bc648..b10fe02 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,19 @@
+2019-05-13 Jiewen Tan <jiewen_tan@apple.com>
+
+ [WebAuthN] InvalidStateError should be reported to sites
+ https://bugs.webkit.org/show_bug.cgi?id=193269
+ <rdar://problem/48298264>
+
+ Reviewed by Brent Fulgham.
+
+ * http/wpt/webauthn/ctap-hid-failure.https.html:
+ * http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https-expected.txt:
+ * http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html:
+ * http/wpt/webauthn/public-key-credential-create-failure-hid.https-expected.txt:
+ * http/wpt/webauthn/public-key-credential-create-failure-hid.https.html:
+ * http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html:
+ * http/wpt/webauthn/resources/util.js:
+
2019-05-13 Devin Rousso <drousso@apple.com>
[ Mac Debug ] Layout Test inspector/audit/basic.html is a flaky timeout on bots
diff --git a/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html b/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html
index c46ee39..4f0fd6a 100644
--- a/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html
+++ b/LayoutTests/http/wpt/webauthn/ctap-hid-failure.https.html
@@ -65,6 +65,6 @@
promise_test(function(t) {
if (window.testRunner)
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");
+ return promiseRejects(t, "UnknownError", navigator.credentials.create(defaultOptions), "Unknown internal error. Error code: 18");
}, "CTAP HID with request::msg stage wrong channel id error in a mock hid authenticator.");
</script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https-expected.txt
index c708757..f32671e 100644
--- a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https-expected.txt
+++ b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https-expected.txt
@@ -3,4 +3,5 @@
PASS PublicKeyCredential's [[create]] with unsupported options in a mock hid authenticator.
PASS PublicKeyCredential's [[create]] with unsupported options in a mock hid authenticator. 2
PASS PublicKeyCredential's [[create]] with mixed options in a mock hid authenticator.
+PASS PublicKeyCredential's [[create]] with InvalidStateError in a mock hid authenticator.
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html
index 66004a3..66b5da4 100644
--- a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html
+++ b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid-silent.https.html
@@ -94,4 +94,25 @@
testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, hid: { stage: "request", subStage: "msg", error: "unsupported-options" } });
return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
}, "PublicKeyCredential's [[create]] with mixed options 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", payloadBase64: [testCtapErrCredentialExcludedOnlyResponseBase64] } });
+ 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 InvalidStateError in a mock hid authenticator.");
</script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https-expected.txt b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https-expected.txt
index e5fc45c..721db3b 100644
--- a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https-expected.txt
+++ b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https-expected.txt
@@ -5,4 +5,5 @@
PASS PublicKeyCredential's [[create]] with unsupported options in a mock hid authenticator. 2
PASS PublicKeyCredential's [[create]] with mixed options in a mock hid authenticator.
PASS PublicKeyCredential's [[create]] with mixed options in a mock hid authenticator. 2
+PASS PublicKeyCredential's [[create]] with InvalidStateError in a mock hid authenticator.
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html
index f163a39..2f837c6 100644
--- a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html
+++ b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-hid.https.html
@@ -47,7 +47,7 @@
if (window.testRunner)
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");
+ return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error. Error code: 255");
}, "PublicKeyCredential's [[create]] with malicious payload in a mock hid authenticator.");
promise_test(function(t) {
@@ -138,4 +138,25 @@
testRunner.setWebAuthenticationMockConfiguration({ hid: { stage: "request", subStage: "msg", error: "unsupported-options" } });
return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error. Error code: 43");
}, "PublicKeyCredential's [[create]] with mixed options in a mock hid authenticator. 2");
+
+ 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", payloadBase64: [testCtapErrCredentialExcludedOnlyResponseBase64] } });
+ 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 InvalidStateError in a mock hid authenticator.");
</script>
diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html
index 5417998..641c0ef 100644
--- a/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html
+++ b/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-u2f-silent.https.html
@@ -113,7 +113,7 @@
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.");
+ 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.
@@ -137,7 +137,7 @@
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.");
+ 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) {
diff --git a/LayoutTests/http/wpt/webauthn/resources/util.js b/LayoutTests/http/wpt/webauthn/resources/util.js
index f60986b..f9a3204 100644
--- a/LayoutTests/http/wpt/webauthn/resources/util.js
+++ b/LayoutTests/http/wpt/webauthn/resources/util.js
@@ -97,6 +97,7 @@
const testU2fSignResponse =
"AQAAADswRAIge94KUqwfTIsn4AOjcM1mpMcRjdItVEeDX0W5nGhCP/cCIDxRe0eH" +
"f4V4LeEAhqeD0effTjY553H19q+jWq1Tc4WOkAA=";
+const testCtapErrCredentialExcludedOnlyResponseBase64 = "GQ==";
const RESOURCES_DIR = "/WebKit/webauthn/resources/";
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 94b0840..1e12379 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,19 @@
+2019-05-13 Jiewen Tan <jiewen_tan@apple.com>
+
+ [WebAuthN] InvalidStateError should be reported to sites
+ https://bugs.webkit.org/show_bug.cgi?id=193269
+ <rdar://problem/48298264>
+
+ Reviewed by Brent Fulgham.
+
+ This patch implements step 20 about InvalidStateError of the spec:
+ https://www.w3.org/TR/webauthn/#createCredential.
+
+ * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
+ (WebKit::AuthenticatorManager::respondReceived):
+ * UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp:
+ (WebKit::CtapHidAuthenticator::continueMakeCredentialAfterResponseReceived const):
+
2019-05-13 Jer Noble <jer.noble@apple.com>
Take out MediaPlayback UI assertion when any WebProcess is playing audible media
diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
index ca7ae5e..0c5d25c 100644
--- a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
+++ b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
@@ -194,9 +194,12 @@
ASSERT(RunLoop::isMain());
if (!m_requestTimeOutTimer.isActive())
return;
-
ASSERT(m_pendingCompletionHandler);
- if (WTF::holds_alternative<PublicKeyCredentialData>(respond)) {
+
+ auto shouldComplete = WTF::holds_alternative<PublicKeyCredentialData>(respond);
+ if (!shouldComplete)
+ shouldComplete = WTF::get<ExceptionData>(respond).code == InvalidStateError;
+ if (shouldComplete) {
m_pendingCompletionHandler(WTFMove(respond));
clearStateAsync();
m_requestTimeOutTimer.stop();
diff --git a/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp b/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp
index 2a4bd19..08cd5a3 100644
--- a/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp
+++ b/Source/WebKit/UIProcess/WebAuthentication/fido/CtapHidAuthenticator.cpp
@@ -62,7 +62,11 @@
{
auto response = readCTAPMakeCredentialResponse(data);
if (!response) {
- receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", data.size() == 1 ? data[0] : -1) });
+ auto error = getResponseCode(data);
+ if (error == CtapDeviceResponseCode::kCtap2ErrCredentialExcluded)
+ receiveRespond(ExceptionData { InvalidStateError, "At least one credential matches an entry of the excludeCredentials list in the authenticator."_s });
+ else
+ receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) });
return;
}
receiveRespond(WTFMove(*response));