/* * Copyright (C) 2010-2021 Apple Inc. All rights reserved. * Copyright (C) 2013 Company 100 Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "WebCoreArgumentCoders.h" #import "ArgumentCodersCF.h" #import "ArgumentCodersCocoa.h" #import "DaemonDecoder.h" #import "DaemonEncoder.h" #import "DataReference.h" #import #import #import #import #import #import #import #import #import #import #import namespace IPC { template<> void ArgumentCoder::encode(Encoder& encoder, const WebCore::CertificateInfo& certificateInfo) { encoder << certificateInfo.type(); switch (certificateInfo.type()) { #if HAVE(SEC_TRUST_SERIALIZATION) case WebCore::CertificateInfo::Type::Trust: encoder << certificateInfo.trust(); break; #endif case WebCore::CertificateInfo::Type::CertificateChain: encoder << certificateInfo.certificateChain(); break; case WebCore::CertificateInfo::Type::None: // Do nothing. break; } } template<> void ArgumentCoder::encode(WebKit::Daemon::Encoder& encoder, const WebCore::CertificateInfo& certificateInfo) { ASSERT(certificateInfo.type() == WebCore::CertificateInfo::Type::Trust); encoder << certificateInfo.trust(); } template<> std::optional ArgumentCoder::decode(Decoder& decoder) { std::optional certificateInfoType; decoder >> certificateInfoType; if (!certificateInfoType) return std::nullopt; switch (*certificateInfoType) { #if HAVE(SEC_TRUST_SERIALIZATION) case WebCore::CertificateInfo::Type::Trust: { std::optional> trust; decoder >> trust; if (!trust || !*trust) return std::nullopt; return WebCore::CertificateInfo(WTFMove(*trust)); } #endif case WebCore::CertificateInfo::Type::CertificateChain: { std::optional> certificateChain; decoder >> certificateChain; if (!certificateChain || !*certificateChain) return std::nullopt; return WebCore::CertificateInfo(WTFMove(*certificateChain)); } case WebCore::CertificateInfo::Type::None: // Do nothing. break; } return {{ }}; } template<> std::optional ArgumentCoder::decode(WebKit::Daemon::Decoder& decoder) { std::optional> trust; decoder >> trust; if (!trust || !*trust) return std::nullopt; return WebCore::CertificateInfo(WTFMove(*trust)); } static void encodeNSError(Encoder& encoder, NSError *nsError) { String domain = [nsError domain]; encoder << domain; int64_t code = [nsError code]; encoder << code; NSDictionary *userInfo = [nsError userInfo]; RetainPtr filteredUserInfo = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, userInfo.count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); [userInfo enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL*) { if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSURL class]] || [value isKindOfClass:[NSNumber class]]) CFDictionarySetValue(filteredUserInfo.get(), (__bridge CFTypeRef)key, (__bridge CFTypeRef)value); }]; if (NSArray *clientIdentityAndCertificates = [userInfo objectForKey:@"NSErrorClientCertificateChainKey"]) { ASSERT([clientIdentityAndCertificates isKindOfClass:[NSArray class]]); ASSERT(^{ for (id object in clientIdentityAndCertificates) { if (CFGetTypeID((__bridge CFTypeRef)object) != SecIdentityGetTypeID() && CFGetTypeID((__bridge CFTypeRef)object) != SecCertificateGetTypeID()) return false; } return true; }()); // Turn SecIdentity members into SecCertificate to strip out private key information. id clientCertificates = [NSMutableArray arrayWithCapacity:clientIdentityAndCertificates.count]; for (id object in clientIdentityAndCertificates) { if (CFGetTypeID((__bridge CFTypeRef)object) != SecIdentityGetTypeID()) { [clientCertificates addObject:object]; continue; } SecCertificateRef certificate = nil; OSStatus status = SecIdentityCopyCertificate((SecIdentityRef)object, &certificate); RetainPtr retainCertificate = adoptCF(certificate); // The SecIdentity member is the key information of this attribute. Without it, we should nil // the attribute. if (status != errSecSuccess) { LOG_ERROR("Failed to encode nsError.userInfo[NSErrorClientCertificateChainKey]: %d", status); clientCertificates = nil; break; } [clientCertificates addObject:(__bridge id)certificate]; } CFDictionarySetValue(filteredUserInfo.get(), CFSTR("NSErrorClientCertificateChainKey"), (__bridge CFTypeRef)clientCertificates); } id peerCertificateChain = [userInfo objectForKey:@"NSErrorPeerCertificateChainKey"]; if (!peerCertificateChain) { if (SecTrustRef peerTrust = (__bridge SecTrustRef)[userInfo objectForKey:NSURLErrorFailingURLPeerTrustErrorKey]) { #if HAVE(SEC_TRUST_COPY_CERTIFICATE_CHAIN) peerCertificateChain = (__bridge NSArray *)adoptCF(SecTrustCopyCertificateChain(peerTrust)).autorelease(); #else CFIndex count = SecTrustGetCertificateCount(peerTrust); peerCertificateChain = [NSMutableArray arrayWithCapacity:count]; for (CFIndex i = 0; i < count; ++i) [peerCertificateChain addObject:(__bridge id)SecTrustGetCertificateAtIndex(peerTrust, i)]; #endif } } ASSERT(!peerCertificateChain || [peerCertificateChain isKindOfClass:[NSArray class]]); if (peerCertificateChain) CFDictionarySetValue(filteredUserInfo.get(), CFSTR("NSErrorPeerCertificateChainKey"), (__bridge CFTypeRef)peerCertificateChain); #if HAVE(SEC_TRUST_SERIALIZATION) if (SecTrustRef peerTrust = (__bridge SecTrustRef)[userInfo objectForKey:NSURLErrorFailingURLPeerTrustErrorKey]) CFDictionarySetValue(filteredUserInfo.get(), (__bridge CFStringRef)NSURLErrorFailingURLPeerTrustErrorKey, peerTrust); #endif encoder << static_cast(filteredUserInfo.get()); if (id underlyingError = [userInfo objectForKey:NSUnderlyingErrorKey]) { ASSERT([underlyingError isKindOfClass:[NSError class]]); encoder << true; encodeNSError(encoder, underlyingError); } else encoder << false; } void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::ResourceError& resourceError) { encodeNSError(encoder, resourceError.nsError()); } static RetainPtr decodeNSError(Decoder& decoder) { String domain; if (!decoder.decode(domain)) return nil; int64_t code; if (!decoder.decode(code)) return nil; RetainPtr userInfo; if (!decoder.decode(userInfo) || !userInfo) return nil; bool hasUnderlyingError = false; if (!decoder.decode(hasUnderlyingError)) return nil; if (hasUnderlyingError) { auto underlyingNSError = decodeNSError(decoder); if (!underlyingNSError) return nil; auto mutableUserInfo = adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(userInfo.get()) + 1, userInfo.get())); CFDictionarySetValue(mutableUserInfo.get(), (__bridge CFStringRef)NSUnderlyingErrorKey, (__bridge CFTypeRef)underlyingNSError.get()); userInfo = WTFMove(mutableUserInfo); } return adoptNS([[NSError alloc] initWithDomain:domain code:code userInfo:(__bridge NSDictionary *)userInfo.get()]); } bool ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::ResourceError& resourceError) { auto nsError = decodeNSError(decoder); if (!nsError) return false; resourceError = WebCore::ResourceError(nsError.get()); return true; } void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::ProtectionSpace& space) { encoder << space.nsSpace(); } bool ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::ProtectionSpace& space) { auto platformData = IPC::decode(decoder); if (!platformData) return false; space = WebCore::ProtectionSpace { platformData->get() }; return true; } void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::Credential& credential) { NSURLCredential *nsCredential = credential.nsCredential(); encoder << nsCredential; } bool ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::Credential& credential) { auto nsCredential = IPC::decode(decoder); if (!nsCredential) return false; credential = WebCore::Credential { nsCredential->get() }; return true; } void ArgumentCoder::encode(Encoder& encoder, const MachSendRight& sendRight) { encoder << Attachment { sendRight }; } void ArgumentCoder::encode(Encoder& encoder, MachSendRight&& sendRight) { encoder << Attachment { WTFMove(sendRight) }; } bool ArgumentCoder::decode(Decoder& decoder, MachSendRight& sendRight) { Attachment attachment; if (!decoder.decode(attachment)) return false; sendRight = WTFMove(attachment); return true; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::KeypressCommand& keypressCommand) { encoder << keypressCommand.commandName << keypressCommand.text; } std::optional ArgumentCoder::decode(Decoder& decoder) { std::optional commandName; decoder >> commandName; if (!commandName) return std::nullopt; std::optional text; decoder >> text; if (!text) return std::nullopt; WebCore::KeypressCommand command; command.commandName = WTFMove(*commandName); command.text = WTFMove(*text); return WTFMove(command); } #if ENABLE(CONTENT_FILTERING) void ArgumentCoder::encode(Encoder& encoder, const WebCore::ContentFilterUnblockHandler& contentFilterUnblockHandler) { auto archiver = adoptNS([[NSKeyedArchiver alloc] initRequiringSecureCoding:YES]); contentFilterUnblockHandler.encode(archiver.get()); encoder << (__bridge CFDataRef)archiver.get().encodedData; } bool ArgumentCoder::decode(Decoder& decoder, WebCore::ContentFilterUnblockHandler& contentFilterUnblockHandler) { RetainPtr data; if (!decoder.decode(data) || !data) return false; auto unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingFromData:(__bridge NSData *)data.get() error:nullptr]); unarchiver.get().decodingFailurePolicy = NSDecodingFailurePolicyRaiseException; if (!WebCore::ContentFilterUnblockHandler::decode(unarchiver.get(), contentFilterUnblockHandler)) return false; [unarchiver finishDecoding]; return true; } #endif #if ENABLE(VIDEO) void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::SerializedPlatformDataCueValue& value) { ASSERT(value.platformType() == WebCore::SerializedPlatformDataCueValue::PlatformType::ObjC); if (value.platformType() == WebCore::SerializedPlatformDataCueValue::PlatformType::ObjC) encodeObject(encoder, value.nativeValue().get()); } std::optional ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::SerializedPlatformDataCueValue::PlatformType platformType) { ASSERT(platformType == WebCore::SerializedPlatformDataCueValue::PlatformType::ObjC); if (platformType != WebCore::SerializedPlatformDataCueValue::PlatformType::ObjC) return std::nullopt; auto object = decodeObject(decoder, WebCore::SerializedPlatformDataCueMac::allowedClassesForNativeValues()); if (!object) return std::nullopt; return WebCore::SerializedPlatformDataCueValue { platformType, object.value().get() }; } #endif } // namespace IPC