<rdar://problem/8773946> and https://bugs.webkit.org/show_bug.cgi?id=59614
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Apr 2011 19:12:32 +0000 (19:12 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Apr 2011 19:12:32 +0000 (19:12 +0000)
Client certificate authentication in WebKit2

Reviewed by Sam Weinig.

Project-file stuff:
* WebKit2.xcodeproj/project.pbxproj:

Allow WKCredentials to store certificates:
* UIProcess/Authentication/WebCredential.cpp:
(WebKit::WebCredential::WebCredential):
(WebKit::WebCredential::certificateInfo):
* UIProcess/Authentication/WebCredential.h:
(WebKit::WebCredential::create):
* UIProcess/API/C/WKCredential.cpp:
(WKCredentialCreateWithCertificateInfo):
* UIProcess/API/C/WKCredential.h:

Pass the certificate info over the wire to the WebProcess:
* UIProcess/Authentication/AuthenticationChallengeProxy.cpp:
(WebKit::AuthenticationChallengeProxy::useCredential):

Change the WebProcess to prefer certificate info over basic credentials when responding to a challenge:
* WebProcess/Authentication/AuthenticationManager.cpp:
(WebKit::AuthenticationManager::tryUsePlatformCertificateInfoForChallenge): Stub for platforms other than Mac,
  as only Mac can currently respond to challenges with certificates.
(WebKit::AuthenticationManager::useCredentialForChallenge):
* WebProcess/Authentication/AuthenticationManager.h:
* WebProcess/Authentication/AuthenticationManager.messages.in:
* WebProcess/Authentication/mac: Added.
* WebProcess/Authentication/mac/AuthenticationManager.mac.mm: Added.
(WebKit::AuthenticationManager::tryUsePlatformCertificateInfoForChallenge): Recreate the identity and certificate
  chain and respond to the challenge with it.

Add a newly required #include:
* UIProcess/API/C/WKAuthenticationChallenge.cpp:
* UIProcess/Authentication/AuthenticationDecisionListener.cpp:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@85223 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/C/WKAuthenticationChallenge.cpp
Source/WebKit2/UIProcess/API/C/WKCredential.cpp
Source/WebKit2/UIProcess/API/C/WKCredential.h
Source/WebKit2/UIProcess/Authentication/AuthenticationChallengeProxy.cpp
Source/WebKit2/UIProcess/Authentication/AuthenticationDecisionListener.cpp
Source/WebKit2/UIProcess/Authentication/WebCredential.cpp
Source/WebKit2/UIProcess/Authentication/WebCredential.h
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Source/WebKit2/WebProcess/Authentication/AuthenticationManager.cpp
Source/WebKit2/WebProcess/Authentication/AuthenticationManager.h
Source/WebKit2/WebProcess/Authentication/AuthenticationManager.messages.in
Source/WebKit2/WebProcess/Authentication/mac/AuthenticationManager.mac.mm [new file with mode: 0644]

index 23b29a5..0a5be43 100644 (file)
@@ -1,3 +1,43 @@
+2011-04-28  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/8773946> and https://bugs.webkit.org/show_bug.cgi?id=59614
+        Client certificate authentication in WebKit2
+
+        Project-file stuff:
+        * WebKit2.xcodeproj/project.pbxproj:
+
+        Allow WKCredentials to store certificates:
+        * UIProcess/Authentication/WebCredential.cpp:
+        (WebKit::WebCredential::WebCredential):
+        (WebKit::WebCredential::certificateInfo):
+        * UIProcess/Authentication/WebCredential.h:
+        (WebKit::WebCredential::create):
+        * UIProcess/API/C/WKCredential.cpp:
+        (WKCredentialCreateWithCertificateInfo):
+        * UIProcess/API/C/WKCredential.h:
+
+        Pass the certificate info over the wire to the WebProcess:
+        * UIProcess/Authentication/AuthenticationChallengeProxy.cpp:
+        (WebKit::AuthenticationChallengeProxy::useCredential): 
+
+        Change the WebProcess to prefer certificate info over basic credentials when responding to a challenge:
+        * WebProcess/Authentication/AuthenticationManager.cpp:
+        (WebKit::AuthenticationManager::tryUsePlatformCertificateInfoForChallenge): Stub for platforms other than Mac,
+          as only Mac can currently respond to challenges with certificates.
+        (WebKit::AuthenticationManager::useCredentialForChallenge):
+        * WebProcess/Authentication/AuthenticationManager.h:
+        * WebProcess/Authentication/AuthenticationManager.messages.in:
+        * WebProcess/Authentication/mac: Added.
+        * WebProcess/Authentication/mac/AuthenticationManager.mac.mm: Added.
+        (WebKit::AuthenticationManager::tryUsePlatformCertificateInfoForChallenge): Recreate the identity and certificate
+          chain and respond to the challenge with it.
+
+        Add a newly required #include:
+        * UIProcess/API/C/WKAuthenticationChallenge.cpp:
+        * UIProcess/Authentication/AuthenticationDecisionListener.cpp:
+
 2011-04-28  Martin Robinson  <mrobinson@igalia.com>
 
         Reviewed by Xan Lopez.
index 5319c2a..c42b857 100644 (file)
@@ -27,6 +27,7 @@
 #include "WKAuthenticationChallenge.h"
 
 #include "AuthenticationChallengeProxy.h"
+#include "WebCertificateInfo.h"
 #include "WebCredential.h"
 #include "WebProtectionSpace.h"
 #include "WKAPICast.h"
index 997fd7a..fb8cbe4 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "WKCredential.h"
 
+#include "WebCertificateInfo.h"
 #include "WebCredential.h"
 #include "WebString.h"
 #include "WKAPICast.h"
@@ -43,6 +44,12 @@ WKCredentialRef WKCredentialCreate(WKStringRef username, WKStringRef password, W
     return toAPI(credential.release().releaseRef());
 }
 
+WKCredentialRef WKCredentialCreateWithCertificateInfo(WKCertificateInfoRef certificateInfo)
+{
+    RefPtr<WebCredential> credential = WebCredential::create(toImpl(certificateInfo));
+    return toAPI(credential.release().releaseRef());
+}
+
 WKStringRef WKCredentialCopyUser(WKCredentialRef credentialRef)
 {
     return toCopiedAPI(toImpl(credentialRef)->user());
index 8b2602e..560fc41 100644 (file)
@@ -36,6 +36,8 @@ extern "C" {
 WK_EXPORT WKTypeID WKCredentialGetTypeID();
 
 WK_EXPORT WKCredentialRef WKCredentialCreate(WKStringRef username, WKStringRef password, WKCredentialPersistence);
+WK_EXPORT WKCredentialRef WKCredentialCreateWithCertificateInfo(WKCertificateInfoRef certificateInfo);
+
 WK_EXPORT WKStringRef WKCredentialCopyUser(WKCredentialRef);
 
 #ifdef __cplusplus
index ecff862..7f4e958 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "AuthenticationDecisionListener.h"
 #include "AuthenticationManagerMessages.h"
+#include "WebCertificateInfo.h"
 #include "WebCoreArgumentCoders.h"
 #include "WebCredential.h"
 #include "WebPageProxy.h"
@@ -63,8 +64,11 @@ void AuthenticationChallengeProxy::useCredential(WebCredential* credential)
 
     if (!credential)
         m_process->send(Messages::AuthenticationManager::ContinueWithoutCredentialForChallenge(m_challengeID), 0);
-    else 
-        m_process->send(Messages::AuthenticationManager::UseCredentialForChallenge(m_challengeID, credential->core()), 0);
+    else {
+        WebCertificateInfo* certificateInfo = credential->certificateInfo();
+        PlatformCertificateInfo platformInfo = certificateInfo ? certificateInfo->platformCertificateInfo() : PlatformCertificateInfo();
+        m_process->send(Messages::AuthenticationManager::UseCredentialForChallenge(m_challengeID, credential->core(), platformInfo), 0);
+    }
 
     m_challengeID = 0;
 }
index a3987cd..00cd874 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "AuthenticationChallengeProxy.h"
 #include "AuthenticationManagerMessages.h"
+#include "WebCertificateInfo.h"
 #include "WebCredential.h"
 #include "WebPageProxy.h"
 #include "WebProcessProxy.h"
index 0b429a7..6d70c5f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "WebCredential.h"
 
+#include "WebCertificateInfo.h"
+
 namespace WebKit {
 
 WebCredential::WebCredential(const WebCore::Credential& credential)
@@ -33,6 +35,16 @@ WebCredential::WebCredential(const WebCore::Credential& credential)
 {
 }
 
+WebCredential::WebCredential(WebCertificateInfo* certificateInfo)
+    : m_certificateInfo(certificateInfo)
+{
+}
+
+WebCertificateInfo* WebCredential::certificateInfo()
+{
+    return m_certificateInfo.get();
+}
+
 const WebCore::Credential& WebCredential::core()
 {
     return m_coreCredential;
index 7beac04..b07a8a6 100644 (file)
@@ -35,6 +35,8 @@
 
 namespace WebKit {
 
+class WebCertificateInfo;
+
 class WebCredential : public APIObject {
 public:
     static const Type APIType = TypeCredential;
@@ -48,17 +50,26 @@ public:
     {
         return adoptRef(new WebCredential(WebCore::Credential(username->string(), password->string(), persistence)));
     }
+
+    static PassRefPtr<WebCredential> create(WebCertificateInfo* certificateInfo)
+    {
+        return adoptRef(new WebCredential(certificateInfo));
+    }
     
+    WebCertificateInfo* certificateInfo();
+
     const WebCore::Credential& core();
 
     const String& user() const;
     
 private:
     WebCredential(const WebCore::Credential&);
+    WebCredential(WebCertificateInfo*);
 
     virtual Type type() const { return APIType; }
 
     WebCore::Credential m_coreCredential;
+    RefPtr<WebCertificateInfo> m_certificateInfo;
 };
 
 } // namespace WebKit
index 0466e14..700c46b 100644 (file)
                51ACBBA1127A8F2C00D203B9 /* WebContextMenuProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51ACBB9F127A8F2C00D203B9 /* WebContextMenuProxyMac.mm */; };
                51B3005012529D0E000B5CA0 /* WebBackForwardListCF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51B3004E12529D0E000B5CA0 /* WebBackForwardListCF.cpp */; };
                51B3005112529D0E000B5CA0 /* WebPageProxyCF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51B3004F12529D0E000B5CA0 /* WebPageProxyCF.cpp */; };
+               51C4032C136749D800DC972D /* AuthenticationManager.mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51C4032B136749D800DC972D /* AuthenticationManager.mac.mm */; };
                51D02F64132EC5B900BEAA96 /* WebIconDatabaseMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51D02F63132EC5B900BEAA96 /* WebIconDatabaseMessageReceiver.cpp */; };
                51D02F6A132EC73700BEAA96 /* WebIconDatabaseMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 51D02F67132EC73700BEAA96 /* WebIconDatabaseMessages.h */; };
                51D02F6B132EC73700BEAA96 /* WebIconDatabaseProxyMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51D02F68132EC73700BEAA96 /* WebIconDatabaseProxyMessageReceiver.cpp */; };
                51ACBB9F127A8F2C00D203B9 /* WebContextMenuProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebContextMenuProxyMac.mm; sourceTree = "<group>"; };
                51B3004E12529D0E000B5CA0 /* WebBackForwardListCF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebBackForwardListCF.cpp; path = cf/WebBackForwardListCF.cpp; sourceTree = "<group>"; };
                51B3004F12529D0E000B5CA0 /* WebPageProxyCF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebPageProxyCF.cpp; path = cf/WebPageProxyCF.cpp; sourceTree = "<group>"; };
+               51C4032B136749D800DC972D /* AuthenticationManager.mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AuthenticationManager.mac.mm; path = mac/AuthenticationManager.mac.mm; sourceTree = "<group>"; };
                51D02F63132EC5B900BEAA96 /* WebIconDatabaseMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebIconDatabaseMessageReceiver.cpp; sourceTree = "<group>"; };
                51D02F65132EC6D300BEAA96 /* WebIconDatabaseProxy.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = WebIconDatabaseProxy.messages.in; path = IconDatabase/WebIconDatabaseProxy.messages.in; sourceTree = "<group>"; };
                51D02F67132EC73700BEAA96 /* WebIconDatabaseMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebIconDatabaseMessages.h; sourceTree = "<group>"; };
                512F588612A8834700629530 /* Authentication */ = {
                        isa = PBXGroup;
                        children = (
+                               51C4032A136749C400DC972D /* mac */,
                                512F588712A8836600629530 /* AuthenticationManager.cpp */,
                                512F588812A8836600629530 /* AuthenticationManager.h */,
                                512F588912A8836600629530 /* AuthenticationManager.messages.in */,
                        name = cf;
                        sourceTree = "<group>";
                };
+               51C4032A136749C400DC972D /* mac */ = {
+                       isa = PBXGroup;
+                       children = (
+                               51C4032B136749D800DC972D /* AuthenticationManager.mac.mm */,
+                       );
+                       name = mac;
+                       sourceTree = "<group>";
+               };
                51FBB9C1132E079200F327B4 /* IconDatabase */ = {
                        isa = PBXGroup;
                        children = (
                                E179FD9F134D38250015B883 /* ArgumentCodersMac.mm in Sources */,
                                31EA25D2134F78C0005B1452 /* NativeWebMouseEventMac.mm in Sources */,
                                CD5C66A0134B9D38004FE2A8 /* InjectedBundlePageFullScreenClient.cpp in Sources */,
+                               51C4032C136749D800DC972D /* AuthenticationManager.mac.mm in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index e7550d0..aa76a29 100644 (file)
@@ -81,10 +81,22 @@ void AuthenticationManager::didReceiveAuthenticationChallenge(Download* download
     download->send(Messages::DownloadProxy::DidReceiveAuthenticationChallenge(authenticationChallenge, challengeID));
 }
 
-void AuthenticationManager::useCredentialForChallenge(uint64_t challengeID, const Credential& credential)
+// Currently, only Mac knows how to respond to authentication challenges with certificate info.
+#if !PLATFORM(MAC)
+bool AuthenticationManager::tryUsePlatformCertificateInfoForChallenge(const WebCore::AuthenticationChallenge&, const PlatformCertificateInfo&)
+{
+    return false;
+}
+#endif
+
+void AuthenticationManager::useCredentialForChallenge(uint64_t challengeID, const Credential& credential, const PlatformCertificateInfo& certificateInfo)
 {
     AuthenticationChallenge challenge = m_challenges.take(challengeID);
     ASSERT(!challenge.isNull());
+    
+    if (tryUsePlatformCertificateInfoForChallenge(challenge, certificateInfo))
+        return;
+    
     AuthenticationClient* coreClient = challenge.authenticationClient();
     if (!coreClient) {
         // This authentication challenge comes from a download.
index 2c67430..192c91a 100644 (file)
@@ -42,6 +42,7 @@ namespace WebCore {
 namespace WebKit {
 
 class Download;
+class PlatformCertificateInfo;
 class WebFrame;
 
 class AuthenticationManager {
@@ -55,7 +56,7 @@ public:
     void didReceiveAuthenticationChallenge(WebFrame*, const WebCore::AuthenticationChallenge&);
     void didReceiveAuthenticationChallenge(Download*, const WebCore::AuthenticationChallenge&);
 
-    void useCredentialForChallenge(uint64_t challengeID, const WebCore::Credential&);
+    void useCredentialForChallenge(uint64_t challengeID, const WebCore::Credential&, const PlatformCertificateInfo&);
     void continueWithoutCredentialForChallenge(uint64_t challengeID);
     void cancelChallenge(uint64_t challengeID);
 
@@ -64,6 +65,8 @@ private:
 
     void didReceiveAuthenticationManagerMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*);
 
+    bool tryUsePlatformCertificateInfoForChallenge(const WebCore::AuthenticationChallenge&, const PlatformCertificateInfo&);
+    
     typedef HashMap<uint64_t, WebCore::AuthenticationChallenge> AuthenticationChallengeMap;
     AuthenticationChallengeMap m_challenges;
 };
index 264cd55..bb1cc30 100644 (file)
@@ -21,7 +21,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 messages -> AuthenticationManager {
-    void UseCredentialForChallenge(uint64_t challengeID, WebCore::Credential credential);
+    void UseCredentialForChallenge(uint64_t challengeID, WebCore::Credential credential, WebKit::PlatformCertificateInfo certificate);
     void ContinueWithoutCredentialForChallenge(uint64_t challengeID);
     void CancelChallenge(uint64_t challengeID);
 }
diff --git a/Source/WebKit2/WebProcess/Authentication/mac/AuthenticationManager.mac.mm b/Source/WebKit2/WebProcess/Authentication/mac/AuthenticationManager.mac.mm
new file mode 100644 (file)
index 0000000..091ad40
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 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 "AuthenticationManager.h"
+
+#include "PlatformCertificateInfo.h"
+#include <Security/SecIdentity.h>
+#include <WebCore/AuthenticationChallenge.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+bool AuthenticationManager::tryUsePlatformCertificateInfoForChallenge(const AuthenticationChallenge& challenge, const PlatformCertificateInfo& certificateInfo)
+{
+    CFArrayRef chain = certificateInfo.certificateChain();
+    if (!chain)
+        return false;
+        
+    ASSERT(CFArrayGetCount(chain));
+
+    // The passed-in certificate chain includes the identity certificate at index 0, and additional certificates starting at index 1.
+    SecIdentityRef identity;
+    OSStatus result = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(chain, 0), &identity);
+    if (result != errSecSuccess) {
+        LOG_ERROR("Unable to create SecIdentityRef with certificate - %i", result);
+        [challenge.sender() cancelAuthenticationChallenge:challenge.nsURLAuthenticationChallenge()];
+        return true;
+    }
+
+    CFIndex chainCount = CFArrayGetCount(chain);
+    NSArray *nsChain = chainCount > 1 ? [(NSArray *)chain subarrayWithRange:NSMakeRange(1, chainCount - 1)] : nil;
+
+    NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity
+                                                             certificates:nsChain
+                                                              persistence:NSURLCredentialPersistenceNone];
+
+    [challenge.sender() useCredential:credential forAuthenticationChallenge:challenge.nsURLAuthenticationChallenge()];
+    return true;
+}
+
+} // namespace WebKit