Title: [274738] branches/safari-611.1.21.1-branch
Revision
274738
Author
[email protected]
Date
2021-03-19 14:25:13 -0700 (Fri, 19 Mar 2021)

Log Message

Cherry-pick r273875. rdar://problem/75635901

    WKRemoteObjectCoder should be able to handle NSErrors from TLS failures
    https://bugs.webkit.org/show_bug.cgi?id=222401
    Source/WebKit:

    <rdar://problem/72103865>

    Patch by Alex Christensen <[email protected]> on 2021-03-03
    Reviewed by Chris Dumez.

    NSErrors from TLS failures contain values like a SecTrustRef or a SecCertificateRef,
    which are not ObjC objects, and they don't like it when you call encodeWithCoder: on them.
    Until r273141 it would crash when we do, but even after that we just decode a nil NSError.
    Add a special case like we did in encodeNSError to successfully encode and decode these errors.

    * Shared/API/Cocoa/WKRemoteObjectCoder.mm:
    (decodeObjCObject):
    (transformCertificatesToData):
    (transformTrustToData):
    (encodeError):
    (transformDataToCertificates):
    (transformDataToTrust):
    (decodeError):
    (encodeObject):
    (decodeObject):

    Tools:

    Patch by Alex Christensen <[email protected]> on 2021-03-03
    Reviewed by Chris Dumez.

    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.h:
    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.mm:
    (TEST):
    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistryPlugIn.mm:
    (-[RemoteObjectRegistryPlugIn sendError:completionHandler:]):

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

Modified Paths

Diff

Modified: branches/safari-611.1.21.1-branch/Source/WebKit/ChangeLog (274737 => 274738)


--- branches/safari-611.1.21.1-branch/Source/WebKit/ChangeLog	2021-03-19 21:20:02 UTC (rev 274737)
+++ branches/safari-611.1.21.1-branch/Source/WebKit/ChangeLog	2021-03-19 21:25:13 UTC (rev 274738)
@@ -1,5 +1,71 @@
 2021-03-19  Russell Epstein  <[email protected]>
 
+        Cherry-pick r273875. rdar://problem/75635901
+
+    WKRemoteObjectCoder should be able to handle NSErrors from TLS failures
+    https://bugs.webkit.org/show_bug.cgi?id=222401
+    Source/WebKit:
+    
+    <rdar://problem/72103865>
+    
+    Patch by Alex Christensen <[email protected]> on 2021-03-03
+    Reviewed by Chris Dumez.
+    
+    NSErrors from TLS failures contain values like a SecTrustRef or a SecCertificateRef,
+    which are not ObjC objects, and they don't like it when you call encodeWithCoder: on them.
+    Until r273141 it would crash when we do, but even after that we just decode a nil NSError.
+    Add a special case like we did in encodeNSError to successfully encode and decode these errors.
+    
+    * Shared/API/Cocoa/WKRemoteObjectCoder.mm:
+    (decodeObjCObject):
+    (transformCertificatesToData):
+    (transformTrustToData):
+    (encodeError):
+    (transformDataToCertificates):
+    (transformDataToTrust):
+    (decodeError):
+    (encodeObject):
+    (decodeObject):
+    
+    Tools:
+    
+    Patch by Alex Christensen <[email protected]> on 2021-03-03
+    Reviewed by Chris Dumez.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.h:
+    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.mm:
+    (TEST):
+    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistryPlugIn.mm:
+    (-[RemoteObjectRegistryPlugIn sendError:completionHandler:]):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@273875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-03-03  Alex Christensen  <[email protected]>
+
+            WKRemoteObjectCoder should be able to handle NSErrors from TLS failures
+            https://bugs.webkit.org/show_bug.cgi?id=222401
+            <rdar://problem/72103865>
+
+            Reviewed by Chris Dumez.
+
+            NSErrors from TLS failures contain values like a SecTrustRef or a SecCertificateRef,
+            which are not ObjC objects, and they don't like it when you call encodeWithCoder: on them.
+            Until r273141 it would crash when we do, but even after that we just decode a nil NSError.
+            Add a special case like we did in encodeNSError to successfully encode and decode these errors.
+
+            * Shared/API/Cocoa/WKRemoteObjectCoder.mm:
+            (decodeObjCObject):
+            (transformCertificatesToData):
+            (transformTrustToData):
+            (encodeError):
+            (transformDataToCertificates):
+            (transformDataToTrust):
+            (decodeError):
+            (encodeObject):
+            (decodeObject):
+
+2021-03-19  Russell Epstein  <[email protected]>
+
         Apply patch. rdar://problem/75625529
 
     2021-03-19  Per Arne Vollan  <[email protected]>

Modified: branches/safari-611.1.21.1-branch/Source/WebKit/Shared/API/Cocoa/WKRemoteObjectCoder.mm (274737 => 274738)


--- branches/safari-611.1.21.1-branch/Source/WebKit/Shared/API/Cocoa/WKRemoteObjectCoder.mm	2021-03-19 21:20:02 UTC (rev 274737)
+++ branches/safari-611.1.21.1-branch/Source/WebKit/Shared/API/Cocoa/WKRemoteObjectCoder.mm	2021-03-19 21:25:13 UTC (rev 274738)
@@ -33,6 +33,7 @@
 #import "APIString.h"
 #import "Logging.h"
 #import "NSInvocationSPI.h"
+#import "_WKErrorRecoveryAttempting.h"
 #import "_WKRemoteObjectInterfaceInternal.h"
 #import <objc/runtime.h>
 #import <wtf/RetainPtr.h>
@@ -295,6 +296,120 @@
     encoder->_currentDictionary->set(stringKey, API::String::create(string));
 }
 
+static RetainPtr<id> decodeObjCObject(WKRemoteObjectDecoder *decoder, Class objectClass)
+{
+    id allocation = [objectClass allocWithZone:decoder.zone];
+    if (!allocation)
+        [NSException raise:NSInvalidUnarchiveOperationException format:@"Class \"%@\" returned nil from +alloc while being decoded", NSStringFromClass(objectClass)];
+
+    RetainPtr<id> result = adoptNS([allocation initWithCoder:decoder]);
+    if (!result)
+        [NSException raise:NSInvalidUnarchiveOperationException format:@"Object of class \"%@\" returned nil from -initWithCoder: while being decoded", NSStringFromClass(objectClass)];
+
+    result = [result awakeAfterUsingCoder:decoder];
+    if (!result)
+        [NSException raise:NSInvalidUnarchiveOperationException format:@"Object of class \"%@\" returned nil from -awakeAfterUsingCoder: while being decoded", NSStringFromClass(objectClass)];
+
+    return result;
+}
+
+static constexpr NSString *peerCertificateKey = @"NSErrorPeerCertificateChainKey";
+static constexpr NSString *peerTrustKey = @"NSURLErrorFailingURLPeerTrustErrorKey";
+static constexpr NSString *clientCertificateKey = @"NSErrorClientCertificateChainKey";
+
+static RetainPtr<NSArray<NSData *>> transformCertificatesToData(NSArray *input)
+{
+    auto dataArray = adoptNS([[NSMutableArray alloc] initWithCapacity:input.count]);
+    for (id certificate in input) {
+        if (CFGetTypeID(certificate) != SecCertificateGetTypeID())
+            [NSException raise:NSInvalidArgumentException format:@"Error encoding invalid certificate in chain"];
+        [dataArray addObject:(NSData *)adoptCF(SecCertificateCopyData((SecCertificateRef)certificate)).get()];
+    }
+    return dataArray;
+}
+
+static RetainPtr<NSData> transformTrustToData(SecTrustRef trust)
+{
+    if (CFGetTypeID(trust) != SecTrustGetTypeID())
+        [NSException raise:NSInvalidArgumentException format:@"Error encoding invalid SecTrustRef"];
+    CFErrorRef error = nullptr;
+    auto data = "" &error));
+    if (error)
+        [NSException raise:NSInvalidArgumentException format:@"Error serializing SecTrustRef: %@", error];
+    return data;
+}
+
+static void encodeError(WKRemoteObjectEncoder *encoder, NSError *error)
+{
+    RetainPtr<NSMutableDictionary> copy;
+    if (error.userInfo[_WKRecoveryAttempterErrorKey]) {
+        copy = adoptNS([error.userInfo mutableCopy]);
+        [copy removeObjectForKey:_WKRecoveryAttempterErrorKey];
+    }
+    if (error.userInfo[clientCertificateKey]) {
+        if (!copy)
+            copy = adoptNS([error.userInfo mutableCopy]);
+        [copy removeObjectForKey:clientCertificateKey];
+    }
+    if (NSArray *certificateChain = error.userInfo[peerCertificateKey]) {
+        if (!copy)
+            copy = adoptNS([error.userInfo mutableCopy]);
+        copy.get()[peerCertificateKey] = transformCertificatesToData(certificateChain).get();
+    }
+    if (id trust = error.userInfo[peerTrustKey]) {
+        if (!copy)
+            copy = adoptNS([error.userInfo mutableCopy]);
+        copy.get()[peerTrustKey] = transformTrustToData((SecTrustRef)trust).get();
+    }
+    if (!copy)
+        [error encodeWithCoder:encoder];
+    else
+        [[NSError errorWithDomain:error.domain code:error.code userInfo:copy.get()] encodeWithCoder:encoder];
+}
+
+static RetainPtr<NSArray> transformDataToCertificates(NSArray *input)
+{
+    auto array = adoptNS([[NSMutableArray alloc] initWithCapacity:input.count]);
+    for (NSData *data in input) {
+        if (CFGetTypeID(data) != CFDataGetTypeID())
+            [NSException raise:NSInvalidUnarchiveOperationException format:@"Error decoding certificate from object that is not data %@", NSStringFromClass([data class])];
+        auto certificate = adoptCF(SecCertificateCreateWithData(nullptr, (CFDataRef)data));
+        if (!certificate)
+            [NSException raise:NSInvalidUnarchiveOperationException format:@"Error decoding nvalid certificate in chain"];
+        [array addObject:(id)certificate.get()];
+    }
+    return array;
+}
+
+static RetainPtr<id> transformDataToTrust(NSData *data)
+{
+    if (CFGetTypeID(data) != CFDataGetTypeID())
+        [NSException raise:NSInvalidUnarchiveOperationException format:@"Invalid SecTrustRef data %@", NSStringFromClass([data class])];
+    CFErrorRef error = nullptr;
+    auto trust = adoptCF(SecTrustDeserialize((CFDataRef)data, &error));
+    if (error || !trust)
+        [NSException raise:NSInvalidUnarchiveOperationException format:@"Invalid SecTrustRef %@", error];
+    return trust;
+}
+
+static RetainPtr<NSError> decodeError(WKRemoteObjectDecoder *decoder)
+{
+    RetainPtr<NSError> error = decodeObjCObject(decoder, [NSError class]);
+    RetainPtr<NSMutableDictionary> copy;
+    if (NSArray *certificateChain = error.get().userInfo[peerCertificateKey]) {
+        copy = adoptNS([error.get().userInfo mutableCopy]);
+        copy.get()[peerCertificateKey] = transformDataToCertificates(certificateChain).get();
+    }
+    if (NSData *trust = error.get().userInfo[peerTrustKey]) {
+        if (!copy)
+            copy = adoptNS([error.get().userInfo mutableCopy]);
+        copy.get()[peerTrustKey] = transformDataToTrust(trust).get();
+    }
+    if (!copy)
+        return error;
+    return [NSError errorWithDomain:error.get().domain code:error.get().code userInfo:copy.get()];
+}
+
 static void encodeObject(WKRemoteObjectEncoder *encoder, id object)
 {
     ASSERT(object);
@@ -338,6 +453,9 @@
         return;
     }
 
+    if (objectClass == [NSError class])
+        return encodeError(encoder, object);
+    
     [object encodeWithCoder:encoder];
 }
 
@@ -874,23 +992,14 @@
 
     if (objectClass == [NSString class])
         return decodeString(decoder);
+    
+    if (objectClass == [NSError class])
+        return decodeError(decoder).autorelease();
 
     if (objectClass == [NSMutableString class])
         return [NSMutableString stringWithString:decodeString(decoder)];
 
-    id result = [objectClass allocWithZone:decoder.zone];
-    if (!result)
-        [NSException raise:NSInvalidUnarchiveOperationException format:@"Class \"%s\" returned nil from +alloc while being decoded", className.data()];
-
-    result = [result initWithCoder:decoder];
-    if (!result)
-        [NSException raise:NSInvalidUnarchiveOperationException format:@"Object of class \"%s\" returned nil from -initWithCoder: while being decoded", className.data()];
-
-    result = [result awakeAfterUsingCoder:decoder];
-    if (!result)
-        [NSException raise:NSInvalidUnarchiveOperationException format:@"Object of class \"%s\" returned nil from -awakeAfterUsingCoder: while being decoded", className.data()];
-
-    return [result autorelease];
+    return decodeObjCObject(decoder, objectClass).autorelease();
 }
 
 static id decodeObject(WKRemoteObjectDecoder *decoder, const API::Dictionary* dictionary, const HashSet<CFTypeRef>& allowedClasses)

Modified: branches/safari-611.1.21.1-branch/Tools/ChangeLog (274737 => 274738)


--- branches/safari-611.1.21.1-branch/Tools/ChangeLog	2021-03-19 21:20:02 UTC (rev 274737)
+++ branches/safari-611.1.21.1-branch/Tools/ChangeLog	2021-03-19 21:25:13 UTC (rev 274738)
@@ -1,3 +1,58 @@
+2021-03-19  Russell Epstein  <[email protected]>
+
+        Cherry-pick r273875. rdar://problem/75635901
+
+    WKRemoteObjectCoder should be able to handle NSErrors from TLS failures
+    https://bugs.webkit.org/show_bug.cgi?id=222401
+    Source/WebKit:
+    
+    <rdar://problem/72103865>
+    
+    Patch by Alex Christensen <[email protected]> on 2021-03-03
+    Reviewed by Chris Dumez.
+    
+    NSErrors from TLS failures contain values like a SecTrustRef or a SecCertificateRef,
+    which are not ObjC objects, and they don't like it when you call encodeWithCoder: on them.
+    Until r273141 it would crash when we do, but even after that we just decode a nil NSError.
+    Add a special case like we did in encodeNSError to successfully encode and decode these errors.
+    
+    * Shared/API/Cocoa/WKRemoteObjectCoder.mm:
+    (decodeObjCObject):
+    (transformCertificatesToData):
+    (transformTrustToData):
+    (encodeError):
+    (transformDataToCertificates):
+    (transformDataToTrust):
+    (decodeError):
+    (encodeObject):
+    (decodeObject):
+    
+    Tools:
+    
+    Patch by Alex Christensen <[email protected]> on 2021-03-03
+    Reviewed by Chris Dumez.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.h:
+    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.mm:
+    (TEST):
+    * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistryPlugIn.mm:
+    (-[RemoteObjectRegistryPlugIn sendError:completionHandler:]):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@273875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-03-03  Alex Christensen  <[email protected]>
+
+            WKRemoteObjectCoder should be able to handle NSErrors from TLS failures
+            https://bugs.webkit.org/show_bug.cgi?id=222401
+
+            Reviewed by Chris Dumez.
+
+            * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.h:
+            * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.mm:
+            (TEST):
+            * TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistryPlugIn.mm:
+            (-[RemoteObjectRegistryPlugIn sendError:completionHandler:]):
+
 2021-03-08  Russell Epstein  <[email protected]>
 
         Cherry-pick r273997. rdar://problem/75180339

Modified: branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.h (274737 => 274738)


--- branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.h	2021-03-19 21:20:02 UTC (rev 274737)
+++ branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.h	2021-03-19 21:25:13 UTC (rev 274738)
@@ -52,6 +52,7 @@
 - (void)doNotCallCompletionHandler:(void (^)())completionHandler;
 - (void)sendRequest:(NSURLRequest *)request response:(NSURLResponse *)response challenge:(NSURLAuthenticationChallenge *)challenge error:(NSError *)error completionHandler:(void (^)(NSURLRequest *, NSURLResponse *, NSURLAuthenticationChallenge *, NSError *))completionHandler;
 - (void)callUIProcessMethodWithReplyBlock;
+- (void)sendError:(NSError *)error completionHandler:(void (^)(NSError *))completionHandler;
 
 @end
 

Modified: branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.mm (274737 => 274738)


--- branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.mm	2021-03-19 21:20:02 UTC (rev 274737)
+++ branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistry.mm	2021-03-19 21:25:13 UTC (rev 274738)
@@ -25,9 +25,11 @@
 
 #import "config.h"
 
+#import "HTTPServer.h"
 #import "PlatformUtilities.h"
 #import "RemoteObjectRegistry.h"
 #import "Test.h"
+#import "TestNavigationDelegate.h"
 #import "WKWebViewConfigurationExtras.h"
 #import <WebKit/WKProcessPoolPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
@@ -38,7 +40,7 @@
 #import <wtf/RetainPtr.h>
 #import <wtf/WeakObjCPtr.h>
 
-TEST(WebKit, RemoteObjectRegistry)
+TEST(RemoteObjectRegistry, Basic)
 {
     __block bool isDone = false;
 
@@ -207,7 +209,7 @@
 
 @end
 
-TEST(WebKit, RemoteObjectRegistry_CallReplyBlockAfterOriginatingWebViewDeallocates)
+TEST(RemoteObjectRegistry, CallReplyBlockAfterOriginatingWebViewDeallocates)
 {
     LocalObject *localObject = [[[LocalObject alloc] init] autorelease];
     WeakObjCPtr<WKWebView> weakWebViewPtr;
@@ -239,3 +241,28 @@
 
     localObject->completionHandlerFromWebProcess();
 }
+
+TEST(RemoteObjectRegistry, SerializeErrorWithCertificates)
+{
+    TestWebKitAPI::HTTPServer server({ }, TestWebKitAPI::HTTPServer::Protocol::Https);
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:[WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"RemoteObjectRegistryPlugIn"]]);
+    auto delegate = adoptNS([TestNavigationDelegate new]);
+    webView.get().navigationDelegate = delegate.get();
+    [webView loadRequest:server.request()];
+    NSError *error = [delegate waitForDidFailProvisionalNavigation];
+    NSString *key = @"NSErrorPeerCertificateChainKey";
+    EXPECT_WK_STREQ(error.domain, "NSURLErrorDomain");
+    EXPECT_TRUE(error.userInfo[key]);
+    
+    _WKRemoteObjectInterface *interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(RemoteObjectProtocol)];
+    id <RemoteObjectProtocol> object = [[webView _remoteObjectRegistry] remoteObjectProxyWithInterface:interface];
+    __block bool roundTripComplete = false;
+    [object sendError:error completionHandler:^(NSError *deserializedError) {
+        EXPECT_WK_STREQ(deserializedError.domain, "NSURLErrorDomain");
+        NSArray *chain = deserializedError.userInfo[key];
+        EXPECT_TRUE(chain);
+        EXPECT_EQ(CFGetTypeID(chain[0]), SecCertificateGetTypeID());
+        roundTripComplete = true;
+    }];
+    TestWebKitAPI::Util::run(&roundTripComplete);
+}

Modified: branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistryPlugIn.mm (274737 => 274738)


--- branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistryPlugIn.mm	2021-03-19 21:20:02 UTC (rev 274737)
+++ branches/safari-611.1.21.1-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/RemoteObjectRegistryPlugIn.mm	2021-03-19 21:25:13 UTC (rev 274738)
@@ -118,6 +118,11 @@
     completionHandler(request, response, challenge, error);
 }
 
+- (void)sendError:(NSError *)error completionHandler:(void (^)(NSError *))completionHandler
+{
+    completionHandler(error);
+}
+
 - (void)callUIProcessMethodWithReplyBlock
 {
     id <LocalObjectProtocol> localObject = [[_browserContextController _remoteObjectRegistry] remoteObjectProxyWithInterface:localObjectInterface()];
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to