Title: [279872] trunk
Revision
279872
Author
[email protected]
Date
2021-07-13 07:19:38 -0700 (Tue, 13 Jul 2021)

Log Message

[GTK][WPE] Expose support for client certificate auth
https://bugs.webkit.org/show_bug.cgi?id=200805

Reviewed by Michael Catanzaro.

.:

Bump libsoup3 required version.

* Source/cmake/OptionsGTK.cmake:
* Source/cmake/OptionsWPE.cmake:

Source/WebCore:

* platform/Soup.cmake:
* platform/SourcesSoup.txt:
* platform/network/Credential.h:
* platform/network/ProtectionSpaceBase.cpp:
(WebCore::ProtectionSpaceBase::isPasswordBased const):
* platform/network/ProtectionSpaceBase.h:
* platform/network/soup/AuthenticationChallenge.h:
* platform/network/soup/AuthenticationChallengeSoup.cpp:
(WebCore::protectionSpaceForClientCertificate):
(WebCore::AuthenticationChallenge::AuthenticationChallenge):
(WebCore::protectionSpaceForClientCertificatePassword):
(WebCore::AuthenticationChallenge::platformCompare):
* platform/network/soup/CertificateInfoSoup.cpp:
(WebCore::CertificateInfo::isolatedCopy const):
* platform/network/soup/CredentialSoup.cpp: Added.
(WebCore::Credential::Credential):
(WebCore::m_certificate):
(WebCore::Credential::isEmpty const):
(WebCore::Credential::platformCompare):
* platform/network/soup/CredentialSoup.h: Added.
(WebCore::Credential::Credential):
(WebCore::Credential::encodingRequiresPlatformData const):
(WebCore::Credential::certificate const):
* platform/network/soup/NetworkStorageSessionSoup.cpp:
(WebCore::authTypeFromProtectionSpaceAuthenticationScheme):

Source/WebKit:

Add new API to handle certificate and pin certificate authentication requests.

* NetworkProcess/soup/NetworkDataTaskSoup.cpp:
(WebKit::NetworkDataTaskSoup::createRequest):
(WebKit::NetworkDataTaskSoup::completeAuthentication):
(WebKit::NetworkDataTaskSoup::cancelAuthentication):
(WebKit::NetworkDataTaskSoup::authenticate):
(WebKit::NetworkDataTaskSoup::continueAuthenticate):
(WebKit::NetworkDataTaskSoup::requestCertificateCallback):
(WebKit::NetworkDataTaskSoup::requestCertificatePasswordCallback):
* NetworkProcess/soup/NetworkDataTaskSoup.h:
* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<AuthenticationChallenge>::encode):
(IPC::ArgumentCoder<AuthenticationChallenge>::decode):
* Shared/glib/ArgumentCodersGLib.cpp:
(IPC::ArgumentCoder<GRefPtr<GTlsCertificate>>::encode):
(IPC::ArgumentCoder<GRefPtr<GTlsCertificate>>::decode):
* Shared/soup/WebCoreArgumentCodersSoup.cpp:
(IPC::ArgumentCoder<Credential>::encodePlatformData):
(IPC::ArgumentCoder<Credential>::decodePlatformData):
* UIProcess/API/glib/WebKitAuthenticationRequest.cpp:
(webkit_authentication_request_get_certificate_pin_flags):
* UIProcess/API/glib/WebKitCredential.cpp:
(webkit_credential_new_for_certificate_pin):
(webkit_credential_new_for_certificate):
(webkit_credential_get_certificate):
* UIProcess/API/gtk/WebKitAuthenticationRequest.h:
* UIProcess/API/gtk/WebKitCredential.h:
* UIProcess/API/gtk/WebKitWebViewGtk.cpp:
(webkitWebViewAuthenticate):
* UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
* UIProcess/API/wpe/WebKitAuthenticationRequest.h:
* UIProcess/API/wpe/WebKitCredential.h:
* UIProcess/API/wpe/docs/wpe-1.0-sections.txt:

Tools:

Add a simple implementation in MiniBrowser using a file chooser to ask for the certificate from a file and unit
tests for the client certificate request. Unfortunately we can't easily test pin certificates.

* MiniBrowser/gtk/BrowserTab.c:
(certificateDialogResponse):
(webViewAuthenticate):
(browserTabConstructed):
* TestWebKitAPI/Tests/WebKitGLib/TestSSL.cpp:
(ClientSideCertificateTest::acceptCertificateCallback):
(ClientSideCertificateTest::requestStartedCallback):
(ClientSideCertificateTest::authenticateCallback):
(ClientSideCertificateTest::ClientSideCertificateTest):
(ClientSideCertificateTest::~ClientSideCertificateTest):
(ClientSideCertificateTest::authenticate):
(ClientSideCertificateTest::acceptCertificate):
(ClientSideCertificateTest::waitForAuthenticationRequest):
(testClientSideCertificate):
(beforeAll):
* TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp:
* TestWebKitAPI/glib/WebKitGLib/WebKitTestServer.h:
(WebKitTestServer::soupServer const):

Modified Paths

Added Paths

Diff

Modified: trunk/ChangeLog (279871 => 279872)


--- trunk/ChangeLog	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/ChangeLog	2021-07-13 14:19:38 UTC (rev 279872)
@@ -1,3 +1,15 @@
+2021-07-13  Carlos Garcia Campos  <[email protected]>
+
+        [GTK][WPE] Expose support for client certificate auth
+        https://bugs.webkit.org/show_bug.cgi?id=200805
+
+        Reviewed by Michael Catanzaro.
+
+        Bump libsoup3 required version.
+
+        * Source/cmake/OptionsGTK.cmake:
+        * Source/cmake/OptionsWPE.cmake:
+
 2021-06-24  Zan Dobersek  <[email protected]>
 
         REGRESSION(r236846): WPE shouldn't depend on OpenGL ES 3

Modified: trunk/Source/WebCore/ChangeLog (279871 => 279872)


--- trunk/Source/WebCore/ChangeLog	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/ChangeLog	2021-07-13 14:19:38 UTC (rev 279872)
@@ -1,3 +1,36 @@
+2021-07-13  Carlos Garcia Campos  <[email protected]>
+
+        [GTK][WPE] Expose support for client certificate auth
+        https://bugs.webkit.org/show_bug.cgi?id=200805
+
+        Reviewed by Michael Catanzaro.
+
+        * platform/Soup.cmake:
+        * platform/SourcesSoup.txt:
+        * platform/network/Credential.h:
+        * platform/network/ProtectionSpaceBase.cpp:
+        (WebCore::ProtectionSpaceBase::isPasswordBased const):
+        * platform/network/ProtectionSpaceBase.h:
+        * platform/network/soup/AuthenticationChallenge.h:
+        * platform/network/soup/AuthenticationChallengeSoup.cpp:
+        (WebCore::protectionSpaceForClientCertificate):
+        (WebCore::AuthenticationChallenge::AuthenticationChallenge):
+        (WebCore::protectionSpaceForClientCertificatePassword):
+        (WebCore::AuthenticationChallenge::platformCompare):
+        * platform/network/soup/CertificateInfoSoup.cpp:
+        (WebCore::CertificateInfo::isolatedCopy const):
+        * platform/network/soup/CredentialSoup.cpp: Added.
+        (WebCore::Credential::Credential):
+        (WebCore::m_certificate):
+        (WebCore::Credential::isEmpty const):
+        (WebCore::Credential::platformCompare):
+        * platform/network/soup/CredentialSoup.h: Added.
+        (WebCore::Credential::Credential):
+        (WebCore::Credential::encodingRequiresPlatformData const):
+        (WebCore::Credential::certificate const):
+        * platform/network/soup/NetworkStorageSessionSoup.cpp:
+        (WebCore::authTypeFromProtectionSpaceAuthenticationScheme):
+
 2021-07-13  Martin Robinson  <[email protected]>
 
         RenderLayerScrollableArea::updateScrollPosition assumes that it can scroll to the targeted scroll position

Modified: trunk/Source/WebCore/platform/Soup.cmake (279871 => 279872)


--- trunk/Source/WebCore/platform/Soup.cmake	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/Soup.cmake	2021-07-13 14:19:38 UTC (rev 279872)
@@ -9,6 +9,7 @@
 list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS
     platform/network/soup/AuthenticationChallenge.h
     platform/network/soup/CertificateInfo.h
+    platform/network/soup/CredentialSoup.h
     platform/network/soup/GUniquePtrSoup.h
     platform/network/soup/ResourceError.h
     platform/network/soup/ResourceRequest.h

Modified: trunk/Source/WebCore/platform/SourcesSoup.txt (279871 => 279872)


--- trunk/Source/WebCore/platform/SourcesSoup.txt	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/SourcesSoup.txt	2021-07-13 14:19:38 UTC (rev 279872)
@@ -25,6 +25,7 @@
 platform/network/soup/CertificateInfoSoup.cpp
 platform/network/soup/CookieSoup.cpp
 platform/network/soup/CookieStorageSoup.cpp
+platform/network/soup/CredentialSoup.cpp
 platform/network/soup/CredentialStorageSoup.cpp
 platform/network/soup/NetworkStorageSessionSoup.cpp
 platform/network/soup/ProxyServerSoup.cpp

Modified: trunk/Source/WebCore/platform/network/Credential.h (279871 => 279872)


--- trunk/Source/WebCore/platform/network/Credential.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/network/Credential.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -30,6 +30,8 @@
 
 #if PLATFORM(COCOA)
 #include "CredentialCocoa.h"
+#elif USE(SOUP)
+#include "CredentialSoup.h"
 #else
 
 #include "CredentialBase.h"

Modified: trunk/Source/WebCore/platform/network/ProtectionSpaceBase.cpp (279871 => 279872)


--- trunk/Source/WebCore/platform/network/ProtectionSpaceBase.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/network/ProtectionSpaceBase.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -109,6 +109,9 @@
     case ProtectionSpaceAuthenticationSchemeNTLM:
     case ProtectionSpaceAuthenticationSchemeNegotiate:
     case ProtectionSpaceAuthenticationSchemeOAuth:
+#if USE(GLIB)
+    case ProtectionSpaceAuthenticationSchemeClientCertificatePINRequested:
+#endif
         return true;
     case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
     case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:

Modified: trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h (279871 => 279872)


--- trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -53,6 +53,9 @@
     ProtectionSpaceAuthenticationSchemeClientCertificateRequested = 7,
     ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested = 8,
     ProtectionSpaceAuthenticationSchemeOAuth = 9,
+#if USE(GLIB)
+    ProtectionSpaceAuthenticationSchemeClientCertificatePINRequested = 10,
+#endif
     ProtectionSpaceAuthenticationSchemeUnknown = 100
 };
   

Modified: trunk/Source/WebCore/platform/network/soup/AuthenticationChallenge.h (279871 => 279872)


--- trunk/Source/WebCore/platform/network/soup/AuthenticationChallenge.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/network/soup/AuthenticationChallenge.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -28,6 +28,8 @@
 #include "AuthenticationChallengeBase.h"
 #include "AuthenticationClient.h"
 
+typedef struct _GTlsClientConnection GTlsClientConnection;
+typedef struct _GTlsPassword GTlsPassword;
 typedef struct _SoupAuth SoupAuth;
 typedef struct _SoupMessage SoupMessage;
 
@@ -45,13 +47,19 @@
     }
 
     AuthenticationChallenge(SoupMessage*, SoupAuth*, bool retrying);
+    AuthenticationChallenge(SoupMessage*, GTlsClientConnection*);
+    AuthenticationChallenge(SoupMessage*, GTlsPassword*);
     AuthenticationClient* authenticationClient() const { RELEASE_ASSERT_NOT_REACHED(); }
 #if USE(SOUP2)
     SoupMessage* soupMessage() const { return m_soupMessage.get(); }
 #endif
     SoupAuth* soupAuth() const { return m_soupAuth.get(); }
+    GTlsPassword* tlsPassword() const { return m_tlsPassword.get(); }
     void setProposedCredential(const Credential& credential) { m_proposedCredential = credential; }
 
+    uint32_t tlsPasswordFlags() const { return m_tlsPasswordFlags; }
+    void setTLSPasswordFlags(uint32_t tlsPasswordFlags) { m_tlsPasswordFlags = tlsPasswordFlags; }
+
 private:
     friend class AuthenticationChallengeBase;
     static bool platformCompare(const AuthenticationChallenge&, const AuthenticationChallenge&);
@@ -60,6 +68,8 @@
     GRefPtr<SoupMessage> m_soupMessage;
 #endif
     GRefPtr<SoupAuth> m_soupAuth;
+    GRefPtr<GTlsPassword> m_tlsPassword;
+    uint32_t m_tlsPasswordFlags { 0 };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp (279871 => 279872)


--- trunk/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -90,11 +90,55 @@
 {
 }
 
+static ProtectionSpace protectionSpaceForClientCertificate(const URL& url)
+{
+    auto port = url.port();
+    if (!port)
+        port = defaultPortForProtocol(url.protocol());
+    return ProtectionSpace(url.host().toString(), static_cast<int>(port.value_or(0)), protectionSpaceServerTypeFromURL(url, false), { },
+        ProtectionSpaceAuthenticationSchemeClientCertificateRequested);
+}
+
+AuthenticationChallenge::AuthenticationChallenge(SoupMessage* soupMessage, GTlsClientConnection*)
+    : AuthenticationChallengeBase(protectionSpaceForClientCertificate(soupURIToURL(soup_message_get_uri(soupMessage)))
+        , Credential() // proposedCredentials
+        , 0 // previousFailureCount
+        , soupMessage // failureResponse
+        , ResourceError::authenticationError(soupMessage))
+{
+}
+
+static ProtectionSpace protectionSpaceForClientCertificatePassword(GTlsPassword* tlsPassword, const URL& url)
+{
+    auto port = url.port();
+    if (!port)
+        port = defaultPortForProtocol(url.protocol());
+    return ProtectionSpace(url.host().toString(), static_cast<int>(port.value_or(0)), protectionSpaceServerTypeFromURL(url, false),
+        String::fromUTF8(g_tls_password_get_description(tlsPassword)), ProtectionSpaceAuthenticationSchemeClientCertificatePINRequested);
+}
+
+AuthenticationChallenge::AuthenticationChallenge(SoupMessage* soupMessage, GTlsPassword* tlsPassword)
+    : AuthenticationChallengeBase(protectionSpaceForClientCertificatePassword(tlsPassword, soupURIToURL(soup_message_get_uri(soupMessage)))
+        , Credential() // proposedCredentials
+        , g_tls_password_get_flags(tlsPassword) & G_TLS_PASSWORD_RETRY ? 1 : 0 // previousFailureCount
+        , soupMessage // failureResponse
+        , ResourceError::authenticationError(soupMessage))
+    , m_tlsPassword(tlsPassword)
+    , m_tlsPasswordFlags(tlsPassword ? g_tls_password_get_flags(tlsPassword) : G_TLS_PASSWORD_NONE)
+{
+}
+
 bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
 {
     if (a.soupAuth() != b.soupAuth())
         return false;
 
+    if (a.tlsPassword() != b.tlsPassword())
+        return false;
+
+    if (a.tlsPasswordFlags() != b.tlsPasswordFlags())
+        return false;
+
 #if USE(SOUP2)
     return a.soupMessage() == b.soupMessage();
 #endif

Modified: trunk/Source/WebCore/platform/network/soup/CertificateInfoSoup.cpp (279871 => 279872)


--- trunk/Source/WebCore/platform/network/soup/CertificateInfoSoup.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/network/soup/CertificateInfoSoup.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -62,45 +62,43 @@
 
 CertificateInfo::~CertificateInfo() = default;
 
-static GRefPtr<GTlsCertificate> createCertificate(GByteArray* bytes, GTlsCertificate* issuer)
-{
-    gpointer cert = g_initable_new(g_tls_backend_get_certificate_type(g_tls_backend_get_default()),
-        nullptr, nullptr,
-        "certificate", bytes,
-        "issuer", issuer,
-        nullptr);
-    RELEASE_ASSERT(cert);
-    return adoptGRef(G_TLS_CERTIFICATE(cert));
-}
-
 CertificateInfo CertificateInfo::isolatedCopy() const
 {
-    // We can only copy the public portions, so this can only be used for server certificates, not
-    // for client certificates. Sadly, other ports don't have this restriction, and there is no way
-    // to assert that we are not messing up here because we can't know how callers are using the
-    // certificate. So be careful?
-    //
-    // We should add g_tls_certificate_copy() to GLib so that we can copy the private portion too.
+    if (!m_certificate)
+        return { };
 
-    Vector<GRefPtr<GByteArray>> certificateBytes;
-    GTlsCertificate* cert = m_certificate.get();
-    if (!cert)
-        return CertificateInfo();
+    Vector<GUniquePtr<char>> certificatesDataList;
+    for (auto* nextCertificate = m_certificate.get(); nextCertificate; nextCertificate = g_tls_certificate_get_issuer(nextCertificate)) {
+        GUniqueOutPtr<char> certificateData;
+        g_object_get(nextCertificate, "certificate-pem", &certificateData.outPtr(), nullptr);
+        certificatesDataList.append(certificateData.release());
+    }
 
-    do {
-        GRefPtr<GByteArray> der;
-        g_object_get(cert, "certificate", &der.outPtr(), nullptr);
+#if GLIB_CHECK_VERSION(2, 69, 0)
+    GUniqueOutPtr<char> privateKey;
+    GUniqueOutPtr<char> privateKeyPKCS11Uri;
+    g_object_get(m_certificate.get(), "private-key-pem", &privateKey.outPtr(), "private-key-pkcs11-uri", &privateKeyPKCS11Uri.outPtr(), nullptr);
+#endif
 
-        GRefPtr<GByteArray> copy = adoptGRef(g_byte_array_new());
-        g_byte_array_append(copy.get(), der->data, der->len);
-        certificateBytes.append(WTFMove(copy));
-    } while ((cert = g_tls_certificate_get_issuer(cert)));
+    GType certificateType = g_tls_backend_get_certificate_type(g_tls_backend_get_default());
+    GRefPtr<GTlsCertificate> certificate;
+    GTlsCertificate* issuer = nullptr;
+    while (!certificatesDataList.isEmpty()) {
+        auto certificateData = certificatesDataList.takeLast();
+        certificate = adoptGRef(G_TLS_CERTIFICATE(g_initable_new(
+            certificateType, nullptr, nullptr,
+            "certificate-pem", certificateData.get(),
+            "issuer", issuer,
+#if GLIB_CHECK_VERSION(2, 69, 0)
+            "private-key-pem", certificatesDataList.isEmpty() ? privateKey.get() : nullptr,
+            "private-key-pkcs11-uri", certificatesDataList.isEmpty() ? privateKeyPKCS11Uri.get() : nullptr,
+#endif
+            nullptr)));
+        RELEASE_ASSERT(certificate);
+        issuer = certificate.get();
+    }
 
-    auto finalCertificateIndex = certificateBytes.size() - 1;
-    GRefPtr<GTlsCertificate> copy = createCertificate(certificateBytes[finalCertificateIndex].get(), nullptr);
-    for (ssize_t i = finalCertificateIndex - 1; i >= 0; i--)
-        copy = createCertificate(certificateBytes[i].get(), copy.get());
-    return CertificateInfo(copy.get(), m_tlsErrors);
+    return CertificateInfo(certificate.get(), m_tlsErrors);
 }
 
 std::optional<CertificateSummary> CertificateInfo::summary() const

Added: trunk/Source/WebCore/platform/network/soup/CredentialSoup.cpp (0 => 279872)


--- trunk/Source/WebCore/platform/network/soup/CredentialSoup.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/soup/CredentialSoup.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * 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 "CredentialSoup.h"
+
+namespace WebCore {
+
+Credential::Credential(const Credential& original, CredentialPersistence persistence)
+    : CredentialBase(original, persistence)
+    , m_certificate(original.certificate())
+{
+}
+
+Credential::Credential(GTlsCertificate* certificate, CredentialPersistence persistence)
+    : CredentialBase({ }, { }, persistence)
+    , m_certificate(certificate)
+{
+}
+
+bool Credential::isEmpty() const
+{
+    return !m_certificate && CredentialBase::isEmpty();
+}
+
+bool Credential::platformCompare(const Credential& a, const Credential& b)
+{
+    return a.certificate() == b.certificate();
+}
+
+} // namespace WebCore

Added: trunk/Source/WebCore/platform/network/soup/CredentialSoup.h (0 => 279872)


--- trunk/Source/WebCore/platform/network/soup/CredentialSoup.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/soup/CredentialSoup.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "CredentialBase.h"
+#include <wtf/glib/GRefPtr.h>
+
+typedef struct _GTlsCertificate GTlsCertificate;
+
+namespace WebCore {
+
+class Credential : public CredentialBase {
+public:
+    Credential()
+        : CredentialBase()
+    {
+    }
+
+    Credential(const String& user, const String& password, CredentialPersistence persistence)
+        : CredentialBase(user, password, persistence)
+    {
+    }
+
+    Credential(const Credential&, CredentialPersistence);
+
+    WEBCORE_EXPORT Credential(GTlsCertificate*, CredentialPersistence);
+
+    WEBCORE_EXPORT bool isEmpty() const;
+
+    static bool platformCompare(const Credential&, const Credential&);
+
+    bool encodingRequiresPlatformData() const { return !!m_certificate; }
+
+    GTlsCertificate* certificate() const { return m_certificate.get(); }
+
+private:
+    GRefPtr<GTlsCertificate> m_certificate;
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp (279871 => 279872)


--- trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -125,6 +125,8 @@
     case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
         ASSERT_NOT_REACHED();
         break;
+    case ProtectionSpaceAuthenticationSchemeClientCertificatePINRequested:
+        return "Certificate PIN";
     case ProtectionSpaceAuthenticationSchemeOAuth:
         return "OAuth";
     case ProtectionSpaceAuthenticationSchemeUnknown:

Modified: trunk/Source/WebKit/ChangeLog (279871 => 279872)


--- trunk/Source/WebKit/ChangeLog	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/ChangeLog	2021-07-13 14:19:38 UTC (rev 279872)
@@ -1,3 +1,45 @@
+2021-07-13  Carlos Garcia Campos  <[email protected]>
+
+        [GTK][WPE] Expose support for client certificate auth
+        https://bugs.webkit.org/show_bug.cgi?id=200805
+
+        Reviewed by Michael Catanzaro.
+
+        Add new API to handle certificate and pin certificate authentication requests.
+
+        * NetworkProcess/soup/NetworkDataTaskSoup.cpp:
+        (WebKit::NetworkDataTaskSoup::createRequest):
+        (WebKit::NetworkDataTaskSoup::completeAuthentication):
+        (WebKit::NetworkDataTaskSoup::cancelAuthentication):
+        (WebKit::NetworkDataTaskSoup::authenticate):
+        (WebKit::NetworkDataTaskSoup::continueAuthenticate):
+        (WebKit::NetworkDataTaskSoup::requestCertificateCallback):
+        (WebKit::NetworkDataTaskSoup::requestCertificatePasswordCallback):
+        * NetworkProcess/soup/NetworkDataTaskSoup.h:
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<AuthenticationChallenge>::encode):
+        (IPC::ArgumentCoder<AuthenticationChallenge>::decode):
+        * Shared/glib/ArgumentCodersGLib.cpp:
+        (IPC::ArgumentCoder<GRefPtr<GTlsCertificate>>::encode):
+        (IPC::ArgumentCoder<GRefPtr<GTlsCertificate>>::decode):
+        * Shared/soup/WebCoreArgumentCodersSoup.cpp:
+        (IPC::ArgumentCoder<Credential>::encodePlatformData):
+        (IPC::ArgumentCoder<Credential>::decodePlatformData):
+        * UIProcess/API/glib/WebKitAuthenticationRequest.cpp:
+        (webkit_authentication_request_get_certificate_pin_flags):
+        * UIProcess/API/glib/WebKitCredential.cpp:
+        (webkit_credential_new_for_certificate_pin):
+        (webkit_credential_new_for_certificate):
+        (webkit_credential_get_certificate):
+        * UIProcess/API/gtk/WebKitAuthenticationRequest.h:
+        * UIProcess/API/gtk/WebKitCredential.h:
+        * UIProcess/API/gtk/WebKitWebViewGtk.cpp:
+        (webkitWebViewAuthenticate):
+        * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
+        * UIProcess/API/wpe/WebKitAuthenticationRequest.h:
+        * UIProcess/API/wpe/WebKitCredential.h:
+        * UIProcess/API/wpe/docs/wpe-1.0-sections.txt:
+
 2021-07-13  Myles C. Maxfield  <[email protected]>
 
         Fix the Apple Internal iOS build

Modified: trunk/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp (279871 => 279872)


--- trunk/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -238,6 +238,8 @@
         g_signal_connect(m_soupMessage.get(), "wrote-headers", G_CALLBACK(wroteHeadersCallback), this);
         g_signal_connect(m_soupMessage.get(), "wrote-body", G_CALLBACK(wroteBodyCallback), this);
     }
+    g_signal_connect(m_soupMessage.get(), "request-certificate", G_CALLBACK(requestCertificateCallback), this);
+    g_signal_connect(m_soupMessage.get(), "request-certificate-password", G_CALLBACK(requestCertificatePasswordCallback), this);
 #endif
     g_signal_connect(m_soupMessage.get(), "restarted", G_CALLBACK(restartedCallback), this);
     g_signal_connect(m_soupMessage.get(), "starting", G_CALLBACK(startingCallback), this);
@@ -683,6 +685,73 @@
     return httpStatusCode == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED || httpStatusCode == SOUP_STATUS_UNAUTHORIZED;
 }
 
+void NetworkDataTaskSoup::completeAuthentication(const AuthenticationChallenge& challenge, const Credential& credential)
+{
+    switch (challenge.protectionSpace().authenticationScheme()) {
+    case ProtectionSpaceAuthenticationSchemeDefault:
+    case ProtectionSpaceAuthenticationSchemeHTTPBasic:
+    case ProtectionSpaceAuthenticationSchemeHTTPDigest:
+    case ProtectionSpaceAuthenticationSchemeHTMLForm:
+    case ProtectionSpaceAuthenticationSchemeNTLM:
+    case ProtectionSpaceAuthenticationSchemeNegotiate:
+    case ProtectionSpaceAuthenticationSchemeOAuth:
+        soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
+        break;
+    case ProtectionSpaceAuthenticationSchemeClientCertificatePINRequested: {
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
+        CString password = credential.password().utf8();
+        g_tls_password_set_value(challenge.tlsPassword(), reinterpret_cast<const unsigned char*>(password.data()), password.length());
+        soup_message_tls_client_certificate_password_request_complete(m_soupMessage.get());
+#endif
+        break;
+    }
+    case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
+        soup_message_set_tls_client_certificate(m_soupMessage.get(), credential.certificate());
+#endif
+        break;
+    case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
+    case ProtectionSpaceAuthenticationSchemeUnknown:
+        break;
+    }
+}
+
+void NetworkDataTaskSoup::cancelAuthentication(const AuthenticationChallenge& challenge)
+{
+    switch (challenge.protectionSpace().authenticationScheme()) {
+    case ProtectionSpaceAuthenticationSchemeDefault:
+    case ProtectionSpaceAuthenticationSchemeHTTPBasic:
+    case ProtectionSpaceAuthenticationSchemeHTTPDigest:
+    case ProtectionSpaceAuthenticationSchemeHTMLForm:
+    case ProtectionSpaceAuthenticationSchemeNTLM:
+    case ProtectionSpaceAuthenticationSchemeNegotiate:
+    case ProtectionSpaceAuthenticationSchemeOAuth:
+        soup_auth_cancel(challenge.soupAuth());
+        break;
+    case ProtectionSpaceAuthenticationSchemeClientCertificatePINRequested:
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
+        soup_message_tls_client_certificate_password_request_complete(m_soupMessage.get());
+#endif
+        break;
+    case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
+        soup_message_set_tls_client_certificate(m_soupMessage.get(), nullptr);
+#endif
+        break;
+    case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
+    case ProtectionSpaceAuthenticationSchemeUnknown:
+        break;
+    }
+}
+
 void NetworkDataTaskSoup::authenticate(AuthenticationChallenge&& challenge)
 {
     ASSERT(m_soupMessage);
@@ -703,7 +772,8 @@
                     // Store the credential back, possibly adding it as a default for this directory.
                     m_session->networkStorageSession()->credentialStorage().set(m_partition, credential, challenge.protectionSpace(), challenge.failureResponse().url());
                 }
-                soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
+
+                completeAuthentication(challenge, credential);
                 return;
             }
         }
@@ -737,11 +807,13 @@
 {
     m_client->didReceiveChallenge(AuthenticationChallenge(challenge), NegotiatedLegacyTLS::No, [this, protectedThis = makeRef(*this), challenge](AuthenticationChallengeDisposition disposition, const Credential& credential) {
         if (m_state == State::Canceling || m_state == State::Completed) {
+            cancelAuthentication(challenge);
             clearRequest();
             return;
         }
 
         if (disposition == AuthenticationChallengeDisposition::Cancel) {
+            cancelAuthentication(challenge);
             cancel();
             didFail(cancelledError(m_currentRequest));
             return;
@@ -762,9 +834,9 @@
                 }
             }
 
-            soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
+            completeAuthentication(challenge, credential);
         } else
-            soup_auth_cancel(challenge.soupAuth());
+            cancelAuthentication(challenge);
 
 #if USE(SOUP2)
         soup_session_unpause_message(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), challenge.soupMessage());
@@ -1193,6 +1265,28 @@
     task->m_networkLoadMetrics.responseBodyBytesReceived = soup_message_metrics_get_response_body_bytes_received(metrics);
     task->m_networkLoadMetrics.responseBodyDecodedSize = soup_message_metrics_get_response_body_size(metrics);
 }
+
+gboolean NetworkDataTaskSoup::requestCertificateCallback(SoupMessage* soupMessage, GTlsClientConnection* connection, NetworkDataTaskSoup* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return FALSE;
+    }
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->authenticate(AuthenticationChallenge(soupMessage, connection));
+    return TRUE;
+}
+
+gboolean NetworkDataTaskSoup::requestCertificatePasswordCallback(SoupMessage* soupMessage, GTlsPassword* tlsPassword, NetworkDataTaskSoup* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return FALSE;
+    }
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->authenticate(AuthenticationChallenge(soupMessage, tlsPassword));
+    return TRUE;
+}
 #endif
 
 #if USE(SOUP2)

Modified: trunk/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h (279871 => 279872)


--- trunk/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -102,6 +102,8 @@
 #endif
     void authenticate(WebCore::AuthenticationChallenge&&);
     void continueAuthenticate(WebCore::AuthenticationChallenge&&);
+    void completeAuthentication(const WebCore::AuthenticationChallenge&, const WebCore::Credential&);
+    void cancelAuthentication(const WebCore::AuthenticationChallenge&);
 
     static void skipInputStreamForRedirectionCallback(GInputStream*, GAsyncResult*, NetworkDataTaskSoup*);
     void skipInputStreamForRedirection();
@@ -133,6 +135,8 @@
     static void wroteHeadersCallback(SoupMessage*, NetworkDataTaskSoup*);
     static void wroteBodyCallback(SoupMessage*, NetworkDataTaskSoup*);
     static void gotBodyCallback(SoupMessage*, NetworkDataTaskSoup*);
+    static gboolean requestCertificateCallback(SoupMessage*, GTlsClientConnection*, NetworkDataTaskSoup*);
+    static gboolean requestCertificatePasswordCallback(SoupMessage*, GTlsPassword*, NetworkDataTaskSoup*);
 #endif
 
     void download();

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (279871 => 279872)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -932,6 +932,9 @@
 void ArgumentCoder<AuthenticationChallenge>::encode(Encoder& encoder, const AuthenticationChallenge& challenge)
 {
     encoder << challenge.protectionSpace() << challenge.proposedCredential() << challenge.previousFailureCount() << challenge.failureResponse() << challenge.error();
+#if USE(SOUP)
+    encoder << challenge.tlsPasswordFlags();
+#endif
 }
 
 bool ArgumentCoder<AuthenticationChallenge>::decode(Decoder& decoder, AuthenticationChallenge& challenge)
@@ -955,8 +958,18 @@
     ResourceError error;
     if (!decoder.decode(error))
         return false;
-    
+
+#if USE(SOUP)
+    uint32_t tlsPasswordFlags;
+    if (!decoder.decode(tlsPasswordFlags))
+        return false;
+#endif
+
     challenge = AuthenticationChallenge(protectionSpace, proposedCredential, previousFailureCount, failureResponse, error);
+
+#if USE(SOUP)
+    challenge.setTLSPasswordFlags(tlsPasswordFlags);
+#endif
     return true;
 }
 

Modified: trunk/Source/WebKit/Shared/glib/ArgumentCodersGLib.cpp (279871 => 279872)


--- trunk/Source/WebKit/Shared/glib/ArgumentCodersGLib.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/Shared/glib/ArgumentCodersGLib.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -89,6 +89,14 @@
     if (certificatesDataList.isEmpty())
         return;
 
+#if GLIB_CHECK_VERSION(2, 69, 0)
+    GRefPtr<GByteArray> privateKey;
+    GUniqueOutPtr<char> privateKeyPKCS11Uri;
+    g_object_get(certificate.get(), "private-key", &privateKey.outPtr(), "private-key-pkcs11-uri", &privateKeyPKCS11Uri.outPtr(), nullptr);
+    encoder << IPC::DataReference(privateKey ? privateKey->data : nullptr, privateKey ? privateKey->len : 0);
+    encoder << CString(privateKeyPKCS11Uri.get());
+#endif
+
     // Encode starting from the root certificate.
     while (!certificatesDataList.isEmpty()) {
         auto certificateData = certificatesDataList.takeLast();
@@ -105,6 +113,21 @@
     if (!chainLength)
         return GRefPtr<GTlsCertificate>();
 
+#if GLIB_CHECK_VERSION(2, 69, 0)
+    IPC::DataReference privateKeyData;
+    if (!decoder.decode(privateKeyData))
+        return std::nullopt;
+    GRefPtr<GByteArray> privateKey;
+    if (privateKeyData.size()) {
+        privateKey = adoptGRef(g_byte_array_sized_new(privateKeyData.size()));
+        g_byte_array_append(privateKey.get(), privateKeyData.data(), privateKeyData.size());
+    }
+
+    CString privateKeyPKCS11Uri;
+    if (!decoder.decode(privateKeyPKCS11Uri))
+        return std::nullopt;
+#endif
+
     GType certificateType = g_tls_backend_get_certificate_type(g_tls_backend_get_default());
     GRefPtr<GTlsCertificate> certificate;
     GTlsCertificate* issuer = nullptr;
@@ -120,6 +143,10 @@
             certificateType, nullptr, nullptr,
             "certificate", certificateData.get(),
             "issuer", issuer,
+#if GLIB_CHECK_VERSION(2, 69, 0)
+            "private-key", i == chainLength - 1 ? privateKey.get() : nullptr,
+            "private-key-pkcs11-uri", i == chainLength - 1 ? privateKeyPKCS11Uri.data() : nullptr,
+#endif
             nullptr)));
         issuer = certificate.get();
     }

Modified: trunk/Source/WebKit/Shared/soup/WebCoreArgumentCodersSoup.cpp (279871 => 279872)


--- trunk/Source/WebKit/Shared/soup/WebCoreArgumentCodersSoup.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/Shared/soup/WebCoreArgumentCodersSoup.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -31,6 +31,7 @@
 #include "ArgumentCodersGLib.h"
 #include "DataReference.h"
 #include <WebCore/CertificateInfo.h>
+#include <WebCore/Credential.h>
 #include <WebCore/DictionaryPopupInfo.h>
 #include <WebCore/Font.h>
 #include <WebCore/FontAttributes.h>
@@ -181,15 +182,26 @@
     return false;
 }
 
-void ArgumentCoder<Credential>::encodePlatformData(Encoder&, const Credential&)
+void ArgumentCoder<Credential>::encodePlatformData(Encoder& encoder, const Credential& credential)
 {
-    ASSERT_NOT_REACHED();
+    GRefPtr<GTlsCertificate> certificate = credential.certificate();
+    encoder << certificate;
+    encoder << credential.persistence();
 }
 
-bool ArgumentCoder<Credential>::decodePlatformData(Decoder&, Credential&)
+bool ArgumentCoder<Credential>::decodePlatformData(Decoder& decoder, Credential& credential)
 {
-    ASSERT_NOT_REACHED();
-    return false;
+    std::optional<GRefPtr<GTlsCertificate>> certificate;
+    decoder >> certificate;
+    if (!certificate)
+        return false;
+
+    CredentialPersistence persistence;
+    if (!decoder.decode(persistence))
+        return false;
+
+    credential = Credential(certificate->get(), persistence);
+    return true;
 }
 
 void ArgumentCoder<FontAttributes>::encodePlatformData(Encoder&, const FontAttributes&)

Modified: trunk/Source/WebKit/UIProcess/API/glib/WebKitAuthenticationRequest.cpp (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/glib/WebKitAuthenticationRequest.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/glib/WebKitAuthenticationRequest.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -98,6 +98,8 @@
         return WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED;
     case WebCore::ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
         return WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED;
+    case WebCore::ProtectionSpaceAuthenticationSchemeClientCertificatePINRequested:
+        return WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_PIN_REQUESTED;
     case WebCore::ProtectionSpaceAuthenticationSchemeUnknown:
         return WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN;
     default:
@@ -482,3 +484,20 @@
 
     g_signal_emit(request, signals[CANCELLED], 0);
 }
+
+/**
+ * webkit_authentication_request_get_certificate_pin_flags:
+ * @request: a #WebKitAuthenticationRequest
+ *
+ * Get the #GTlsPasswordFlags of the %WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_PIN_REQUESTED authentication challenge.
+ *
+ * Returns: a #GTlsPasswordFlags
+ *
+ * Since: 2.34
+ */
+GTlsPasswordFlags webkit_authentication_request_get_certificate_pin_flags(WebKitAuthenticationRequest* request)
+{
+    g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), G_TLS_PASSWORD_NONE);
+
+    return static_cast<GTlsPasswordFlags>(request->priv->authenticationChallenge->core().tlsPasswordFlags());
+}

Modified: trunk/Source/WebKit/UIProcess/API/glib/WebKitCredential.cpp (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/glib/WebKitCredential.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/glib/WebKitCredential.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -103,6 +103,54 @@
 }
 
 /**
+ * webkit_credential_new_for_certificate_pin:
+ * @pin: The PIN for the new credential
+ * @persistence: The #WebKitCredentialPersistence of the new credential
+ *
+ * Create a new credential from the provided PIN and persistence mode.
+ * Note that %WEBKIT_CREDENTIAL_PERSISTENCE_PERMANENT is not supported for certificate pin credentials.
+ *
+ * Returns: (transfer full): A #WebKitCredential.
+ *
+ * Since: 2.34
+ */
+WebKitCredential* webkit_credential_new_for_certificate_pin(const gchar* pin, WebKitCredentialPersistence persistence)
+{
+    g_return_val_if_fail(pin, 0);
+
+    if (persistence == WEBKIT_CREDENTIAL_PERSISTENCE_PERMANENT) {
+        g_warning("Permanent persistence is not supported for certificate pin credentials. Session persistence will be used instead.");
+        persistence = WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION;
+    }
+
+    return webkitCredentialCreate(WebCore::Credential("", String::fromUTF8(pin), toWebCoreCredentialPersistence(persistence)));
+}
+
+/**
+ * webkit_credential_new_for_certificate:
+ * @certificate: (nullable): The #GTlsCertificate, or %NULL
+ * @persistence: The #WebKitCredentialPersistence of the new credential
+ *
+ * Create a new credential from the @certificate and persistence mode.
+ * Note that %WEBKIT_CREDENTIAL_PERSISTENCE_PERMANENT is not supported for certificate credentials.
+ *
+ * Returns: (transfer full): A #WebKitCredential.
+ *
+ * Since: 2.34
+ */
+WebKitCredential* webkit_credential_new_for_certificate(GTlsCertificate* certificate, WebKitCredentialPersistence persistence)
+{
+    g_return_val_if_fail(!certificate || G_IS_TLS_CERTIFICATE(certificate), nullptr);
+
+    if (persistence == WEBKIT_CREDENTIAL_PERSISTENCE_PERMANENT) {
+        g_warning("Permanent persistence is not supported for certificate credentials. Session persistence will be used instead.");
+        persistence = WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION;
+    }
+
+    return webkitCredentialCreate(WebCore::Credential(certificate, toWebCoreCredentialPersistence(persistence)));
+}
+
+/**
  * webkit_credential_copy:
  * @credential: a #WebKitCredential
  *
@@ -191,6 +239,23 @@
 }
 
 /**
+ * webkit_credential_get_certificate:
+ * @credential: a #WebKitCredential
+ *
+ * Get the certificate currently held by this #WebKitCredential.
+ *
+ * Returns: (transfer none): a #GTlsCertificate, or %NULL
+ *
+ * Since: 2.34
+ */
+GTlsCertificate* webkit_credential_get_certificate(WebKitCredential* credential)
+{
+    g_return_val_if_fail(credential, NULL);
+
+    return credential->credential.certificate();
+}
+
+/**
  * webkit_credential_get_persistence:
  * @credential: a #WebKitCredential
  *

Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitAuthenticationRequest.h (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitAuthenticationRequest.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitAuthenticationRequest.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -68,6 +68,7 @@
  * @WEBKIT_AUTHENTICATION_SCHEME_NEGOTIATE: Negotiate (or SPNEGO) authentication scheme as defined in RFC 4559.
  * @WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED: Client Certificate Authentication (see RFC 2246).
  * @WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED: Server Trust Authentication.
+ * @WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_PIN_REQUESTED: Client certificate PIN required for use. Since: 2.34
  * @WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN: Authentication scheme unknown.
  *
  * Enum values representing the authentication scheme.
@@ -83,6 +84,7 @@
     WEBKIT_AUTHENTICATION_SCHEME_NEGOTIATE = 6,
     WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED = 7,
     WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED = 8,
+    WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_PIN_REQUESTED = 9,
     WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN = 100,
 } WebKitAuthenticationScheme;
 
@@ -132,6 +134,9 @@
 WEBKIT_API void
 webkit_authentication_request_cancel                  (WebKitAuthenticationRequest *request);
 
+WEBKIT_API GTlsPasswordFlags
+webkit_authentication_request_get_certificate_pin_flags (WebKitAuthenticationRequest* request);
+
 G_END_DECLS
 
 #endif

Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitCredential.h (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitCredential.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitCredential.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -25,6 +25,7 @@
 #define WebKitCredential_h
 
 #include <glib-object.h>
+#include <gio/gio.h>
 #include <webkit2/WebKitDefines.h>
 
 G_BEGIN_DECLS
@@ -50,30 +51,41 @@
 } WebKitCredentialPersistence;
 
 WEBKIT_API GType
-webkit_credential_get_type             (void);
+webkit_credential_get_type                (void);
 
 WEBKIT_API WebKitCredential *
-webkit_credential_new                  (const gchar                 *username,
-                                        const gchar                 *password,
-                                        WebKitCredentialPersistence  persistence);
+webkit_credential_new                     (const gchar                 *username,
+                                           const gchar                 *password,
+                                           WebKitCredentialPersistence  persistence);
 
 WEBKIT_API WebKitCredential *
-webkit_credential_copy                 (WebKitCredential            *credential);
+webkit_credential_new_for_certificate_pin (const gchar                 *pin,
+                                           WebKitCredentialPersistence  persistence);
 
+WEBKIT_API WebKitCredential *
+webkit_credential_new_for_certificate     (GTlsCertificate             *certificate,
+                                           WebKitCredentialPersistence  persistence);
+
+WEBKIT_API WebKitCredential *
+webkit_credential_copy                    (WebKitCredential            *credential);
+
 WEBKIT_API void
-webkit_credential_free                 (WebKitCredential            *credential);
+webkit_credential_free                    (WebKitCredential            *credential);
 
 WEBKIT_API const gchar *
-webkit_credential_get_username         (WebKitCredential            *credential);
+webkit_credential_get_username            (WebKitCredential            *credential);
 
 WEBKIT_API const gchar *
-webkit_credential_get_password         (WebKitCredential            *credential);
+webkit_credential_get_password            (WebKitCredential            *credential);
 
 WEBKIT_API gboolean
-webkit_credential_has_password         (WebKitCredential            *credential);
+webkit_credential_has_password            (WebKitCredential            *credential);
 
+WEBKIT_API GTlsCertificate *
+webkit_credential_get_certificate         (WebKitCredential            *credential);
+
 WEBKIT_API WebKitCredentialPersistence
-webkit_credential_get_persistence      (WebKitCredential            *credential);
+webkit_credential_get_persistence         (WebKitCredential            *credential);
 
 G_END_DECLS
 

Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewGtk.cpp (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewGtk.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewGtk.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -34,8 +34,24 @@
 
 gboolean webkitWebViewAuthenticate(WebKitWebView* webView, WebKitAuthenticationRequest* request)
 {
-    CredentialStorageMode credentialStorageMode = webkit_authentication_request_can_save_credentials(request) ? AllowPersistentStorage : DisallowPersistentStorage;
-    webkitWebViewBaseAddDialog(WEBKIT_WEB_VIEW_BASE(webView), webkitAuthenticationDialogNew(request, credentialStorageMode));
+    switch (webkit_authentication_request_get_scheme(request)) {
+    case WEBKIT_AUTHENTICATION_SCHEME_DEFAULT:
+    case WEBKIT_AUTHENTICATION_SCHEME_HTTP_BASIC:
+    case WEBKIT_AUTHENTICATION_SCHEME_HTTP_DIGEST:
+    case WEBKIT_AUTHENTICATION_SCHEME_HTML_FORM:
+    case WEBKIT_AUTHENTICATION_SCHEME_NTLM:
+    case WEBKIT_AUTHENTICATION_SCHEME_NEGOTIATE:
+    case WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED:
+    case WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN: {
+        CredentialStorageMode credentialStorageMode = webkit_authentication_request_can_save_credentials(request) ? AllowPersistentStorage : DisallowPersistentStorage;
+        webkitWebViewBaseAddDialog(WEBKIT_WEB_VIEW_BASE(webView), webkitAuthenticationDialogNew(request, credentialStorageMode));
+        break;
+    }
+    case WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED:
+    case WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_PIN_REQUESTED:
+        webkit_authentication_request_authenticate(request, nullptr);
+        break;
+    }
 
     return TRUE;
 }

Modified: trunk/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt	2021-07-13 14:19:38 UTC (rev 279872)
@@ -357,6 +357,7 @@
 webkit_authentication_request_set_proposed_credential
 webkit_authentication_request_get_realm
 webkit_authentication_request_get_scheme
+webkit_authentication_request_get_certificate_pin_flags
 webkit_authentication_request_is_for_proxy
 
 <SUBSECTION Standard>
@@ -378,6 +379,8 @@
 WebKitCredential
 WebKitCredentialPersistence
 webkit_credential_new
+webkit_credential_new_for_certificate_pin
+webkit_credential_new_for_certificate
 webkit_credential_copy
 webkit_credential_free
 webkit_credential_get_password
@@ -384,6 +387,7 @@
 webkit_credential_get_persistence
 webkit_credential_get_username
 webkit_credential_has_password
+webkit_credential_get_certificate
 </SECTION>
 
 <SECTION>

Modified: trunk/Source/WebKit/UIProcess/API/wpe/WebKitAuthenticationRequest.h (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/wpe/WebKitAuthenticationRequest.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/wpe/WebKitAuthenticationRequest.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -67,6 +67,7 @@
  * @WEBKIT_AUTHENTICATION_SCHEME_NEGOTIATE: Negotiate (or SPNEGO) authentication scheme as defined in RFC 4559.
  * @WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED: Client Certificate Authentication (see RFC 2246).
  * @WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED: Server Trust Authentication.
+ * @WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_PIN_REQUESTED: Client certificate PIN required for use. Since: 2.34
  * @WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN: Authentication scheme unknown.
  *
  * Enum values representing the authentication scheme.
@@ -82,6 +83,7 @@
     WEBKIT_AUTHENTICATION_SCHEME_NEGOTIATE = 6,
     WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED = 7,
     WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED = 8,
+    WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_PIN_REQUESTED = 9,
     WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN = 100,
 } WebKitAuthenticationScheme;
 
@@ -131,6 +133,9 @@
 WEBKIT_API void
 webkit_authentication_request_cancel                  (WebKitAuthenticationRequest *request);
 
+WEBKIT_API GTlsPasswordFlags
+webkit_authentication_request_get_certificate_pin_flags (WebKitAuthenticationRequest* request);
+
 G_END_DECLS
 
 #endif

Modified: trunk/Source/WebKit/UIProcess/API/wpe/WebKitCredential.h (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/wpe/WebKitCredential.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/wpe/WebKitCredential.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -25,6 +25,7 @@
 #define WebKitCredential_h
 
 #include <glib-object.h>
+#include <gio/gio.h>
 #include <wpe/WebKitDefines.h>
 
 G_BEGIN_DECLS
@@ -53,27 +54,38 @@
 webkit_credential_get_type             (void);
 
 WEBKIT_API WebKitCredential *
-webkit_credential_new                  (const gchar                 *username,
-                                        const gchar                 *password,
-                                        WebKitCredentialPersistence  persistence);
+webkit_credential_new                     (const gchar                 *username,
+                                           const gchar                 *password,
+                                           WebKitCredentialPersistence  persistence);
 
 WEBKIT_API WebKitCredential *
-webkit_credential_copy                 (WebKitCredential            *credential);
+webkit_credential_new_for_certificate_pin (const gchar                 *pin,
+                                           WebKitCredentialPersistence  persistence);
 
+WEBKIT_API WebKitCredential *
+webkit_credential_new_for_certificate     (GTlsCertificate             *certificate,
+                                           WebKitCredentialPersistence  persistence);
+
+WEBKIT_API WebKitCredential *
+webkit_credential_copy                    (WebKitCredential            *credential);
+
 WEBKIT_API void
-webkit_credential_free                 (WebKitCredential            *credential);
+webkit_credential_free                    (WebKitCredential            *credential);
 
 WEBKIT_API const gchar *
-webkit_credential_get_username         (WebKitCredential            *credential);
+webkit_credential_get_username            (WebKitCredential            *credential);
 
 WEBKIT_API const gchar *
-webkit_credential_get_password         (WebKitCredential            *credential);
+webkit_credential_get_password            (WebKitCredential            *credential);
 
 WEBKIT_API gboolean
-webkit_credential_has_password         (WebKitCredential            *credential);
+webkit_credential_has_password            (WebKitCredential            *credential);
 
+WEBKIT_API GTlsCertificate *
+webkit_credential_get_certificate         (WebKitCredential            *credential);
+
 WEBKIT_API WebKitCredentialPersistence
-webkit_credential_get_persistence      (WebKitCredential            *credential);
+webkit_credential_get_persistence         (WebKitCredential            *credential);
 
 G_END_DECLS
 

Modified: trunk/Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt (279871 => 279872)


--- trunk/Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt	2021-07-13 14:19:38 UTC (rev 279872)
@@ -360,6 +360,7 @@
 webkit_authentication_request_set_proposed_credential
 webkit_authentication_request_get_realm
 webkit_authentication_request_get_scheme
+webkit_authentication_request_get_certificate_pin_flags
 webkit_authentication_request_is_for_proxy
 
 <SUBSECTION Standard>
@@ -381,6 +382,8 @@
 WebKitCredential
 WebKitCredentialPersistence
 webkit_credential_new
+webkit_credential_new_for_certificate_pin
+webkit_credential_new_for_certificate
 webkit_credential_copy
 webkit_credential_free
 webkit_credential_get_password
@@ -387,6 +390,7 @@
 webkit_credential_get_persistence
 webkit_credential_get_username
 webkit_credential_has_password
+webkit_credential_get_certificate
 </SECTION>
 
 <SECTION>

Modified: trunk/Source/cmake/OptionsGTK.cmake (279871 => 279872)


--- trunk/Source/cmake/OptionsGTK.cmake	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/cmake/OptionsGTK.cmake	2021-07-13 14:19:38 UTC (rev 279872)
@@ -209,7 +209,7 @@
     set(SOUP_MINIMUM_VERSION 2.54.0)
     set(SOUP_API_VERSION 2.4)
 else ()
-    set(SOUP_MINIMUM_VERSION 2.99.8)
+    set(SOUP_MINIMUM_VERSION 2.99.9)
     set(SOUP_API_VERSION 3.0)
     set(ENABLE_SERVER_PRECONNECT ON)
 endif ()

Modified: trunk/Source/cmake/OptionsWPE.cmake (279871 => 279872)


--- trunk/Source/cmake/OptionsWPE.cmake	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Source/cmake/OptionsWPE.cmake	2021-07-13 14:19:38 UTC (rev 279872)
@@ -124,7 +124,7 @@
     set(WPE_API_VERSION 1.0)
     set(WPE_API_DOC_VERSION 1.0)
 else ()
-    set(SOUP_MINIMUM_VERSION 2.99.8)
+    set(SOUP_MINIMUM_VERSION 2.99.9)
     set(SOUP_API_VERSION 3.0)
     set(WPE_API_VERSION 1.1)
     # No API changes in 1.1, so keep using the same API documentation.

Modified: trunk/Tools/ChangeLog (279871 => 279872)


--- trunk/Tools/ChangeLog	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Tools/ChangeLog	2021-07-13 14:19:38 UTC (rev 279872)
@@ -1,3 +1,32 @@
+2021-07-13  Carlos Garcia Campos  <[email protected]>
+
+        [GTK][WPE] Expose support for client certificate auth
+        https://bugs.webkit.org/show_bug.cgi?id=200805
+
+        Reviewed by Michael Catanzaro.
+
+        Add a simple implementation in MiniBrowser using a file chooser to ask for the certificate from a file and unit
+        tests for the client certificate request. Unfortunately we can't easily test pin certificates.
+
+        * MiniBrowser/gtk/BrowserTab.c:
+        (certificateDialogResponse):
+        (webViewAuthenticate):
+        (browserTabConstructed):
+        * TestWebKitAPI/Tests/WebKitGLib/TestSSL.cpp:
+        (ClientSideCertificateTest::acceptCertificateCallback):
+        (ClientSideCertificateTest::requestStartedCallback):
+        (ClientSideCertificateTest::authenticateCallback):
+        (ClientSideCertificateTest::ClientSideCertificateTest):
+        (ClientSideCertificateTest::~ClientSideCertificateTest):
+        (ClientSideCertificateTest::authenticate):
+        (ClientSideCertificateTest::acceptCertificate):
+        (ClientSideCertificateTest::waitForAuthenticationRequest):
+        (testClientSideCertificate):
+        (beforeAll):
+        * TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp:
+        * TestWebKitAPI/glib/WebKitGLib/WebKitTestServer.h:
+        (WebKitTestServer::soupServer const):
+
 2021-07-12  Filip Pizlo  <[email protected]> and Yusuke Suzuki  <[email protected]>
 
         New malloc algorithm

Modified: trunk/Tools/MiniBrowser/gtk/BrowserTab.c (279871 => 279872)


--- trunk/Tools/MiniBrowser/gtk/BrowserTab.c	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Tools/MiniBrowser/gtk/BrowserTab.c	2021-07-13 14:19:38 UTC (rev 279872)
@@ -443,6 +443,61 @@
         g_warning("WebProcess CRASHED");
 }
 
+static void certificateDialogResponse(GtkDialog *dialog, int response, WebKitAuthenticationRequest *request)
+{
+    if (response == GTK_RESPONSE_ACCEPT) {
+        GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(dialog));
+        if (file) {
+            char *path = g_file_get_path(file);
+            GError *error = NULL;
+            GTlsCertificate *certificate = g_tls_certificate_new_from_file(path, &error);
+            if (certificate) {
+                WebKitCredential *credential = webkit_credential_new_for_certificate(certificate, WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION);
+                webkit_authentication_request_authenticate(request, credential);
+                webkit_credential_free(credential);
+                g_object_unref(certificate);
+            } else {
+                g_warning("Failed to create certificate for %s", path);
+                g_error_free(error);
+            }
+            g_free(path);
+            g_object_unref(file);
+        }
+    } else
+        webkit_authentication_request_authenticate(request, NULL);
+
+    g_object_unref(request);
+
+#if GTK_CHECK_VERSION(3, 98, 5)
+    gtk_window_destroy(GTK_WINDOW(dialog));
+#else
+    gtk_widget_destroy(GTK_WIDGET(dialog));
+#endif
+}
+
+static gboolean webViewAuthenticate(WebKitWebView *webView, WebKitAuthenticationRequest *request, BrowserTab *tab)
+{
+    if (webkit_authentication_request_get_scheme(request) != WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED)
+        return FALSE;
+
+#if GTK_CHECK_VERSION(3, 98, 5)
+    GtkWindow *window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(tab)));
+#else
+    GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(tab)));
+#endif
+    GtkWidget *fileChooser = gtk_file_chooser_dialog_new("Certificate required", window, GTK_FILE_CHOOSER_ACTION_OPEN, "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
+    GtkFileFilter *filter = gtk_file_filter_new();
+    gtk_file_filter_set_name(filter, "PEM Certificate");
+    gtk_file_filter_add_mime_type(filter, "application/x-x509-ca-cert");
+    gtk_file_filter_add_pattern(filter, "*.pem");
+    gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fileChooser), filter);
+
+    g_signal_connect(fileChooser, "response", G_CALLBACK(certificateDialogResponse), g_object_ref(request));
+    gtk_widget_show(fileChooser);
+
+    return TRUE;
+}
+
 static gboolean inspectorOpenedInWindow(WebKitWebInspector *inspector, BrowserTab *tab)
 {
     tab->inspectorIsVisible = TRUE;
@@ -653,6 +708,7 @@
     g_signal_connect(tab->webView, "permission-request", G_CALLBACK(decidePermissionRequest), tab);
     g_signal_connect(tab->webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), tab);
     g_signal_connect(tab->webView, "web-process-terminated", G_CALLBACK(webProcessTerminatedCallback), NULL);
+    g_signal_connect(tab->webView, "authenticate", G_CALLBACK(webViewAuthenticate), tab);
 
     g_object_bind_property(tab->webView, "is-playing-audio", tab->titleAudioButton, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
     g_signal_connect(tab->webView, "notify::is-muted", G_CALLBACK(audioMutedChanged), tab);

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestSSL.cpp (279871 => 279872)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestSSL.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestSSL.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -477,6 +477,171 @@
     g_assert_false(test->m_loadEvents.contains(LoadTrackingTest::LoadCommitted));
 }
 
+#if !USE(SOUP2)
+class ClientSideCertificateTest : public LoadTrackingTest {
+public:
+    MAKE_GLIB_TEST_FIXTURE(ClientSideCertificateTest);
+
+    static gboolean acceptCertificateCallback(SoupServerMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors, ClientSideCertificateTest* test)
+    {
+        bool acceptedCertificate = test->acceptCertificate(errors);
+        g_object_set_data_full(G_OBJECT(message), acceptedCertificate ? "accepted-certificate" : "rejected-certificate", g_object_ref(certificate), g_object_unref);
+        return acceptedCertificate;
+    }
+
+    static void requestStartedCallback(SoupServer*, SoupServerMessage* message, ClientSideCertificateTest* test)
+    {
+        g_signal_connect(message, "accept-certificate", G_CALLBACK(acceptCertificateCallback), test);
+    }
+
+    static gboolean authenticateCallback(WebKitWebView*, WebKitAuthenticationRequest* request, ClientSideCertificateTest* test)
+    {
+        test->authenticate(request);
+        return TRUE;
+    }
+
+    ClientSideCertificateTest()
+    {
+        CString resourcesDir = Test::getResourcesDir();
+        GUniquePtr<char> sslCertificateFile(g_build_filename(resourcesDir.data(), "test-cert.pem", nullptr));
+        GUniquePtr<char> sslKeyFile(g_build_filename(resourcesDir.data(), "test-key.pem", nullptr));
+        GUniqueOutPtr<GError> error;
+        m_clientCertificate = adoptGRef(g_tls_certificate_new_from_files(sslCertificateFile.get(), sslKeyFile.get(), &error.outPtr()));
+        g_assert_no_error(error.get());
+
+        soup_server_set_tls_auth_mode(kHttpsServer->soupServer(), G_TLS_AUTHENTICATION_REQUIRED);
+        g_signal_connect(kHttpsServer->soupServer(), "request-started", G_CALLBACK(requestStartedCallback), this);
+        g_signal_connect(m_webView, "authenticate", G_CALLBACK(authenticateCallback), this);
+    }
+
+    ~ClientSideCertificateTest()
+    {
+        soup_server_set_tls_auth_mode(kHttpsServer->soupServer(), G_TLS_AUTHENTICATION_NONE);
+        g_signal_handlers_disconnect_by_data(kHttpsServer->soupServer(), this);
+    }
+
+    void authenticate(WebKitAuthenticationRequest* request)
+    {
+        assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
+        m_authenticationRequest = request;
+        g_main_loop_quit(m_mainLoop);
+    }
+
+    bool acceptCertificate(GTlsCertificateFlags errors)
+    {
+        if (m_rejectClientCertificates)
+            return false;
+
+        // We always expect errors because we are using a self-signed certificate,
+        // but only G_TLS_CERTIFICATE_UNKNOWN_CA flags should be present.
+        return !errors || errors == G_TLS_CERTIFICATE_UNKNOWN_CA;
+    }
+
+    WebKitAuthenticationRequest* waitForAuthenticationRequest()
+    {
+        m_authenticationRequest = nullptr;
+        g_main_loop_run(m_mainLoop);
+        return m_authenticationRequest.get();
+    }
+
+    GRefPtr<WebKitAuthenticationRequest> m_authenticationRequest;
+    GRefPtr<GTlsCertificate> m_clientCertificate;
+    bool m_rejectClientCertificates { false };
+};
+
+static void testClientSideCertificate(ClientSideCertificateTest* test, gconstpointer)
+{
+    // Ignore server certificate errors.
+    auto* websiteDataManager = webkit_web_context_get_website_data_manager(test->m_webContext.get());
+    WebKitTLSErrorsPolicy originalPolicy = webkit_website_data_manager_get_tls_errors_policy(websiteDataManager);
+    webkit_website_data_manager_set_tls_errors_policy(websiteDataManager, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+
+    // Cancel the authentiation request.
+    test->loadURI(kHttpsServer->getURIForPath("/").data());
+    auto* request = test->waitForAuthenticationRequest();
+    g_assert_cmpstr(webkit_authentication_request_get_realm(request), ==, "");
+    g_assert_cmpint(webkit_authentication_request_get_scheme(request), ==, WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED);
+    g_assert_false(webkit_authentication_request_is_for_proxy(request));
+    g_assert_false(webkit_authentication_request_is_retry(request));
+    auto* origin = webkit_authentication_request_get_security_origin(request);
+    g_assert_nonnull(origin);
+    ASSERT_CMP_CSTRING(webkit_security_origin_get_protocol(origin), ==, kHttpsServer->baseURL().protocol().toString().utf8());
+    ASSERT_CMP_CSTRING(webkit_security_origin_get_host(origin), ==, kHttpsServer->baseURL().host().toString().utf8());
+    g_assert_cmpuint(webkit_security_origin_get_port(origin), ==, kHttpsServer->port());
+    webkit_security_origin_unref(origin);
+    webkit_authentication_request_cancel(request);
+    test->waitUntilLoadFinished();
+    g_assert_cmpint(test->m_loadEvents.size(), ==, 3);
+    g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
+    g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::ProvisionalLoadFailed);
+    g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
+    g_assert_error(test->m_error.get(), WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED);
+    test->m_loadEvents.clear();
+
+    // Complete the request with no credential.
+    test->loadURI(kHttpsServer->getURIForPath("/").data());
+    request = test->waitForAuthenticationRequest();
+    webkit_authentication_request_authenticate(request, nullptr);
+    test->waitUntilLoadFinished();
+    g_assert_cmpint(test->m_loadEvents.size(), ==, 3);
+    g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
+    g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::ProvisionalLoadFailed);
+    g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
+    // Sometimes glib-networking fails to report the error as certificate required and we end up
+    // with connection reset by peer because the server closes the connection.
+    if (!g_error_matches(test->m_error.get(), G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
+        g_assert_error(test->m_error.get(), G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
+    test->m_loadEvents.clear();
+
+    // Complete the request with a credential with no certificate.
+    test->loadURI(kHttpsServer->getURIForPath("/").data());
+    request = test->waitForAuthenticationRequest();
+    WebKitCredential* credential = webkit_credential_new_for_certificate(nullptr, WEBKIT_CREDENTIAL_PERSISTENCE_NONE);
+    webkit_authentication_request_authenticate(request, credential);
+    webkit_credential_free(credential);
+    test->waitUntilLoadFinished();
+    g_assert_cmpint(test->m_loadEvents.size(), ==, 3);
+    g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
+    g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::ProvisionalLoadFailed);
+    g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
+    if (!g_error_matches(test->m_error.get(), G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
+        g_assert_error(test->m_error.get(), G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
+    test->m_loadEvents.clear();
+
+    // Complete the request with a credential with an invalid certificate.
+    test->m_rejectClientCertificates = true;
+    test->loadURI(kHttpsServer->getURIForPath("/").data());
+    request = test->waitForAuthenticationRequest();
+    credential = webkit_credential_new_for_certificate(test->m_clientCertificate.get(), WEBKIT_CREDENTIAL_PERSISTENCE_NONE);
+    webkit_authentication_request_authenticate(request, credential);
+    webkit_credential_free(credential);
+    test->waitUntilLoadFinished();
+    g_assert_cmpint(test->m_loadEvents.size(), ==, 3);
+    g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
+    g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::ProvisionalLoadFailed);
+    g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
+    if (!g_error_matches(test->m_error.get(), G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
+        g_assert_error(test->m_error.get(), G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
+    test->m_loadEvents.clear();
+    test->m_rejectClientCertificates = false;
+
+    // Complete the request with a credential with a valid certificate.
+    test->loadURI(kHttpsServer->getURIForPath("/").data());
+    request = test->waitForAuthenticationRequest();
+    credential = webkit_credential_new_for_certificate(test->m_clientCertificate.get(), WEBKIT_CREDENTIAL_PERSISTENCE_NONE);
+    webkit_authentication_request_authenticate(request, credential);
+    webkit_credential_free(credential);
+    test->waitUntilLoadFinished();
+    g_assert_cmpint(test->m_loadEvents.size(), ==, 3);
+    g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
+    g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
+    g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
+    test->m_loadEvents.clear();
+
+    webkit_website_data_manager_set_tls_errors_policy(websiteDataManager, originalPolicy);
+}
+#endif
+
 #if USE(SOUP2)
 static void httpsServerCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
 #else
@@ -577,6 +742,9 @@
     TLSErrorsTest::add("WebKitWebView", "load-failed-with-tls-errors", testLoadFailedWithTLSErrors);
     WebSocketTest::add("WebKitWebView", "web-socket-tls-errors", testWebSocketTLSErrors);
     EphemeralSSLTest::add("WebKitWebView", "ephemeral-tls-errors", testTLSErrorsEphemeral);
+#if !USE(SOUP2)
+    ClientSideCertificateTest::add("WebKitWebView", "client-side-certificate", testClientSideCertificate);
+#endif
 }
 
 void afterAll()

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp (279871 => 279872)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp	2021-07-13 14:19:38 UTC (rev 279872)
@@ -675,6 +675,9 @@
         g_error("Failed to register object: %s\n", error->message);
 
     g_object_set_data_full(G_OBJECT(userData), "dbus-connection", connection, g_object_unref);
+    g_signal_connect_object(connection, "closed", G_CALLBACK(+[](GDBusConnection*, gboolean, GError*, gpointer userData) {
+        g_object_set_data_full(G_OBJECT(userData), "dbus-connection", nullptr, nullptr);
+    }), userData, static_cast<GConnectFlags>(0));
     while (delayedSignalsQueue.size()) {
         DelayedSignal delayedSignal = delayedSignalsQueue.takeFirst();
         switch (delayedSignal.type) {

Modified: trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebKitTestServer.h (279871 => 279872)


--- trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebKitTestServer.h	2021-07-13 12:54:02 UTC (rev 279871)
+++ trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebKitTestServer.h	2021-07-13 14:19:38 UTC (rev 279872)
@@ -40,6 +40,7 @@
     WebKitTestServer(ServerOptions option)
         : WebKitTestServer(ServerOptionsBitSet().set(option)) { }
 
+    SoupServer* soupServer() const { return m_soupServer.get(); }
     const URL& baseURL() const { return m_baseURL; }
     unsigned port() const;
     CString getURIForPath(const char* path) const;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to