Add specialization for encoding/decoding WebCore::CertificateInfos in the Network...
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 25 Jul 2016 00:48:51 +0000 (00:48 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 25 Jul 2016 00:48:51 +0000 (00:48 +0000)
<rdar://problem/27409315>
https://bugs.webkit.org/show_bug.cgi?id=160144

Reviewed by Chris Dumez.

* NetworkProcess/cache/NetworkCacheCoders.cpp:
(WebKit::NetworkCache::encodeCFData):
(WebKit::NetworkCache::decodeCFData):
(WebKit::NetworkCache::encodeSecTrustRef):
(WebKit::NetworkCache::decodeSecTrustRef):
(WebKit::NetworkCache::encodeCertificateChain):
(WebKit::NetworkCache::decodeCertificateChain):
(WebKit::NetworkCache::Coder<WebCore::CertificateInfo>::encode):
(WebKit::NetworkCache::Coder<WebCore::CertificateInfo>::decode):

* NetworkProcess/cache/NetworkCacheStorage.h:
(WebKit::NetworkCache::Storage::version):
Bump the version and lastStableVersion to account for the format change.

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

Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h

index 35eef7b..7309556 100644 (file)
@@ -1,3 +1,25 @@
+2016-07-24  Sam Weinig  <sam@webkit.org>
+
+        Add specialization for encoding/decoding WebCore::CertificateInfos in the Network Cache
+        <rdar://problem/27409315>
+        https://bugs.webkit.org/show_bug.cgi?id=160144
+
+        Reviewed by Chris Dumez.
+
+        * NetworkProcess/cache/NetworkCacheCoders.cpp:
+        (WebKit::NetworkCache::encodeCFData):
+        (WebKit::NetworkCache::decodeCFData):
+        (WebKit::NetworkCache::encodeSecTrustRef):
+        (WebKit::NetworkCache::decodeSecTrustRef):
+        (WebKit::NetworkCache::encodeCertificateChain):
+        (WebKit::NetworkCache::decodeCertificateChain):
+        (WebKit::NetworkCache::Coder<WebCore::CertificateInfo>::encode):
+        (WebKit::NetworkCache::Coder<WebCore::CertificateInfo>::decode):
+
+        * NetworkProcess/cache/NetworkCacheStorage.h:
+        (WebKit::NetworkCache::Storage::version):
+        Bump the version and lastStableVersion to account for the format change.
+
 2016-07-22  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Automation: All key events should be processed before sending response
index 3803a21..03f1283 100644 (file)
 
 #if ENABLE(NETWORK_CACHE)
 
-#include "WebCoreArgumentCoders.h"
 #include <wtf/text/CString.h>
 #include <wtf/text/WTFString.h>
 
+#if PLATFORM(COCOA)
+#include <Security/SecCertificate.h>
+#include <Security/SecTrust.h>
+#include <wtf/spi/cocoa/SecuritySPI.h>
+#endif
+
 namespace WebKit {
 namespace NetworkCache {
 
@@ -145,26 +150,215 @@ bool Coder<String>::decode(Decoder& decoder, String& result)
     return decodeStringText<UChar>(decoder, length, result);
 }
 
+#if PLATFORM(COCOA)
+static void encodeCFData(Encoder& encoder, CFDataRef data)
+{
+    uint64_t length = CFDataGetLength(data);
+    const uint8_t* bytePtr = CFDataGetBytePtr(data);
+
+    encoder << length;
+    encoder.encodeFixedLengthData(bytePtr, length);
+}
+
+static bool decodeCFData(Decoder& decoder, RetainPtr<CFDataRef>& data)
+{
+    uint64_t size = 0;
+    if (!decoder.decode(size))
+        return false;
+
+    Vector<uint8_t> vector(size);
+    if (!decoder.decodeFixedLengthData(vector.data(), vector.size()))
+        return false;
+
+    data = adoptCF(CFDataCreate(nullptr, vector.data(), vector.size()));
+    return true;
+}
+
+
+#if HAVE(SEC_TRUST_SERIALIZATION)
+static void encodeSecTrustRef(Encoder& encoder, SecTrustRef trust)
+{
+    auto data = adoptCF(SecTrustSerialize(trust, nullptr));
+    if (!data) {
+        encoder << false;
+        return;
+    }
+
+    encoder << true;
+    encodeCFData(encoder, data.get());
+}
+
+static bool decodeSecTrustRef(Decoder& decoder, RetainPtr<SecTrustRef>& result)
+{
+    bool hasTrust;
+    if (!decoder.decode(hasTrust))
+        return false;
+
+    if (!hasTrust)
+        return true;
+
+    RetainPtr<CFDataRef> trustData;
+    if (!decodeCFData(decoder, trustData))
+        return false;
+
+    auto trust = adoptCF(SecTrustDeserialize(trustData.get(), nullptr));
+    if (!trust)
+        return false;
+
+    result = WTFMove(trust);
+    return true;
+}
+#endif
+
+static void encodeCertificateChain(Encoder& encoder, CFArrayRef certificateChain)
+{
+    CFIndex size = CFArrayGetCount(certificateChain);
+    Vector<CFTypeRef, 32> values(size);
+
+    CFArrayGetValues(certificateChain, CFRangeMake(0, size), values.data());
+
+    encoder << static_cast<uint64_t>(size);
+
+    for (CFIndex i = 0; i < size; ++i) {
+        ASSERT(values[i]);
+        ASSERT(CFGetTypeID(values[i]) != SecCertificateGetTypeID());
+
+        auto data = adoptCF(SecCertificateCopyData((SecCertificateRef)values[i]));
+        encodeCFData(encoder, data.get());
+    }
+}
+
+static bool decodeCertificateChain(Decoder& decoder, RetainPtr<CFArrayRef>& certificateChain)
+{
+    uint64_t size;
+    if (!decoder.decode(size))
+        return false;
+
+    auto array = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
+
+    for (size_t i = 0; i < size; ++i) {
+        RetainPtr<CFDataRef> data;
+        if (!decodeCFData(decoder, data))
+            return false;
+
+        auto certificate = adoptCF(SecCertificateCreateWithData(0, data.get()));
+        CFArrayAppendValue(array.get(), certificate.get());
+    }
+
+    certificateChain = WTFMove(array);
+    return true;
+}
+
 void Coder<WebCore::CertificateInfo>::encode(Encoder& encoder, const WebCore::CertificateInfo& certificateInfo)
 {
-    // FIXME: Cocoa CertificateInfo is a CF object tree. Generalize CF type coding so we don't need to use ArgumentCoder here.
-    IPC::ArgumentEncoder argumentEncoder;
-    argumentEncoder << certificateInfo;
-    encoder << static_cast<uint64_t>(argumentEncoder.bufferSize());
-    encoder.encodeFixedLengthData(argumentEncoder.buffer(), argumentEncoder.bufferSize());
+    encoder.encodeEnum(certificateInfo.type());
+
+    switch (certificateInfo.type()) {
+#if HAVE(SEC_TRUST_SERIALIZATION)
+    case WebCore::CertificateInfo::Type::Trust:
+        encodeSecTrustRef(encoder, certificateInfo.trust());
+        break;
+#endif
+    case WebCore::CertificateInfo::Type::CertificateChain: {
+        encodeCertificateChain(encoder, certificateInfo.certificateChain());
+        break;
+    }
+    case WebCore::CertificateInfo::Type::None:
+        // Do nothing.
+        break;
+    }
 }
 
 bool Coder<WebCore::CertificateInfo>::decode(Decoder& decoder, WebCore::CertificateInfo& certificateInfo)
 {
-    uint64_t certificateSize;
-    if (!decoder.decode(certificateSize))
+    WebCore::CertificateInfo::Type certificateInfoType;
+    if (!decoder.decodeEnum(certificateInfoType))
         return false;
-    Vector<uint8_t> data(certificateSize);
-    if (!decoder.decodeFixedLengthData(data.data(), data.size()))
+
+    switch (certificateInfoType) {
+#if HAVE(SEC_TRUST_SERIALIZATION)
+    case WebCore::CertificateInfo::Type::Trust: {
+        RetainPtr<SecTrustRef> trust;
+        if (!decodeSecTrustRef(decoder, trust))
+            return false;
+
+        certificateInfo = WebCore::CertificateInfo(WTFMove(trust));
+        return true;
+    }
+#endif
+    case WebCore::CertificateInfo::Type::CertificateChain: {
+        RetainPtr<CFArrayRef> certificateChain;
+        if (!decodeCertificateChain(decoder, certificateChain))
+            return false;
+
+        certificateInfo = WebCore::CertificateInfo(WTFMove(certificateChain));
+        return true;
+    }    
+    case WebCore::CertificateInfo::Type::None:
+        // Do nothing.
+        break;
+    }
+
+    return true;
+}
+#else
+void Coder<WebCore::CertificateInfo>::encode(Encoder& encoder, const WebCore::CertificateInfo& certificateInfo)
+{
+    if (!certificateInfo.certificate()) {
+        encoder << false;
+        return;
+    }
+
+    GByteArray* certificateData = 0;
+    g_object_get(G_OBJECT(certificateInfo.certificate()), "certificate", &certificateData, NULL);
+    if (!certificateData) {
+        encoder << false;
+        return;
+    }
+
+    encoder << true;
+
+    GRefPtr<GByteArray> certificate = adoptGRef(certificateData);
+    encoder << static_cast<uint64_t>(certificate->len);
+    encoder.encodeFixedLengthData(certificate->data, certificate->len);
+
+    encoder << static_cast<uint32_t>(certificateInfo.tlsErrors());
+}
+
+bool Coder<WebCore::CertificateInfo>::decode(Decoder& decoder, WebCore::CertificateInfo& certificateInfo)
+{
+    bool hasCertificate;
+    if (!decoder.decode(hasCertificate))
+        return false;
+
+    if (!hasCertificate)
+        return true;
+
+    uint64_t size = 0;
+    if (!decoder.decode(size))
+        return false;
+
+    Vector<uint8_t> vector(size);
+    if (!decoder.decodeFixedLengthData(vector.data(), vector.size()))
+        return false;
+
+    GByteArray* certificateData = g_byte_array_sized_new(vector.size());
+    certificateData = g_byte_array_append(certificateData, vector.data(), vector.size());
+    GRefPtr<GByteArray> certificateBytes = adoptGRef(certificateData);
+
+    GTlsBackend* backend = g_tls_backend_get_default();
+    GRefPtr<GTlsCertificate> certificate = adoptGRef(G_TLS_CERTIFICATE(g_initable_new(
+        g_tls_backend_get_certificate_type(backend), 0, 0, "certificate", certificateBytes.get(), nullptr)));
+    certificateInfo.setCertificate(certificate.get());
+
+    uint32_t tlsErrors;
+    if (!decoder.decode(tlsErrors))
         return false;
-    IPC::ArgumentDecoder argumentDecoder(data.data(), data.size());
-    return argumentDecoder.decode(certificateInfo);
+    certificateInfo.setTLSErrors(static_cast<GTlsCertificateFlags>(tlsErrors));
+
+    return true;
 }
+#endif
 
 void Coder<SHA1::Digest>::encode(Encoder& encoder, const SHA1::Digest& digest)
 {
index f6c9c23..462c088 100644 (file)
@@ -87,10 +87,10 @@ public:
     size_t capacity() const { return m_capacity; }
     size_t approximateSize() const;
 
-    static const unsigned version = 8;
+    static const unsigned version = 9;
 #if PLATFORM(MAC)
     /// Allow the last stable version of the cache to co-exist with the latest development one.
-    static const unsigned lastStableVersion = 8;
+    static const unsigned lastStableVersion = 9;
 #endif
 
     String basePath() const;