Title: [264543] trunk
Revision
264543
Author
[email protected]
Date
2020-07-17 15:58:51 -0700 (Fri, 17 Jul 2020)

Log Message

[WebAuthn] Cache the PIN to improve NFC user experience
https://bugs.webkit.org/show_bug.cgi?id=213900
<rdar://problem/60073622>

Reviewed by Brent Fulgham.

Source/WebKit:

Cache the PIN to improve NFC user experience. Users might not hold the NFC key against the NFC scanner all the time
while entering the PIN. Therefore, we cache the PIN from the previous connection and immediately return the cached PIN to
the current connection such that users don't need to enter the PIN again.

The only downside for this optimization is that a wrong PIN could be used if the user switch to another authenticator for
the new connection. Given there is no UUID to identify a particular authenticator, there is nothing we can do to resolve the
issue. The probability of the issue, however, should be rare.

Covered by new API tests.

* UIProcess/WebAuthentication/AuthenticatorManager.cpp:
(WebKit::AuthenticatorManager::authenticatorStatusUpdated):
(WebKit::AuthenticatorManager::requestPin):
Where the above logic is implemented.

* UIProcess/WebAuthentication/Cocoa/NfcConnection.mm:
(WebKit::NfcConnection::transact const):
Adds a comment.

* UIProcess/WebAuthentication/WebAuthenticationRequestData.h:
* UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp:
(WebKit::WebAuthenticatorCoordinatorProxy::makeCredential):
(WebKit::WebAuthenticatorCoordinatorProxy::getAssertion):
Adds a field for the cached PIN.

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-pin-disconnect.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (264542 => 264543)


--- trunk/Source/WebKit/ChangeLog	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Source/WebKit/ChangeLog	2020-07-17 22:58:51 UTC (rev 264543)
@@ -1,3 +1,36 @@
+2020-07-17  Jiewen Tan  <[email protected]>
+
+        [WebAuthn] Cache the PIN to improve NFC user experience
+        https://bugs.webkit.org/show_bug.cgi?id=213900
+        <rdar://problem/60073622>
+
+        Reviewed by Brent Fulgham.
+
+        Cache the PIN to improve NFC user experience. Users might not hold the NFC key against the NFC scanner all the time
+        while entering the PIN. Therefore, we cache the PIN from the previous connection and immediately return the cached PIN to
+        the current connection such that users don't need to enter the PIN again.
+
+        The only downside for this optimization is that a wrong PIN could be used if the user switch to another authenticator for
+        the new connection. Given there is no UUID to identify a particular authenticator, there is nothing we can do to resolve the
+        issue. The probability of the issue, however, should be rare.
+
+        Covered by new API tests.
+
+        * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
+        (WebKit::AuthenticatorManager::authenticatorStatusUpdated):
+        (WebKit::AuthenticatorManager::requestPin):
+        Where the above logic is implemented.
+
+        * UIProcess/WebAuthentication/Cocoa/NfcConnection.mm:
+        (WebKit::NfcConnection::transact const):
+        Adds a comment.
+
+        * UIProcess/WebAuthentication/WebAuthenticationRequestData.h:
+        * UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp:
+        (WebKit::WebAuthenticatorCoordinatorProxy::makeCredential):
+        (WebKit::WebAuthenticatorCoordinatorProxy::getAssertion):
+        Adds a field for the cached PIN.
+
 2020-07-17  Per Arne Vollan  <[email protected]>
 
         [iOS] Crash under WebProcess::handleXPCEndpointMessages

Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp (264542 => 264543)


--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp	2020-07-17 22:58:51 UTC (rev 264543)
@@ -264,6 +264,10 @@
 
 void AuthenticatorManager::authenticatorStatusUpdated(WebAuthenticationStatus status)
 {
+    // Immediately invalidate the cache if the PIN is incorrect. A status update often means
+    // an error. We don't really care what kind of error it really is.
+    m_pendingRequestData.cachedPin = String();
+
     dispatchPanelClientCall([status] (const API::WebAuthenticationPanel& panel) {
         panel.client().updatePanel(status);
     });
@@ -271,8 +275,25 @@
 
 void AuthenticatorManager::requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&& completionHandler)
 {
-    dispatchPanelClientCall([retries, completionHandler = WTFMove(completionHandler)] (const API::WebAuthenticationPanel& panel) mutable {
-        panel.client().requestPin(retries, WTFMove(completionHandler));
+    // Cache the PIN to improve NFC user experience so that a momentary movement of the NFC key away from the scanner doesn't
+    // force the PIN entry to be re-entered.
+    // We don't distinguish USB and NFC here becuase there is no harms to have this optimization for USB even though it is useless.
+    if (!m_pendingRequestData.cachedPin.isNull()) {
+        completionHandler(m_pendingRequestData.cachedPin);
+        m_pendingRequestData.cachedPin = String();
+        return;
+    }
+
+    auto callback = [weakThis = makeWeakPtr(*this), this, completionHandler = WTFMove(completionHandler)] (const WTF::String& pin) mutable {
+        if (!weakThis)
+            return;
+
+        m_pendingRequestData.cachedPin = pin;
+        completionHandler(pin);
+    };
+
+    dispatchPanelClientCall([retries, callback = WTFMove(callback)] (const API::WebAuthenticationPanel& panel) mutable {
+        panel.client().requestPin(retries, WTFMove(callback));
     });
 }
 

Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.mm (264542 => 264543)


--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.mm	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.mm	2020-07-17 22:58:51 UTC (rev 264543)
@@ -91,6 +91,7 @@
 Vector<uint8_t> NfcConnection::transact(Vector<uint8_t>&& data) const
 {
     Vector<uint8_t> response;
+    // The method will return an empty NSData if the tag is disconnected.
     auto *responseData = [m_session transceive:adoptNS([[NSData alloc] initWithBytes:data.data() length:data.size()]).get()];
     response.append(reinterpret_cast<const uint8_t*>(responseData.bytes), responseData.length);
     return response;

Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h (264542 => 264543)


--- trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h	2020-07-17 22:58:51 UTC (rev 264543)
@@ -51,6 +51,7 @@
     WTF::Optional<WebCore::GlobalFrameIdentifier> frameID;
     WebKit::FrameInfoData frameInfo;
     bool processingUserGesture;
+    String cachedPin; // Only used to improve NFC Client PIN experience.
 };
 
 WebCore::ClientDataType getClientDataType(const Variant<WebCore::PublicKeyCredentialCreationOptions, WebCore::PublicKeyCredentialRequestOptions>&);

Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp (264542 => 264543)


--- trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp	2020-07-17 22:58:51 UTC (rev 264543)
@@ -57,12 +57,12 @@
 
 void WebAuthenticatorCoordinatorProxy::makeCredential(FrameIdentifier frameId, FrameInfoData&& frameInfo, Vector<uint8_t>&& hash, PublicKeyCredentialCreationOptions&& options, bool processingUserGesture, RequestCompletionHandler&& handler)
 {
-    handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture }, WTFMove(handler));
+    handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture, String() }, WTFMove(handler));
 }
 
 void WebAuthenticatorCoordinatorProxy::getAssertion(FrameIdentifier frameId, FrameInfoData&& frameInfo, Vector<uint8_t>&& hash, PublicKeyCredentialRequestOptions&& options, bool processingUserGesture, RequestCompletionHandler&& handler)
 {
-    handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture }, WTFMove(handler));
+    handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture, String() }, WTFMove(handler));
 }
 
 void WebAuthenticatorCoordinatorProxy::handleRequest(WebAuthenticationRequestData&& data, RequestCompletionHandler&& handler)

Modified: trunk/Tools/ChangeLog (264542 => 264543)


--- trunk/Tools/ChangeLog	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Tools/ChangeLog	2020-07-17 22:58:51 UTC (rev 264543)
@@ -1,3 +1,16 @@
+2020-07-17  Jiewen Tan  <[email protected]>
+
+        [WebAuthn] Cache the PIN to improve NFC user experience
+        https://bugs.webkit.org/show_bug.cgi?id=213900
+        <rdar://problem/60073622>
+
+        Reviewed by Brent Fulgham.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-pin-disconnect.html: Added.
+
 2020-07-17  Wenson Hsieh  <[email protected]>
 
         Recommended article titles on csdn.net are clipped after translating to English

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (264542 => 264543)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-07-17 22:58:51 UTC (rev 264543)
@@ -373,6 +373,7 @@
 		5742178E2400D2DF002B303D /* web-authentication-make-credential-la.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5742178D2400D26C002B303D /* web-authentication-make-credential-la.html */; };
 		574F55D2204D47F0002948C6 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 574F55D0204D471C002948C6 /* Security.framework */; };
 		5751B28A249D5BC500664C2A /* web-authentication-make-credential-hid-pin-get-pin-token-fake-pin-invalid-error-retry.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5751B289249D5B9900664C2A /* web-authentication-make-credential-hid-pin-get-pin-token-fake-pin-invalid-error-retry.html */; };
+		57537EE824BEA05F0048DBA5 /* web-authentication-get-assertion-nfc-pin-disconnect.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 57537EE724BEA0190048DBA5 /* web-authentication-get-assertion-nfc-pin-disconnect.html */; };
 		5758597F23A2527A00C74572 /* CtapPinTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5758597E23A2527A00C74572 /* CtapPinTest.cpp */; };
 		5758598423C3C3A400C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5758598323C3C36200C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html */; };
 		57599E211F07191900A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm in Sources */ = {isa = PBXBuildFile; fileRef = 57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */; };
@@ -1602,6 +1603,7 @@
 				57EDFC60245A299C00959521 /* web-authentication-get-assertion-la-no-mock.html in Copy Resources */,
 				572CEF71240F874700C412A2 /* web-authentication-get-assertion-la.html in Copy Resources */,
 				579833922368FA37008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html in Copy Resources */,
+				57537EE824BEA05F0048DBA5 /* web-authentication-get-assertion-nfc-pin-disconnect.html in Copy Resources */,
 				57663DEA234EA66D00E85E09 /* web-authentication-get-assertion-nfc.html in Copy Resources */,
 				577454D22359BB01008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html in Copy Resources */,
 				57C624502346C21E00383FE7 /* web-authentication-get-assertion.html in Copy Resources */,
@@ -2076,6 +2078,7 @@
 		5742178D2400D26C002B303D /* web-authentication-make-credential-la.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-la.html"; sourceTree = "<group>"; };
 		574F55D0204D471C002948C6 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
 		5751B289249D5B9900664C2A /* web-authentication-make-credential-hid-pin-get-pin-token-fake-pin-invalid-error-retry.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin-get-pin-token-fake-pin-invalid-error-retry.html"; sourceTree = "<group>"; };
+		57537EE724BEA0190048DBA5 /* web-authentication-get-assertion-nfc-pin-disconnect.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-get-assertion-nfc-pin-disconnect.html"; sourceTree = "<group>"; };
 		5758597D23A2527A00C74572 /* CtapPinTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CtapPinTest.h; sourceTree = "<group>"; };
 		5758597E23A2527A00C74572 /* CtapPinTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CtapPinTest.cpp; sourceTree = "<group>"; };
 		5758598323C3C36200C74572 /* web-authentication-make-credential-hid-pin-get-retries-error.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-hid-pin-get-retries-error.html"; sourceTree = "<group>"; };
@@ -3784,6 +3787,7 @@
 				57EDFC5F245A279900959521 /* web-authentication-get-assertion-la-no-mock.html */,
 				572CEF70240F86AE00C412A2 /* web-authentication-get-assertion-la.html */,
 				5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */,
+				57537EE724BEA0190048DBA5 /* web-authentication-get-assertion-nfc-pin-disconnect.html */,
 				57663DE9234EA60B00E85E09 /* web-authentication-get-assertion-nfc.html */,
 				577454D12359BAD5008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html */,
 				57C6244F2346C1EC00383FE7 /* web-authentication-get-assertion.html */,

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm (264542 => 264543)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm	2020-07-17 22:57:05 UTC (rev 264542)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm	2020-07-17 22:58:51 UTC (rev 264543)
@@ -1158,6 +1158,25 @@
     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
 }
 
+#if HAVE(NEAR_FIELD)
+TEST(WebAuthenticationPanel, NfcPinCachedDisconnect)
+{
+    reset();
+    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-nfc-pin-disconnect" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
+    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    webAuthenticationPanelPin = "1234";
+    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
+    [webView waitForMessage:@"Succeeded!"];
+}
+#endif // HAVE(NEAR_FIELD)
+
 TEST(WebAuthenticationPanel, MultipleAccountsNullDelegate)
 {
     reset();

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-pin-disconnect.html (0 => 264543)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-pin-disconnect.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-pin-disconnect.html	2020-07-17 22:58:51 UTC (rev 264543)
@@ -0,0 +1,34 @@
+<input type="text" id="input">
+<script>
+    const testNfcCtapVersionBase64 = "RklET18yXzCQAA==";
+    const testGetInfoResponseApduBase64 =
+        "AKYBgmZVMkZfVjJoRklET18yXzACgWtobWFjLXNlY3JldANQbUS6m/bsLkm5MAyP" +
+        "6SDLcwSkYnJr9WJ1cPVkcGxhdPRpY2xpZW50UGlu9QUZBLAGgQGQAA==";
+    const testCtapPinAuthInvalidErrorBase64 = "M5AA";
+    const testPinGetRetriesResponseBase64 = "AKEDCJAA";
+    const testPinGetKeyAgreementResponseBase64 = "AKEBpQECAzgYIAEhWCDodiWJbuTkbcAydm6Ah5YvNt+d/otWfzdjAVsZkKYOFCJYICfeYS1mQYvaGVBYHrxcjB2tcQyxTCL4yXBF9GEvsgyRkAA=";
+    const testPinGetPinTokenResponseBase64 = "AKECUBOk7rcOyRrqAB6TFvYeQfeQAA==";
+    const testAssertionMessageBase64 =
+        "AKQBomJpZFDmAkMt8gsltnzy15Zp9MbpZHR5cGVqcHVibGljLWtleQJYJeRTKdA6" +
+        "IGjRyvf3uwrpVOaw5iWXRfMvSCn3UPBQEfnCBQAAAGcDWEcwRQIgGGBmLZRfmUfs" +
+        "uB3H2yBZTnRhBacx68E+XWFgEQ0oayUCIQCrEBEg7t9//lVkK68mSFNGaBUpRhLI" +
+        "8YfFb+82Pzf6SAShYmlkT2JvYkBleGFtcGxlLmNvbZAA"
+    if (window.internals) {
+        internals.setMockWebAuthenticationConfiguration({ silentFailure: true, nfc: { payloadBase64: [testNfcCtapVersionBase64, testGetInfoResponseApduBase64, testCtapPinAuthInvalidErrorBase64, testPinGetRetriesResponseBase64, testPinGetKeyAgreementResponseBase64, "", testNfcCtapVersionBase64, testGetInfoResponseApduBase64, testCtapPinAuthInvalidErrorBase64, testPinGetRetriesResponseBase64, testPinGetKeyAgreementResponseBase64, testPinGetPinTokenResponseBase64, testAssertionMessageBase64] } });
+        internals.withUserGesture(() => { input.focus(); });
+    }
+
+    const options = {
+        publicKey: {
+            challenge: new Uint8Array(16),
+        }
+    };
+
+    navigator.credentials.get(options).then(credential => {
+        // console.log("Succeeded!");
+        window.webkit.messageHandlers.testHandler.postMessage("Succeeded!");
+    }, error => {
+        // console.log(error.message);
+        window.webkit.messageHandlers.testHandler.postMessage(error.message);
+    });
+</script>
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to