[WebAuthn] We should pass extensions to ASC if possible
https://bugs.webkit.org/show_bug.cgi?id=235533
rdar://87169406

Reviewed by Brent Fulgham.

This patch starts passing WebAuthn extensions to ASC if possible,
in order to support the googleLegacyAppidSupport extension, which
is required to register security keys on google.com. It also starts
passing the attestationPreference option, which was not being passed before.

Tested manually. Previous version of patch contained
TestWebKitAPI.WebAuthenticationPanel.PublicKeyCredentialRequestOptionsASC
and TestWebKitAPI.WebAuthenticationPanel.PublicKeyCredentialCreationOptionsASC,
but were removed due to difficulty softlinking from tests.

* Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h:
* UIProcess/API/Cocoa/_WKAuthenticationExtensionsClientInputs.h:
* UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm:
(authenticationExtensionsClientInputs):
* UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.h:
* UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.mm:
* UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm:
(WebKit::toNSString):
(WebKit::toASCExtensions):
(WebKit::configureRegistrationRequestContext):
(WebKit::configurationAssertionRequestContext):
* UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h:
* WebKit.xcodeproj/project.pbxproj:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@288652 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index f9adf43..8ee9037 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,35 @@
+2022-01-26  J Pascoe  <j_pascoe@apple.com>
+
+        [WebAuthn] We should pass extensions to ASC if possible
+        https://bugs.webkit.org/show_bug.cgi?id=235533
+        rdar://87169406
+
+        Reviewed by Brent Fulgham.
+
+        This patch starts passing WebAuthn extensions to ASC if possible,
+        in order to support the googleLegacyAppidSupport extension, which
+        is required to register security keys on google.com. It also starts
+        passing the attestationPreference option, which was not being passed before.
+
+        Tested manually. Previous version of patch contained
+        TestWebKitAPI.WebAuthenticationPanel.PublicKeyCredentialRequestOptionsASC
+        and TestWebKitAPI.WebAuthenticationPanel.PublicKeyCredentialCreationOptionsASC,
+        but were removed due to difficulty softlinking from tests.
+
+        * Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h:
+        * UIProcess/API/Cocoa/_WKAuthenticationExtensionsClientInputs.h:
+        * UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm:
+        (authenticationExtensionsClientInputs):
+        * UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.h:
+        * UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.mm:
+        * UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm:
+        (WebKit::toNSString):
+        (WebKit::toASCExtensions):
+        (WebKit::configureRegistrationRequestContext):
+        (WebKit::configurationAssertionRequestContext):
+        * UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h:
+        * WebKit.xcodeproj/project.pbxproj:
+
 2022-01-26  Alexander Mikhaylenko  <alexm@gnome.org>
 
         [GTK3] Pinch zooming from a link activates it
diff --git a/Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h b/Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h
index 580fcdc..d22ab2c 100644
--- a/Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h
+++ b/Source/WebKit/Platform/spi/Cocoa/AuthenticationServicesCoreSPI.h
@@ -133,6 +133,17 @@
 
 @end
 
+@class ASCWebAuthenticationExtensionsClientInputs;
+
+@interface ASCWebAuthenticationExtensionsClientInputs : NSObject <NSCopying, NSSecureCoding>
+
+- (instancetype)initWithAppID:(NSString * _Nullable)appID isGoogleLegacyAppIDSupport:(BOOL)isGoogleLegacyAppIDSupport NS_DESIGNATED_INITIALIZER;
+
+@property (nonatomic, nullable, copy) NSString *appID;
+@property (nonatomic) BOOL isGoogleLegacyAppIDSupport;
+
+@end
+
 @class ASCPublicKeyCredentialDescriptor;
 
 typedef NS_ENUM(NSUInteger, ASCPublicKeyCredentialKind) {
@@ -152,6 +163,7 @@
 // If clientDataHash is null, then gets generated from challenge and relyingPartyIdentifier.
 @property (nonatomic, nullable, copy) NSData *clientDataHash;
 @property (nonatomic, nullable, readonly, copy) NSString *userVerificationPreference;
+@property (nonatomic, nullable, copy) ASCWebAuthenticationExtensionsClientInputs *extensions;
 
 @property (nonatomic, nullable, readonly, copy) NSArray<ASCPublicKeyCredentialDescriptor *> *allowedCredentials;
 
@@ -178,6 +190,8 @@
 @property (nonatomic, copy) NSString *userDisplayName;
 @property (nonatomic, copy) NSArray<NSNumber *> *supportedAlgorithmIdentifiers;
 @property (nonatomic, nullable, copy) NSString *userVerificationPreference;
+@property (nonatomic, nullable, copy) NSString *attestationPreference;
+@property (nonatomic, nullable, copy) ASCWebAuthenticationExtensionsClientInputs *extensions;
 
 @property (nonatomic) BOOL shouldRequireResidentKey;
 @property (nonatomic, copy) NSArray<ASCPublicKeyCredentialDescriptor *> *excludedCredentials;
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKAuthenticationExtensionsClientInputs.h b/Source/WebKit/UIProcess/API/Cocoa/_WKAuthenticationExtensionsClientInputs.h
index 165096b..f7a9166 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/_WKAuthenticationExtensionsClientInputs.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKAuthenticationExtensionsClientInputs.h
@@ -35,6 +35,7 @@
 @interface _WKAuthenticationExtensionsClientInputs : NSObject
 
 @property (nullable, nonatomic, copy) NSString *appid;
+@property (nonatomic) BOOL googleLegacyAppidSupport;
 
 @end
 
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm
index bb6a8de..d96fdc2 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm
@@ -525,7 +525,7 @@
 {
     WebCore::AuthenticationExtensionsClientInputs result;
     result.appid = extensions.appid;
-    result.googleLegacyAppidSupport = false;
+    result.googleLegacyAppidSupport = extensions.googleLegacyAppidSupport;
 
     return result;
 }
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.h b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.h
index b3a79c07..7b69878 100644
--- a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.h
+++ b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.h
@@ -40,6 +40,7 @@
 SOFT_LINK_CLASS_FOR_HEADER(WebKit, ASCAuthorizationPresenter);
 SOFT_LINK_CLASS_FOR_HEADER(WebKit, ASCAuthorizationRemotePresenter);
 SOFT_LINK_CLASS_FOR_HEADER(WebKit, ASCCredentialRequestContext);
+SOFT_LINK_CLASS_FOR_HEADER(WebKit, ASCWebAuthenticationExtensionsClientInputs);
 SOFT_LINK_CLASS_FOR_HEADER(WebKit, ASCPlatformPublicKeyCredentialAssertion);
 SOFT_LINK_CLASS_FOR_HEADER(WebKit, ASCPlatformPublicKeyCredentialLoginChoice);
 SOFT_LINK_CLASS_FOR_HEADER(WebKit, ASCPlatformPublicKeyCredentialRegistration);
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.mm b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.mm
index a23ac53..0bb6fdfd 100644
--- a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.mm
+++ b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/AuthenticationServicesCoreSoftLink.mm
@@ -40,6 +40,7 @@
 SOFT_LINK_CLASS_FOR_SOURCE(WebKit, AuthenticationServicesCore, ASCAuthorizationPresenter);
 SOFT_LINK_CLASS_FOR_SOURCE(WebKit, AuthenticationServicesCore, ASCAuthorizationRemotePresenter);
 SOFT_LINK_CLASS_FOR_SOURCE(WebKit, AuthenticationServicesCore, ASCCredentialRequestContext);
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL(WebKit, AuthenticationServicesCore, ASCWebAuthenticationExtensionsClientInputs);
 SOFT_LINK_CLASS_FOR_SOURCE(WebKit, AuthenticationServicesCore, ASCPlatformPublicKeyCredentialAssertion);
 SOFT_LINK_CLASS_FOR_SOURCE(WebKit, AuthenticationServicesCore, ASCPlatformPublicKeyCredentialLoginChoice);
 SOFT_LINK_CLASS_FOR_SOURCE(WebKit, AuthenticationServicesCore, ASCPlatformPublicKeyCredentialRegistration);
diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm
index ed32c8b..c5c394a 100644
--- a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm
+++ b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticatorCoordinatorProxy.mm
@@ -69,6 +69,20 @@
     return @"preferred";
 }
 
+static inline RetainPtr<NSString> toNSString(AttestationConveyancePreference attestationConveyancePreference)
+{
+    switch (attestationConveyancePreference) {
+    case AttestationConveyancePreference::Direct:
+        return @"direct";
+    case AttestationConveyancePreference::Indirect:
+        return @"indirect";
+    case AttestationConveyancePreference::None:
+        return @"none";
+    }
+
+    return @"none";
+}
+
 static inline ExceptionCode toExceptionCode(NSInteger nsErrorCode)
 {
     ExceptionCode exceptionCode = (ExceptionCode)nsErrorCode;
@@ -150,6 +164,14 @@
     return adoptNS([allocASCPublicKeyCredentialDescriptorInstance() initWithCredentialID:WebCore::toNSData(descriptor.id).get() transports:transports.get()]);
 }
 
+static inline RetainPtr<ASCWebAuthenticationExtensionsClientInputs> toASCExtensions(const AuthenticationExtensionsClientInputs& extensions)
+{
+    if ([allocASCWebAuthenticationExtensionsClientInputsInstance() respondsToSelector:@selector(initWithAppID:isGoogleLegacyAppIDSupport:)])
+        return adoptNS([allocASCWebAuthenticationExtensionsClientInputsInstance() initWithAppID:extensions.appid isGoogleLegacyAppIDSupport:extensions.googleLegacyAppidSupport]);
+
+    return nil;
+}
+
 static RetainPtr<ASCCredentialRequestContext> configureRegistrationRequestContext(const PublicKeyCredentialCreationOptions& options, Vector<uint8_t> hash)
 {
     ASCCredentialRequestTypes requestTypes = ASCCredentialRequestTypePlatformPublicKeyRegistration | ASCCredentialRequestTypeSecurityKeyPublicKeyRegistration;
@@ -184,6 +206,7 @@
     [credentialCreationOptions setUserDisplayName:options.user.displayName];
     [credentialCreationOptions setUserVerificationPreference:userVerification.get()];
     [credentialCreationOptions setShouldRequireResidentKey:shouldRequireResidentKey];
+    [credentialCreationOptions setAttestationPreference:toNSString(options.attestation).get()];
 
     RetainPtr<NSMutableArray<NSNumber *>> supportedAlgorithmIdentifiers = adoptNS([[NSMutableArray alloc] initWithCapacity:options.pubKeyCredParams.size()]);
     for (PublicKeyCredentialCreationOptions::Parameters algorithmParameter : options.pubKeyCredParams)
@@ -207,6 +230,9 @@
     if (requestTypes & ASCCredentialRequestTypeSecurityKeyPublicKeyRegistration)
         [requestContext setSecurityKeyCredentialCreationOptions:credentialCreationOptions.get()];
 
+    if (options.extensions && [credentialCreationOptions respondsToSelector:@selector(setExtensions:)])
+        [credentialCreationOptions setExtensions:toASCExtensions(*options.extensions).get()];
+
     return requestContext;
 }
 
@@ -244,6 +270,8 @@
             auto challenge = WebCore::toNSData(options.challenge);
             [assertionOptions initWithKind:ASCPublicKeyCredentialKindPlatform relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()];
         }
+        if (options.extensions && [assertionOptions respondsToSelector:@selector(setExtensions:)])
+            [assertionOptions setExtensions:toASCExtensions(*options.extensions).get()];
 
         [requestContext setPlatformKeyCredentialAssertionOptions:assertionOptions.get()];
     }
@@ -257,6 +285,9 @@
             auto challenge = WebCore::toNSData(options.challenge);
             [assertionOptions initWithKind:ASCPublicKeyCredentialKindSecurityKey relyingPartyIdentifier:options.rpId challenge:challenge.get() userVerificationPreference:userVerification.get() allowedCredentials:allowedCredentials.get()];
         }
+        if (options.extensions && [assertionOptions respondsToSelector:@selector(setExtensions:)])
+            [assertionOptions setExtensions:toASCExtensions(*options.extensions).get()];
+
         [requestContext setSecurityKeyCredentialAssertionOptions:assertionOptions.get()];
     }
 
diff --git a/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h b/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h
index 1a437da..86971da 100644
--- a/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h
+++ b/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.h
@@ -80,7 +80,7 @@
     RetainPtr<ASCCredentialRequestContext> contextForRequest(WebAuthenticationRequestData&&);
     void performRequest(RetainPtr<ASCCredentialRequestContext>, RequestCompletionHandler&&);
     RetainPtr<ASCAuthorizationRemotePresenter> m_presenter;
-#endif
+#endif // HAVE(UNIFIED_ASC_AUTH_UI)
 };
 
 } // namespace WebKit