Log Message
[WebAuthn] Support authenticatorGetNextAssertion https://bugs.webkit.org/show_bug.cgi?id=203346 <rdar://problem/56558488>
Reviewed by Brent Fulgham. Source/WebCore: Covered by new tests within existing test files. * Modules/webauthn/AuthenticatorAssertionResponse.h: (WebCore::AuthenticatorAssertionResponse::setName): (WebCore::AuthenticatorAssertionResponse::name const): (WebCore::AuthenticatorAssertionResponse::setDisplayName): (WebCore::AuthenticatorAssertionResponse::displayName const): (WebCore::AuthenticatorAssertionResponse::setNumberOfCredentials): (WebCore::AuthenticatorAssertionResponse::numberOfCredentials const): Adds new members to store new fields of the response from the authenticator. Field "icon" is omitted given it could be used to track users according to https://github.com/w3c/webauthn/issues/1285. * Modules/webauthn/fido/DeviceResponseConverter.cpp: (fido::readCTAPGetAssertionResponse): Adds new logic to parse above fields from an authenticator response. Source/WebKit: This patch implements authenticatorGetNextAssertion as suggested by the spec: https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetNextAssertion The work flow is as follow: 1) When a valid assertion response is received, check its numberOfCredentials member; 2) When it is larger then 1, use authenticatorGetNextAssertion to get all remaining responses; 3) Once all responses are gathered, ask UI clients to pick one to return. * UIProcess/API/APIWebAuthenticationPanelClient.h: (API::WebAuthenticationPanelClient::selectAssertionResponses const): * UIProcess/WebAuthentication/Authenticator.h: * UIProcess/WebAuthentication/AuthenticatorManager.cpp: (WebKit::AuthenticatorManager::selectAssertionResponses): * UIProcess/WebAuthentication/AuthenticatorManager.h: * UIProcess/WebAuthentication/Mock/MockHidConnection.cpp: (WebKit::MockHidConnection::parseRequest): * UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp: (WebKit::CtapAuthenticator::continueGetAssertionAfterResponseReceived): (WebKit::CtapAuthenticator::continueGetNextAssertionAfterResponseReceived): * UIProcess/WebAuthentication/fido/CtapAuthenticator.h: Tools: * TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp: (TestWebKitAPI::TEST): * TestWebKitAPI/Tests/WebCore/FidoTestData.h: Adds new test case for new logic in DeviceResponseConverter. LayoutTests: * http/wpt/webauthn/public-key-credential-get-failure-hid.https-expected.txt: * http/wpt/webauthn/public-key-credential-get-failure-hid.https.html: * http/wpt/webauthn/public-key-credential-get-success-hid.https-expected.txt: * http/wpt/webauthn/public-key-credential-get-success-hid.https.html: * http/wpt/webauthn/resources/util.js:
Modified Paths
- trunk/LayoutTests/ChangeLog
- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https-expected.txt
- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html
- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https-expected.txt
- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html
- trunk/LayoutTests/http/wpt/webauthn/resources/util.js
- trunk/Source/WebCore/ChangeLog
- trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h
- trunk/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp
- trunk/Source/WebKit/ChangeLog
- trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h
- trunk/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h
- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h
- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp
- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp
- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h
- trunk/Tools/ChangeLog
- trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp
- trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h
Diff
Modified: trunk/LayoutTests/ChangeLog (254355 => 254356)
--- trunk/LayoutTests/ChangeLog 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/LayoutTests/ChangeLog 2020-01-10 19:06:44 UTC (rev 254356)
@@ -1,3 +1,17 @@
+2020-01-10 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Support authenticatorGetNextAssertion
+ https://bugs.webkit.org/show_bug.cgi?id=203346
+ <rdar://problem/56558488>
+
+ Reviewed by Brent Fulgham.
+
+ * http/wpt/webauthn/public-key-credential-get-failure-hid.https-expected.txt:
+ * http/wpt/webauthn/public-key-credential-get-failure-hid.https.html:
+ * http/wpt/webauthn/public-key-credential-get-success-hid.https-expected.txt:
+ * http/wpt/webauthn/public-key-credential-get-success-hid.https.html:
+ * http/wpt/webauthn/resources/util.js:
+
2020-01-10 Brent Fulgham <[email protected]>
Remove 'com.apple.nehelper' from the WebContent sandbox.
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https-expected.txt (254355 => 254356)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https-expected.txt 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https-expected.txt 2020-01-10 19:06:44 UTC (rev 254356)
@@ -5,4 +5,5 @@
PASS PublicKeyCredential's [[get]] with authenticator downgrade failed in a mock hid authenticator.
PASS PublicKeyCredential's [[get]] with authenticator downgrade failed in a mock hid authenticator. 2
PASS PublicKeyCredential's [[get]] with authenticator downgrade succeeded and then U2F failed in a mock hid authenticator.
+PASS PublicKeyCredential's [[get]] with getNextAssertion failed in a mock hid authenticator.
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html (254355 => 254356)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-hid.https.html 2020-01-10 19:06:44 UTC (rev 254356)
@@ -84,4 +84,16 @@
internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", canDowngrade: true, payloadBase64: [testCtapErrInvalidCredentialResponseBase64, testU2fApduNoErrorOnlyResponseBase64] } });
return promiseRejects(t, "UnknownError", navigator.credentials.get(options), "Unknown internal error. Error code: 34");
}, "PublicKeyCredential's [[get]] with authenticator downgrade succeeded and then U2F failed in a mock hid authenticator.");
+
+ promise_test(function(t) {
+ const options = {
+ publicKey: {
+ challenge: asciiToUint8Array("123456")
+ }
+ };
+
+ if (window.internals)
+ internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "malicious-payload", payloadBase64: [testAssertionMessageLongBase64, testCtapErrNotAllowedResponseBase64] } });
+ return promiseRejects(t, "UnknownError", navigator.credentials.get(options), "Unknown internal error. Error code: 48");
+ }, "PublicKeyCredential's [[get]] with getNextAssertion failed in a mock hid authenticator.");
</script>
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https-expected.txt (254355 => 254356)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https-expected.txt 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https-expected.txt 2020-01-10 19:06:44 UTC (rev 254356)
@@ -5,4 +5,5 @@
PASS PublicKeyCredential's [[get]] with userVerification { discouraged } in a mock hid authenticator.
PASS PublicKeyCredential's [[get]] with mixed options in a mock hid authenticator.
PASS PublicKeyCredential's [[get]] with two consecutive requests.
+PASS PublicKeyCredential's [[get]] with multiple accounts in a mock hid authenticator.
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html (254355 => 254356)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html 2020-01-10 19:06:44 UTC (rev 254356)
@@ -101,4 +101,19 @@
return checkCtapGetAssertionResult(credential);
});
}, "PublicKeyCredential's [[get]] with two consecutive requests.");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ challenge: Base64URL.parse("MTIzNDU2"),
+ timeout: 100
+ }
+ };
+
+ if (window.internals)
+ internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testAssertionMessageLongBase64, testAssertionMessageLongBase64] } });
+ return navigator.credentials.get(options).then(credential => {
+ return checkCtapGetAssertionResult(credential, "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=");
+ });
+ }, "PublicKeyCredential's [[get]] with multiple accounts in a mock hid authenticator.");
</script>
Modified: trunk/LayoutTests/http/wpt/webauthn/resources/util.js (254355 => 254356)
--- trunk/LayoutTests/http/wpt/webauthn/resources/util.js 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/LayoutTests/http/wpt/webauthn/resources/util.js 2020-01-10 19:06:44 UTC (rev 254356)
@@ -66,6 +66,15 @@
"Z51VstuQkuHI2eXh0Ct1gPC0gSx3CWLh5I9a2AEAAABQA1hHMEUCIQCSFTuuBWgB" +
"4/F0VB7DlUVM09IHPmxe1MzHUwRoCRZbCAIgGKov6xoAx2MEf6/6qNs8OutzhP2C" +
"QoJ1L7Fe64G9uBc=";
+const testAssertionMessageLongBase64 =
+ "AKUBomJpZFhAKAitzuj+Tslzelf3/vZwIGtDQNgoKeFd5oEieYzhyzA65saf0tK2" +
+ "w/mooa7tQtGgDdwZIjOhjcuZ0pQ1ajoE4GR0eXBlanB1YmxpYy1rZXkCWCVGzH+5" +
+ "Z51VstuQkuHI2eXh0Ct1gPC0gSx3CWLh5I9a2AEAAABQA1hHMEUCIQCSFTuuBWgB" +
+ "4/F0VB7DlUVM09IHPmxe1MzHUwRoCRZbCAIgGKov6xoAx2MEf6/6qNs8OutzhP2C" +
+ "QoJ1L7Fe64G9uBcEpGJpZFggMIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGT" +
+ "MIJkaWNvbngoaHR0cHM6Ly9waWNzLmFjbWUuY29tLzAwL3AvYUJqampwcVBiLnBu" +
+ "Z2RuYW1ldmpvaG5wc21pdGhAZXhhbXBsZS5jb21rZGlzcGxheU5hbWVtSm9obiBQ" +
+ "LiBTbWl0aAUC";
const testU2fApduNoErrorOnlyResponseBase64 = "kAA=";
const testU2fApduInsNotSupportedOnlyResponseBase64 = "bQA=";
const testU2fApduWrongDataOnlyResponseBase64 = "aoA=";
@@ -96,6 +105,7 @@
"f4V4LeEAhqeD0effTjY553H19q+jWq1Tc4WOkAA=";
const testCtapErrCredentialExcludedOnlyResponseBase64 = "GQ==";
const testCtapErrInvalidCredentialResponseBase64 = "Ig==";
+const testCtapErrNotAllowedResponseBase64 = "MA==";
const testNfcU2fVersionBase64 = "VTJGX1YykAA=";
const testNfcCtapVersionBase64 = "RklET18yXzCQAA==";
const testGetInfoResponseApduBase64 =
@@ -394,7 +404,7 @@
assert_equals(attestationObject.attStmt.x5c.length, 1);
}
-function checkCtapGetAssertionResult(credential)
+function checkCtapGetAssertionResult(credential, userHandleBase64 = null)
{
// Check respond
assert_array_equals(Base64URL.parse(credential.id), Base64URL.parse(testHidCredentialIdBase64));
@@ -401,7 +411,10 @@
assert_equals(credential.type, 'public-key');
assert_array_equals(new Uint8Array(credential.rawId), Base64URL.parse(testHidCredentialIdBase64));
assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.get","challenge":"MTIzNDU2","origin":"https://localhost:9443"}');
- assert_equals(credential.response.userHandle, null);
+ if (userHandleBase64 == null)
+ assert_equals(credential.response.userHandle, null);
+ else
+ assert_array_equals(new Uint8Array(credential.response.userHandle), Base64URL.parse(userHandleBase64));
assert_not_own_property(credential.getClientExtensionResults(), "appid");
// Check authData
Modified: trunk/Source/WebCore/ChangeLog (254355 => 254356)
--- trunk/Source/WebCore/ChangeLog 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebCore/ChangeLog 2020-01-10 19:06:44 UTC (rev 254356)
@@ -1,3 +1,26 @@
+2020-01-10 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Support authenticatorGetNextAssertion
+ https://bugs.webkit.org/show_bug.cgi?id=203346
+ <rdar://problem/56558488>
+
+ Reviewed by Brent Fulgham.
+
+ Covered by new tests within existing test files.
+
+ * Modules/webauthn/AuthenticatorAssertionResponse.h:
+ (WebCore::AuthenticatorAssertionResponse::setName):
+ (WebCore::AuthenticatorAssertionResponse::name const):
+ (WebCore::AuthenticatorAssertionResponse::setDisplayName):
+ (WebCore::AuthenticatorAssertionResponse::displayName const):
+ (WebCore::AuthenticatorAssertionResponse::setNumberOfCredentials):
+ (WebCore::AuthenticatorAssertionResponse::numberOfCredentials const):
+ Adds new members to store new fields of the response from the authenticator. Field "icon"
+ is omitted given it could be used to track users according to https://github.com/w3c/webauthn/issues/1285.
+ * Modules/webauthn/fido/DeviceResponseConverter.cpp:
+ (fido::readCTAPGetAssertionResponse):
+ Adds new logic to parse above fields from an authenticator response.
+
2020-01-10 Dean Jackson <[email protected]>
[WebGL] Add all remaining WebGL2 implementation functions to GraphicsContextGL
Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h (254355 => 254356)
--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h 2020-01-10 19:06:44 UTC (rev 254356)
@@ -41,6 +41,13 @@
ArrayBuffer* signature() const { return m_signature.ptr(); }
ArrayBuffer* userHandle() const { return m_userHandle.get(); }
+ void setName(const String& name) { m_name = name; }
+ String name() const { return m_name; }
+ void setDisplayName(const String& displayName) { m_displayName = displayName; }
+ String displayName() const { return m_displayName; }
+ void setNumberOfCredentials(size_t numberOfCredentials) { m_numberOfCredentials = numberOfCredentials; }
+ size_t numberOfCredentials() const { return m_numberOfCredentials; }
+
private:
AuthenticatorAssertionResponse(Ref<ArrayBuffer>&&, Ref<ArrayBuffer>&&, Ref<ArrayBuffer>&&, RefPtr<ArrayBuffer>&&);
@@ -50,6 +57,10 @@
Ref<ArrayBuffer> m_authenticatorData;
Ref<ArrayBuffer> m_signature;
RefPtr<ArrayBuffer> m_userHandle;
+
+ String m_name;
+ String m_displayName;
+ size_t m_numberOfCredentials { 0 };
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp (254355 => 254356)
--- trunk/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp 2020-01-10 19:06:44 UTC (rev 254356)
@@ -164,6 +164,7 @@
return nullptr;
auto& signature = it->second.getByteString();
+ RefPtr<AuthenticatorAssertionResponse> response;
it = responseMap.find(CBOR(4));
if (it != responseMap.end() && it->second.isMap()) {
auto& user = it->second.getMap();
@@ -171,10 +172,30 @@
if (itr == user.end() || !itr->second.isByteString())
return nullptr;
auto& userHandle = itr->second.getByteString();
- return AuthenticatorAssertionResponse::create(credentialId, authData, signature, userHandle);
+ response = AuthenticatorAssertionResponse::create(credentialId, authData, signature, userHandle);
+
+ itr = user.find(CBOR(kEntityNameMapKey));
+ if (itr != user.end()) {
+ if (!itr->second.isString())
+ return nullptr;
+ response->setName(itr->second.getString());
+ }
+
+ itr = user.find(CBOR(kDisplayNameMapKey));
+ if (itr != user.end()) {
+ if (!itr->second.isString())
+ return nullptr;
+ response->setDisplayName(itr->second.getString());
+ }
+ } else {
+ response = AuthenticatorAssertionResponse::create(credentialId, authData, signature, { });
}
- return AuthenticatorAssertionResponse::create(credentialId, authData, signature, { });
+ it = responseMap.find(CBOR(5));
+ if (it != responseMap.end() && it->second.isUnsigned())
+ response->setNumberOfCredentials(it->second.getUnsigned());
+
+ return response;
}
Optional<AuthenticatorGetInfoResponse> readCTAPGetInfoResponse(const Vector<uint8_t>& inBuffer)
Modified: trunk/Source/WebKit/ChangeLog (254355 => 254356)
--- trunk/Source/WebKit/ChangeLog 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/ChangeLog 2020-01-10 19:06:44 UTC (rev 254356)
@@ -1,3 +1,32 @@
+2020-01-10 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Support authenticatorGetNextAssertion
+ https://bugs.webkit.org/show_bug.cgi?id=203346
+ <rdar://problem/56558488>
+
+ Reviewed by Brent Fulgham.
+
+ This patch implements authenticatorGetNextAssertion as suggested by the spec:
+ https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetNextAssertion
+
+ The work flow is as follow:
+ 1) When a valid assertion response is received, check its numberOfCredentials member;
+ 2) When it is larger then 1, use authenticatorGetNextAssertion to get all remaining responses;
+ 3) Once all responses are gathered, ask UI clients to pick one to return.
+
+ * UIProcess/API/APIWebAuthenticationPanelClient.h:
+ (API::WebAuthenticationPanelClient::selectAssertionResponses const):
+ * UIProcess/WebAuthentication/Authenticator.h:
+ * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
+ (WebKit::AuthenticatorManager::selectAssertionResponses):
+ * UIProcess/WebAuthentication/AuthenticatorManager.h:
+ * UIProcess/WebAuthentication/Mock/MockHidConnection.cpp:
+ (WebKit::MockHidConnection::parseRequest):
+ * UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp:
+ (WebKit::CtapAuthenticator::continueGetAssertionAfterResponseReceived):
+ (WebKit::CtapAuthenticator::continueGetNextAssertionAfterResponseReceived):
+ * UIProcess/WebAuthentication/fido/CtapAuthenticator.h:
+
2020-01-10 Brent Fulgham <[email protected]>
Remove 'com.apple.nehelper' from the WebContent sandbox.
Modified: trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h (254355 => 254356)
--- trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h 2020-01-10 19:06:44 UTC (rev 254356)
@@ -27,6 +27,14 @@
#if ENABLE(WEB_AUTHN)
+#include <wtf/CompletionHandler.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+class AuthenticatorAssertionResponse;
+}
+
namespace WebKit {
enum class WebAuthenticationStatus : bool;
enum class WebAuthenticationResult : bool;
@@ -41,6 +49,7 @@
virtual void updatePanel(WebKit::WebAuthenticationStatus) const { }
virtual void dismissPanel(WebKit::WebAuthenticationResult) const { }
+ virtual void selectAssertionResponses(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>& responses, CompletionHandler<void(const Ref<WebCore::AuthenticatorAssertionResponse>&)>&& completionHandler) const { completionHandler(*responses.begin()); }
};
} // namespace API
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h (254355 => 254356)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h 2020-01-10 19:06:44 UTC (rev 254356)
@@ -35,6 +35,10 @@
#include <wtf/RefCounted.h>
#include <wtf/WeakPtr.h>
+namespace WebCore {
+class AuthenticatorAssertionResponse;
+}
+
namespace WebKit {
class Authenticator : public RefCounted<Authenticator>, public CanMakeWeakPtr<Authenticator> {
@@ -47,6 +51,7 @@
virtual void respondReceived(Respond&&) = 0;
virtual void downgrade(Authenticator* id, Ref<Authenticator>&& downgradedAuthenticator) = 0;
virtual void authenticatorStatusUpdated(WebAuthenticationStatus) = 0;
+ virtual void selectAssertionResponses(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const Ref<WebCore::AuthenticatorAssertionResponse>&)>&&) = 0;
};
virtual ~Authenticator() = default;
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp (254355 => 254356)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp 2020-01-10 19:06:44 UTC (rev 254356)
@@ -273,6 +273,12 @@
panel->client().updatePanel(status);
}
+void AuthenticatorManager::selectAssertionResponses(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>& responses, CompletionHandler<void(const Ref<WebCore::AuthenticatorAssertionResponse>&)>&& completionHandler)
+{
+ if (auto* panel = m_pendingRequestData.panel.get())
+ panel->client().selectAssertionResponses(responses, WTFMove(completionHandler));
+}
+
UniqueRef<AuthenticatorTransportService> AuthenticatorManager::createService(AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const
{
return AuthenticatorTransportService::create(transport, observer);
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h (254355 => 254356)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h 2020-01-10 19:06:44 UTC (rev 254356)
@@ -81,6 +81,7 @@
void respondReceived(Respond&&) final;
void downgrade(Authenticator* id, Ref<Authenticator>&& downgradedAuthenticator) final;
void authenticatorStatusUpdated(WebAuthenticationStatus) final;
+ void selectAssertionResponses(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const Ref<WebCore::AuthenticatorAssertionResponse>&)>&&) final;
// Overriden by MockAuthenticatorManager.
virtual UniqueRef<AuthenticatorTransportService> createService(WebCore::AuthenticatorTransport, AuthenticatorTransportService::Observer&) const;
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp (254355 => 254356)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp 2020-01-10 19:06:44 UTC (rev 254356)
@@ -158,7 +158,7 @@
auto cmd = static_cast<CtapRequestCommand>(payload[0]);
payload.remove(0);
auto requestMap = CBORReader::read(payload);
- ASSERT(requestMap);
+ ASSERT(requestMap || cmd == CtapRequestCommand::kAuthenticatorGetNextAssertion);
if (cmd == CtapRequestCommand::kAuthenticatorMakeCredential) {
auto it = requestMap->getMap().find(CBORValue(CtapMakeCredentialRequestOptionsKey)); // Find options.
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp (254355 => 254356)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp 2020-01-10 19:06:44 UTC (rev 254356)
@@ -100,9 +100,58 @@
receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) });
return;
}
- receiveRespond(response.releaseNonNull());
+
+ if (response->numberOfCredentials() <= 1) {
+ receiveRespond(response.releaseNonNull());
+ return;
+ }
+
+ m_remainingAssertionResponses = response->numberOfCredentials() - 1;
+ auto addResult = m_assertionResponses.add(response.releaseNonNull());
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
+ driver().transact(encodeEmptyAuthenticatorRequest(CtapRequestCommand::kAuthenticatorGetNextAssertion), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) {
+ ASSERT(RunLoop::isMain());
+ if (!weakThis)
+ return;
+ weakThis->continueGetNextAssertionAfterResponseReceived(WTFMove(data));
+ });
}
+void CtapAuthenticator::continueGetNextAssertionAfterResponseReceived(Vector<uint8_t>&& data)
+{
+ auto response = readCTAPGetAssertionResponse(data);
+ if (!response) {
+ auto error = getResponseCode(data);
+ receiveRespond(ExceptionData { UnknownError, makeString("Unknown internal error. Error code: ", static_cast<uint8_t>(error)) });
+ return;
+ }
+ m_remainingAssertionResponses--;
+ auto addResult = m_assertionResponses.add(response.releaseNonNull());
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
+ if (!m_remainingAssertionResponses) {
+ if (auto* observer = this->observer()) {
+ observer->selectAssertionResponses(m_assertionResponses, [this, weakThis = makeWeakPtr(*this)] (const Ref<AuthenticatorAssertionResponse>& response) {
+ ASSERT(RunLoop::isMain());
+ if (!weakThis)
+ return;
+ auto returnResponse = m_assertionResponses.take(response);
+ if (!returnResponse)
+ return;
+ receiveRespond(WTFMove(*returnResponse));
+ });
+ }
+ return;
+ }
+
+ driver().transact(encodeEmptyAuthenticatorRequest(CtapRequestCommand::kAuthenticatorGetNextAssertion), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) {
+ ASSERT(RunLoop::isMain());
+ if (!weakThis)
+ return;
+ weakThis->continueGetNextAssertionAfterResponseReceived(WTFMove(data));
+ });
+}
+
bool CtapAuthenticator::tryDowngrade()
{
if (m_info.versions().find(ProtocolVersion::kU2f) == m_info.versions().end())
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h (254355 => 254356)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h 2020-01-10 19:06:44 UTC (rev 254356)
@@ -48,6 +48,7 @@
void continueMakeCredentialAfterResponseReceived(Vector<uint8_t>&&) const;
void getAssertion() final;
void continueGetAssertionAfterResponseReceived(Vector<uint8_t>&&);
+ void continueGetNextAssertionAfterResponseReceived(Vector<uint8_t>&&);
bool tryDowngrade();
bool processGoogleLegacyAppIdSupportExtension();
@@ -54,6 +55,8 @@
fido::AuthenticatorGetInfoResponse m_info;
bool m_isDowngraded { false };
+ size_t m_remainingAssertionResponses { 0 };
+ HashSet<Ref<WebCore::AuthenticatorAssertionResponse>> m_assertionResponses;
};
} // namespace WebKit
Modified: trunk/Tools/ChangeLog (254355 => 254356)
--- trunk/Tools/ChangeLog 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Tools/ChangeLog 2020-01-10 19:06:44 UTC (rev 254356)
@@ -1,3 +1,16 @@
+2020-01-10 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Support authenticatorGetNextAssertion
+ https://bugs.webkit.org/show_bug.cgi?id=203346
+ <rdar://problem/56558488>
+
+ Reviewed by Brent Fulgham.
+
+ * TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebCore/FidoTestData.h:
+ Adds new test case for new logic in DeviceResponseConverter.
+
2020-01-10 Jonathan Bedard <[email protected]>
Python 3: Add support to run-webkit-tests (Follow-up fix)
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp (254355 => 254356)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp 2020-01-10 19:06:44 UTC (rev 254356)
@@ -399,8 +399,19 @@
// Leveraging example 5 of section 6.1 of the CTAP spec.
// https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html
-TEST(CTAPResponseTest, TestReadGetAssertionResponse)
+TEST(CTAPResponseTest, TestReadGetAssertionResponse1)
{
+ auto getAssertionResponse = readCTAPGetAssertionResponse(convertBytesToVector(TestData::kDeviceGetAssertionResponseShort, sizeof(TestData::kDeviceGetAssertionResponseShort)));
+ ASSERT_TRUE(getAssertionResponse);
+
+ EXPECT_EQ(getAssertionResponse->authenticatorData()->byteLength(), sizeof(TestData::kCtap2GetAssertionAuthData));
+ EXPECT_EQ(memcmp(getAssertionResponse->authenticatorData()->data(), TestData::kCtap2GetAssertionAuthData, sizeof(TestData::kCtap2GetAssertionAuthData)), 0);
+ EXPECT_EQ(getAssertionResponse->signature()->byteLength(), sizeof(TestData::kCtap2GetAssertionSignature));
+ EXPECT_EQ(memcmp(getAssertionResponse->signature()->data(), TestData::kCtap2GetAssertionSignature, sizeof(TestData::kCtap2GetAssertionSignature)), 0);
+}
+
+TEST(CTAPResponseTest, TestReadGetAssertionResponse2)
+{
auto getAssertionResponse = readCTAPGetAssertionResponse(convertBytesToVector(TestData::kDeviceGetAssertionResponse, sizeof(TestData::kDeviceGetAssertionResponse)));
ASSERT_TRUE(getAssertionResponse);
@@ -408,8 +419,26 @@
EXPECT_EQ(memcmp(getAssertionResponse->authenticatorData()->data(), TestData::kCtap2GetAssertionAuthData, sizeof(TestData::kCtap2GetAssertionAuthData)), 0);
EXPECT_EQ(getAssertionResponse->signature()->byteLength(), sizeof(TestData::kCtap2GetAssertionSignature));
EXPECT_EQ(memcmp(getAssertionResponse->signature()->data(), TestData::kCtap2GetAssertionSignature, sizeof(TestData::kCtap2GetAssertionSignature)), 0);
+ EXPECT_EQ(getAssertionResponse->userHandle()->byteLength(), sizeof(TestData::kCtap2GetAssertionUserHandle));
+ EXPECT_EQ(memcmp(getAssertionResponse->userHandle()->data(), TestData::kCtap2GetAssertionUserHandle, sizeof(TestData::kCtap2GetAssertionUserHandle)), 0);
}
+TEST(CTAPResponseTest, TestReadGetAssertionResponse3)
+{
+ auto getAssertionResponse = readCTAPGetAssertionResponse(convertBytesToVector(TestData::kDeviceGetAssertionResponseLong, sizeof(TestData::kDeviceGetAssertionResponseLong)));
+ ASSERT_TRUE(getAssertionResponse);
+
+ EXPECT_EQ(getAssertionResponse->authenticatorData()->byteLength(), sizeof(TestData::kCtap2GetAssertionAuthData));
+ EXPECT_EQ(memcmp(getAssertionResponse->authenticatorData()->data(), TestData::kCtap2GetAssertionAuthData, sizeof(TestData::kCtap2GetAssertionAuthData)), 0);
+ EXPECT_EQ(getAssertionResponse->signature()->byteLength(), sizeof(TestData::kCtap2GetAssertionSignature));
+ EXPECT_EQ(memcmp(getAssertionResponse->signature()->data(), TestData::kCtap2GetAssertionSignature, sizeof(TestData::kCtap2GetAssertionSignature)), 0);
+ EXPECT_EQ(getAssertionResponse->userHandle()->byteLength(), sizeof(TestData::kCtap2GetAssertionUserHandle));
+ EXPECT_EQ(memcmp(getAssertionResponse->userHandle()->data(), TestData::kCtap2GetAssertionUserHandle, sizeof(TestData::kCtap2GetAssertionUserHandle)), 0);
+ EXPECT_STREQ(getAssertionResponse->name().utf8().data(), "[email protected]");
+ EXPECT_STREQ(getAssertionResponse->displayName().utf8().data(), "John P. Smith");
+ EXPECT_EQ(getAssertionResponse->numberOfCredentials(), 1u);
+}
+
// Test that U2F register response is properly parsed.
TEST(CTAPResponseTest, TestParseRegisterResponseData)
{
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h (254355 => 254356)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h 2020-01-10 19:02:26 UTC (rev 254355)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h 2020-01-10 19:06:44 UTC (rev 254356)
@@ -960,9 +960,133 @@
0x74, 0xc7, 0x47, 0x90, 0xea, 0xab, 0xb1, 0x44, 0x11, 0xe7, 0xa0,
};
+constexpr uint8_t kCtap2GetAssertionUserHandle[] = {
+ 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02,
+ 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82,
+};
+
+constexpr uint8_t kDeviceGetAssertionResponseShort[] = {
+ // Success response code
+ 0x00,
+ // map(3)
+ 0xa3,
+ // unsigned(1) - Credential
+ 0x01,
+ // map(2)
+ 0xa2,
+ // text(2)
+ 0x62,
+ // "id"
+ 0x69, 0x64,
+ // bytes(64)
+ 0x58, 0x40,
+ // credential id
+ 0xf2, 0x20, 0x06, 0xde, 0x4f, 0x90, 0x5a, 0xf6, 0x8a, 0x43, 0x94, 0x2f,
+ 0x02, 0x4f, 0x2a, 0x5e, 0xce, 0x60, 0x3d, 0x9c, 0x6d, 0x4b, 0x3d, 0xf8,
+ 0xbe, 0x08, 0xed, 0x01, 0xfc, 0x44, 0x26, 0x46, 0xd0, 0x34, 0x85, 0x8a,
+ 0xc7, 0x5b, 0xed, 0x3f, 0xd5, 0x80, 0xbf, 0x98, 0x08, 0xd9, 0x4f, 0xcb,
+ 0xee, 0x82, 0xb9, 0xb2, 0xef, 0x66, 0x77, 0xaf, 0x0a, 0xdc, 0xc3, 0x58,
+ 0x52, 0xea, 0x6b, 0x9e,
+ // text(4)
+ 0x64,
+ // "type"
+ 0x74, 0x79, 0x70, 0x65,
+ // text(10)
+ 0x6a,
+ // "public-key"
+ 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79,
+ // unsigned(2) - Auth data
+ 0x02,
+ // bytes(37)
+ 0x58, 0x25,
+ // auth data
+ 0x62, 0x5d, 0xda, 0xdf, 0x74, 0x3f, 0x57, 0x27, 0xe6, 0x6b, 0xba, 0x8c,
+ 0x2e, 0x38, 0x79, 0x22, 0xd1, 0xaf, 0x43, 0xc5, 0x03, 0xd9, 0x11, 0x4a,
+ 0x8f, 0xba, 0x10, 0x4d, 0x84, 0xd0, 0x2b, 0xfa, 0x01, 0x00, 0x00, 0x00,
+ 0x11,
+ // unsigned(3) - signature
+ 0x03,
+ // bytes(71)
+ 0x58, 0x47,
+ // signature
+ 0x30, 0x45, 0x02, 0x20, 0x4a, 0x5a, 0x9d, 0xd3, 0x92, 0x98, 0x14, 0x9d,
+ 0x90, 0x47, 0x69, 0xb5, 0x1a, 0x45, 0x14, 0x33, 0x00, 0x6f, 0x18, 0x2a,
+ 0x34, 0xfb, 0xdf, 0x66, 0xde, 0x5f, 0xc7, 0x17, 0xd7, 0x5f, 0xb3, 0x50,
+ 0x02, 0x21, 0x00, 0xa4, 0x6b, 0x8e, 0xa3, 0xc3, 0xb9, 0x33, 0x82, 0x1c,
+ 0x6e, 0x7f, 0x5e, 0xf9, 0xda, 0xae, 0x94, 0xab, 0x47, 0xf1, 0x8d, 0xb4,
+ 0x74, 0xc7, 0x47, 0x90, 0xea, 0xab, 0xb1, 0x44, 0x11, 0xe7, 0xa0,
+};
+
constexpr uint8_t kDeviceGetAssertionResponse[] = {
// Success response code
0x00,
+ // map(4)
+ 0xa4,
+ // unsigned(1) - Credential
+ 0x01,
+ // map(2)
+ 0xa2,
+ // text(2)
+ 0x62,
+ // "id"
+ 0x69, 0x64,
+ // bytes(64)
+ 0x58, 0x40,
+ // credential id
+ 0xf2, 0x20, 0x06, 0xde, 0x4f, 0x90, 0x5a, 0xf6, 0x8a, 0x43, 0x94, 0x2f,
+ 0x02, 0x4f, 0x2a, 0x5e, 0xce, 0x60, 0x3d, 0x9c, 0x6d, 0x4b, 0x3d, 0xf8,
+ 0xbe, 0x08, 0xed, 0x01, 0xfc, 0x44, 0x26, 0x46, 0xd0, 0x34, 0x85, 0x8a,
+ 0xc7, 0x5b, 0xed, 0x3f, 0xd5, 0x80, 0xbf, 0x98, 0x08, 0xd9, 0x4f, 0xcb,
+ 0xee, 0x82, 0xb9, 0xb2, 0xef, 0x66, 0x77, 0xaf, 0x0a, 0xdc, 0xc3, 0x58,
+ 0x52, 0xea, 0x6b, 0x9e,
+ // text(4)
+ 0x64,
+ // "type"
+ 0x74, 0x79, 0x70, 0x65,
+ // text(10)
+ 0x6a,
+ // "public-key"
+ 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79,
+ // unsigned(2) - Auth data
+ 0x02,
+ // bytes(37)
+ 0x58, 0x25,
+ // auth data
+ 0x62, 0x5d, 0xda, 0xdf, 0x74, 0x3f, 0x57, 0x27, 0xe6, 0x6b, 0xba, 0x8c,
+ 0x2e, 0x38, 0x79, 0x22, 0xd1, 0xaf, 0x43, 0xc5, 0x03, 0xd9, 0x11, 0x4a,
+ 0x8f, 0xba, 0x10, 0x4d, 0x84, 0xd0, 0x2b, 0xfa, 0x01, 0x00, 0x00, 0x00,
+ 0x11,
+ // unsigned(3) - signature
+ 0x03,
+ // bytes(71)
+ 0x58, 0x47,
+ // signature
+ 0x30, 0x45, 0x02, 0x20, 0x4a, 0x5a, 0x9d, 0xd3, 0x92, 0x98, 0x14, 0x9d,
+ 0x90, 0x47, 0x69, 0xb5, 0x1a, 0x45, 0x14, 0x33, 0x00, 0x6f, 0x18, 0x2a,
+ 0x34, 0xfb, 0xdf, 0x66, 0xde, 0x5f, 0xc7, 0x17, 0xd7, 0x5f, 0xb3, 0x50,
+ 0x02, 0x21, 0x00, 0xa4, 0x6b, 0x8e, 0xa3, 0xc3, 0xb9, 0x33, 0x82, 0x1c,
+ 0x6e, 0x7f, 0x5e, 0xf9, 0xda, 0xae, 0x94, 0xab, 0x47, 0xf1, 0x8d, 0xb4,
+ 0x74, 0xc7, 0x47, 0x90, 0xea, 0xab, 0xb1, 0x44, 0x11, 0xe7, 0xa0,
+ // unsigned(4) - publicKeyCredentialUserEntity
+ 0x04,
+ // map(1)
+ 0xa1,
+ // text(2)
+ 0x62,
+ // "id"
+ 0x69, 0x64,
+ // bytes(32) - user id
+ 0x58, 0x20,
+ // user id
+ 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02,
+ 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82,
+};
+
+constexpr uint8_t kDeviceGetAssertionResponseLong[] = {
+ // Success response code
+ 0x00,
// map(5)
0xa5,
// unsigned(1) - Credential
_______________________________________________ webkit-changes mailing list [email protected] https://lists.webkit.org/mailman/listinfo/webkit-changes
