| /* |
| * Copyright (C) 2010-2018 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| // FIXME: This is a .cpp but has ObjC in it? |
| |
| #include "config.h" |
| #include "ArgumentCodersCF.h" |
| |
| #include "DataReference.h" |
| #include "Decoder.h" |
| #include "Encoder.h" |
| #include <wtf/HashSet.h> |
| #include <wtf/ProcessPrivilege.h> |
| #include <wtf/Vector.h> |
| #include <wtf/cf/CFURLExtras.h> |
| #include <wtf/spi/cocoa/SecuritySPI.h> |
| |
| #if USE(FOUNDATION) |
| #import <Foundation/Foundation.h> |
| #endif |
| |
| namespace IPC { |
| using namespace WebCore; |
| |
| CFTypeRef tokenNullTypeRef() |
| { |
| static CFStringRef tokenNullType = CFSTR("WKNull"); |
| return tokenNullType; |
| } |
| |
| enum CFType { |
| CFArray, |
| CFBoolean, |
| CFData, |
| CFDate, |
| CFDictionary, |
| CFNull, |
| CFNumber, |
| CFString, |
| CFURL, |
| SecCertificate, |
| SecIdentity, |
| #if HAVE(SEC_KEYCHAIN) |
| SecKeychainItem, |
| #endif |
| #if HAVE(SEC_ACCESS_CONTROL) |
| SecAccessControl, |
| #endif |
| #if HAVE(SEC_TRUST_SERIALIZATION) |
| SecTrust, |
| #endif |
| Null, |
| Unknown, |
| }; |
| |
| static CFType typeFromCFTypeRef(CFTypeRef type) |
| { |
| ASSERT(type); |
| |
| if (type == tokenNullTypeRef()) |
| return Null; |
| |
| CFTypeID typeID = CFGetTypeID(type); |
| if (typeID == CFArrayGetTypeID()) |
| return CFArray; |
| if (typeID == CFBooleanGetTypeID()) |
| return CFBoolean; |
| if (typeID == CFDataGetTypeID()) |
| return CFData; |
| if (typeID == CFDateGetTypeID()) |
| return CFDate; |
| if (typeID == CFDictionaryGetTypeID()) |
| return CFDictionary; |
| if (typeID == CFNullGetTypeID()) |
| return CFNull; |
| if (typeID == CFNumberGetTypeID()) |
| return CFNumber; |
| if (typeID == CFStringGetTypeID()) |
| return CFString; |
| if (typeID == CFURLGetTypeID()) |
| return CFURL; |
| if (typeID == SecCertificateGetTypeID()) |
| return SecCertificate; |
| if (typeID == SecIdentityGetTypeID()) |
| return SecIdentity; |
| #if HAVE(SEC_KEYCHAIN) |
| if (typeID == SecKeychainItemGetTypeID()) |
| return SecKeychainItem; |
| #endif |
| #if HAVE(SEC_ACCESS_CONTROL) |
| if (typeID == SecAccessControlGetTypeID()) |
| return SecAccessControl; |
| #endif |
| #if HAVE(SEC_TRUST_SERIALIZATION) |
| if (typeID == SecTrustGetTypeID()) |
| return SecTrust; |
| #endif |
| |
| ASSERT_NOT_REACHED(); |
| return Unknown; |
| } |
| |
| void encode(Encoder& encoder, CFTypeRef typeRef) |
| { |
| CFType type = typeFromCFTypeRef(typeRef); |
| encoder.encodeEnum(type); |
| |
| switch (type) { |
| case CFArray: |
| encode(encoder, static_cast<CFArrayRef>(typeRef)); |
| return; |
| case CFBoolean: |
| encode(encoder, static_cast<CFBooleanRef>(typeRef)); |
| return; |
| case CFData: |
| encode(encoder, static_cast<CFDataRef>(typeRef)); |
| return; |
| case CFDate: |
| encode(encoder, static_cast<CFDateRef>(typeRef)); |
| return; |
| case CFDictionary: |
| encode(encoder, static_cast<CFDictionaryRef>(typeRef)); |
| return; |
| case CFNull: |
| return; |
| case CFNumber: |
| encode(encoder, static_cast<CFNumberRef>(typeRef)); |
| return; |
| case CFString: |
| encode(encoder, static_cast<CFStringRef>(typeRef)); |
| return; |
| case CFURL: |
| encode(encoder, static_cast<CFURLRef>(typeRef)); |
| return; |
| case SecCertificate: |
| encode(encoder, static_cast<SecCertificateRef>(const_cast<void*>(typeRef))); |
| return; |
| case SecIdentity: |
| encode(encoder, static_cast<SecIdentityRef>(const_cast<void*>(typeRef))); |
| return; |
| #if HAVE(SEC_KEYCHAIN) |
| case SecKeychainItem: |
| encode(encoder, static_cast<SecKeychainItemRef>(const_cast<void*>(typeRef))); |
| return; |
| #endif |
| #if HAVE(SEC_ACCESS_CONTROL) |
| case SecAccessControl: |
| encode(encoder, static_cast<SecAccessControlRef>(const_cast<void*>(typeRef))); |
| return; |
| #endif |
| #if HAVE(SEC_TRUST_SERIALIZATION) |
| case SecTrust: |
| encode(encoder, static_cast<SecTrustRef>(const_cast<void*>(typeRef))); |
| return; |
| #endif |
| case Null: |
| return; |
| case Unknown: |
| break; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFTypeRef>& result) |
| { |
| CFType type; |
| if (!decoder.decodeEnum(type)) |
| return false; |
| |
| switch (type) { |
| case CFArray: { |
| RetainPtr<CFArrayRef> array; |
| if (!decode(decoder, array)) |
| return false; |
| result = adoptCF(array.leakRef()); |
| return true; |
| } |
| case CFBoolean: { |
| RetainPtr<CFBooleanRef> boolean; |
| if (!decode(decoder, boolean)) |
| return false; |
| result = adoptCF(boolean.leakRef()); |
| return true; |
| } |
| case CFData: { |
| RetainPtr<CFDataRef> data; |
| if (!decode(decoder, data)) |
| return false; |
| result = adoptCF(data.leakRef()); |
| return true; |
| } |
| case CFDate: { |
| RetainPtr<CFDateRef> date; |
| if (!decode(decoder, date)) |
| return false; |
| result = adoptCF(date.leakRef()); |
| return true; |
| } |
| case CFDictionary: { |
| RetainPtr<CFDictionaryRef> dictionary; |
| if (!decode(decoder, dictionary)) |
| return false; |
| result = adoptCF(dictionary.leakRef()); |
| return true; |
| } |
| case CFNull: |
| result = adoptCF(kCFNull); |
| return true; |
| case CFNumber: { |
| RetainPtr<CFNumberRef> number; |
| if (!decode(decoder, number)) |
| return false; |
| result = adoptCF(number.leakRef()); |
| return true; |
| } |
| case CFString: { |
| RetainPtr<CFStringRef> string; |
| if (!decode(decoder, string)) |
| return false; |
| result = adoptCF(string.leakRef()); |
| return true; |
| } |
| case CFURL: { |
| RetainPtr<CFURLRef> url; |
| if (!decode(decoder, url)) |
| return false; |
| result = adoptCF(url.leakRef()); |
| return true; |
| } |
| case SecCertificate: { |
| RetainPtr<SecCertificateRef> certificate; |
| if (!decode(decoder, certificate)) |
| return false; |
| result = adoptCF(certificate.leakRef()); |
| return true; |
| } |
| case SecIdentity: { |
| RetainPtr<SecIdentityRef> identity; |
| if (!decode(decoder, identity)) |
| return false; |
| result = adoptCF(identity.leakRef()); |
| return true; |
| } |
| #if HAVE(SEC_KEYCHAIN) |
| case SecKeychainItem: { |
| RetainPtr<SecKeychainItemRef> keychainItem; |
| if (!decode(decoder, keychainItem)) |
| return false; |
| result = adoptCF(keychainItem.leakRef()); |
| return true; |
| } |
| #endif |
| #if HAVE(SEC_ACCESS_CONTROL) |
| case SecAccessControl: { |
| RetainPtr<SecAccessControlRef> accessControl; |
| if (!decode(decoder, accessControl)) |
| return false; |
| result = adoptCF(accessControl.leakRef()); |
| return true; |
| } |
| #endif |
| #if HAVE(SEC_TRUST_SERIALIZATION) |
| case SecTrust: { |
| RetainPtr<SecTrustRef> trust; |
| if (!decode(decoder, trust)) |
| return false; |
| result = adoptCF(trust.leakRef()); |
| return true; |
| } |
| #endif |
| case Null: |
| result = tokenNullTypeRef(); |
| return true; |
| case Unknown: |
| ASSERT_NOT_REACHED(); |
| return false; |
| } |
| |
| return false; |
| } |
| |
| void encode(Encoder& encoder, CFArrayRef array) |
| { |
| if (!array) { |
| encoder << true; |
| return; |
| } |
| |
| encoder << false; |
| |
| CFIndex size = CFArrayGetCount(array); |
| Vector<CFTypeRef, 32> values(size); |
| |
| CFArrayGetValues(array, CFRangeMake(0, size), values.data()); |
| |
| HashSet<CFIndex> invalidIndicies; |
| for (CFIndex i = 0; i < size; ++i) { |
| // Ignore values we don't support. |
| ASSERT(typeFromCFTypeRef(values[i]) != Unknown); |
| if (typeFromCFTypeRef(values[i]) == Unknown) |
| invalidIndicies.add(i); |
| } |
| |
| encoder << static_cast<uint64_t>(size - invalidIndicies.size()); |
| |
| for (CFIndex i = 0; i < size; ++i) { |
| if (invalidIndicies.contains(i)) |
| continue; |
| encode(encoder, values[i]); |
| } |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFArrayRef>& result) |
| { |
| bool isNull = false; |
| if (!decoder.decode(isNull)) |
| return false; |
| |
| if (isNull) { |
| result = nullptr; |
| return true; |
| } |
| |
| uint64_t size; |
| if (!decoder.decode(size)) |
| return false; |
| |
| RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); |
| |
| for (size_t i = 0; i < size; ++i) { |
| RetainPtr<CFTypeRef> element; |
| if (!decode(decoder, element)) |
| return false; |
| |
| CFArrayAppendValue(array.get(), element.get()); |
| } |
| |
| result = adoptCF(array.leakRef()); |
| return true; |
| } |
| |
| void encode(Encoder& encoder, CFBooleanRef boolean) |
| { |
| encoder << static_cast<bool>(CFBooleanGetValue(boolean)); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFBooleanRef>& result) |
| { |
| bool boolean; |
| if (!decoder.decode(boolean)) |
| return false; |
| |
| result = adoptCF(boolean ? kCFBooleanTrue : kCFBooleanFalse); |
| return true; |
| } |
| |
| void encode(Encoder& encoder, CFDataRef data) |
| { |
| CFIndex length = CFDataGetLength(data); |
| const UInt8* bytePtr = CFDataGetBytePtr(data); |
| |
| encoder << IPC::DataReference(bytePtr, length); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFDataRef>& result) |
| { |
| IPC::DataReference dataReference; |
| if (!decoder.decode(dataReference)) |
| return false; |
| |
| result = adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size())); |
| return true; |
| } |
| |
| void encode(Encoder& encoder, CFDateRef date) |
| { |
| encoder << static_cast<double>(CFDateGetAbsoluteTime(date)); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFDateRef>& result) |
| { |
| double absoluteTime; |
| if (!decoder.decode(absoluteTime)) |
| return false; |
| |
| result = adoptCF(CFDateCreate(0, absoluteTime)); |
| return true; |
| } |
| |
| void encode(Encoder& encoder, CFDictionaryRef dictionary) |
| { |
| if (!dictionary) { |
| encoder << true; |
| return; |
| } |
| |
| encoder << false; |
| |
| CFIndex size = CFDictionaryGetCount(dictionary); |
| Vector<CFTypeRef, 32> keys(size); |
| Vector<CFTypeRef, 32> values(size); |
| |
| CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data()); |
| |
| HashSet<CFTypeRef> invalidKeys; |
| for (CFIndex i = 0; i < size; ++i) { |
| ASSERT(keys[i]); |
| ASSERT(values[i]); |
| |
| // Ignore keys/values we don't support. |
| ASSERT(typeFromCFTypeRef(keys[i]) != Unknown); |
| ASSERT(typeFromCFTypeRef(values[i]) != Unknown); |
| if (typeFromCFTypeRef(keys[i]) == Unknown || typeFromCFTypeRef(values[i]) == Unknown) |
| invalidKeys.add(keys[i]); |
| } |
| |
| encoder << static_cast<uint64_t>(size - invalidKeys.size()); |
| |
| for (CFIndex i = 0; i < size; ++i) { |
| if (invalidKeys.contains(keys[i])) |
| continue; |
| |
| encode(encoder, keys[i]); |
| encode(encoder, values[i]); |
| } |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFDictionaryRef>& result) |
| { |
| bool isNull = false; |
| if (!decoder.decode(isNull)) |
| return false; |
| |
| if (isNull) { |
| result = nullptr; |
| return true; |
| } |
| |
| uint64_t size; |
| if (!decoder.decode(size)) |
| return false; |
| |
| RetainPtr<CFMutableDictionaryRef> dictionary = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); |
| for (uint64_t i = 0; i < size; ++i) { |
| RetainPtr<CFTypeRef> key; |
| if (!decode(decoder, key)) |
| return false; |
| |
| RetainPtr<CFTypeRef> value; |
| if (!decode(decoder, value)) |
| return false; |
| |
| CFDictionarySetValue(dictionary.get(), key.get(), value.get()); |
| } |
| |
| result = adoptCF(dictionary.leakRef()); |
| return true; |
| } |
| |
| void encode(Encoder& encoder, CFNumberRef number) |
| { |
| CFNumberType numberType = CFNumberGetType(number); |
| |
| Vector<uint8_t> buffer(CFNumberGetByteSize(number)); |
| bool result = CFNumberGetValue(number, numberType, buffer.data()); |
| ASSERT_UNUSED(result, result); |
| |
| encoder.encodeEnum(numberType); |
| encoder << IPC::DataReference(buffer); |
| } |
| |
| static size_t sizeForNumberType(CFNumberType numberType) |
| { |
| switch (numberType) { |
| case kCFNumberSInt8Type: |
| return sizeof(SInt8); |
| case kCFNumberSInt16Type: |
| return sizeof(SInt16); |
| case kCFNumberSInt32Type: |
| return sizeof(SInt32); |
| case kCFNumberSInt64Type: |
| return sizeof(SInt64); |
| case kCFNumberFloat32Type: |
| return sizeof(Float32); |
| case kCFNumberFloat64Type: |
| return sizeof(Float64); |
| case kCFNumberCharType: |
| return sizeof(char); |
| case kCFNumberShortType: |
| return sizeof(short); |
| case kCFNumberIntType: |
| return sizeof(int); |
| case kCFNumberLongType: |
| return sizeof(long); |
| case kCFNumberLongLongType: |
| return sizeof(long long); |
| case kCFNumberFloatType: |
| return sizeof(float); |
| case kCFNumberDoubleType: |
| return sizeof(double); |
| case kCFNumberCFIndexType: |
| return sizeof(CFIndex); |
| case kCFNumberNSIntegerType: |
| return sizeof(long); |
| case kCFNumberCGFloatType: |
| return sizeof(double); |
| } |
| |
| return 0; |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFNumberRef>& result) |
| { |
| CFNumberType numberType; |
| if (!decoder.decodeEnum(numberType)) |
| return false; |
| |
| IPC::DataReference dataReference; |
| if (!decoder.decode(dataReference)) |
| return false; |
| |
| size_t neededBufferSize = sizeForNumberType(numberType); |
| if (!neededBufferSize || dataReference.size() != neededBufferSize) |
| return false; |
| |
| ASSERT(dataReference.data()); |
| CFNumberRef number = CFNumberCreate(0, numberType, dataReference.data()); |
| result = adoptCF(number); |
| |
| return true; |
| } |
| |
| void encode(Encoder& encoder, CFStringRef string) |
| { |
| CFIndex length = CFStringGetLength(string); |
| CFStringEncoding encoding = CFStringGetFastestEncoding(string); |
| |
| CFRange range = CFRangeMake(0, length); |
| CFIndex bufferLength = 0; |
| |
| CFIndex numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, 0, 0, &bufferLength); |
| ASSERT(numConvertedBytes == length); |
| |
| Vector<UInt8, 128> buffer(bufferLength); |
| numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, buffer.data(), buffer.size(), &bufferLength); |
| ASSERT(numConvertedBytes == length); |
| |
| encoder.encodeEnum(encoding); |
| encoder << IPC::DataReference(buffer); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFStringRef>& result) |
| { |
| CFStringEncoding encoding; |
| if (!decoder.decodeEnum(encoding)) |
| return false; |
| |
| if (!CFStringIsEncodingAvailable(encoding)) |
| return false; |
| |
| IPC::DataReference dataReference; |
| if (!decoder.decode(dataReference)) |
| return false; |
| |
| CFStringRef string = CFStringCreateWithBytes(0, dataReference.data(), dataReference.size(), encoding, false); |
| if (!string) |
| return false; |
| |
| result = adoptCF(string); |
| return true; |
| } |
| |
| void encode(Encoder& encoder, CFURLRef url) |
| { |
| CFURLRef baseURL = CFURLGetBaseURL(url); |
| encoder << static_cast<bool>(baseURL); |
| if (baseURL) |
| encode(encoder, baseURL); |
| |
| WTF::URLCharBuffer urlBytes; |
| WTF::getURLBytes(url, urlBytes); |
| IPC::DataReference dataReference(reinterpret_cast<const uint8_t*>(urlBytes.data()), urlBytes.size()); |
| encoder << dataReference; |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<CFURLRef>& result) |
| { |
| RetainPtr<CFURLRef> baseURL; |
| bool hasBaseURL; |
| if (!decoder.decode(hasBaseURL)) |
| return false; |
| if (hasBaseURL) { |
| if (!decode(decoder, baseURL)) |
| return false; |
| } |
| |
| IPC::DataReference urlBytes; |
| if (!decoder.decode(urlBytes)) |
| return false; |
| |
| #if USE(FOUNDATION) |
| // FIXME: Move this to ArgumentCodersCFMac.mm and change this file back to be C++ |
| // instead of Objective-C++. |
| if (urlBytes.isEmpty()) { |
| // CFURL can't hold an empty URL, unlike NSURL. |
| // FIXME: This discards base URL, which seems incorrect. |
| result = (__bridge CFURLRef)[NSURL URLWithString:@""]; |
| return true; |
| } |
| #endif |
| |
| result = WTF::createCFURLFromBuffer(reinterpret_cast<const char*>(urlBytes.data()), urlBytes.size(), baseURL.get()); |
| return result; |
| } |
| |
| void encode(Encoder& encoder, SecCertificateRef certificate) |
| { |
| RetainPtr<CFDataRef> data = adoptCF(SecCertificateCopyData(certificate)); |
| encode(encoder, data.get()); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<SecCertificateRef>& result) |
| { |
| RetainPtr<CFDataRef> data; |
| if (!decode(decoder, data)) |
| return false; |
| |
| result = adoptCF(SecCertificateCreateWithData(0, data.get())); |
| return true; |
| } |
| |
| #if PLATFORM(IOS_FAMILY) |
| static bool secKeyRefDecodingAllowed; |
| |
| void setAllowsDecodingSecKeyRef(bool allowsDecodingSecKeyRef) |
| { |
| secKeyRefDecodingAllowed = allowsDecodingSecKeyRef; |
| } |
| |
| static CFDataRef copyPersistentRef(SecKeyRef key) |
| { |
| RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials)); |
| // This function differs from SecItemCopyPersistentRef in that it specifies an access group. |
| // This is necessary in case there are multiple copies of the key in the keychain, because we |
| // need a reference to the one that the Networking process will be able to access. |
| CFDataRef persistentRef = nullptr; |
| SecItemCopyMatching((CFDictionaryRef)@{ |
| (id)kSecReturnPersistentRef: @YES, |
| (id)kSecValueRef: (id)key, |
| (id)kSecAttrSynchronizable: (id)kSecAttrSynchronizableAny, |
| (id)kSecAttrAccessGroup: @"com.apple.identities", |
| }, (CFTypeRef*)&persistentRef); |
| |
| return persistentRef; |
| } |
| #endif |
| |
| void encode(Encoder& encoder, SecIdentityRef identity) |
| { |
| SecCertificateRef certificate = nullptr; |
| SecIdentityCopyCertificate(identity, &certificate); |
| encode(encoder, certificate); |
| CFRelease(certificate); |
| |
| SecKeyRef key = nullptr; |
| SecIdentityCopyPrivateKey(identity, &key); |
| |
| CFDataRef keyData = nullptr; |
| #if PLATFORM(IOS_FAMILY) |
| keyData = copyPersistentRef(key); |
| #endif |
| #if PLATFORM(MAC) |
| RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials)); |
| SecKeychainItemCreatePersistentReference((SecKeychainItemRef)key, &keyData); |
| #endif |
| CFRelease(key); |
| |
| encoder << !!keyData; |
| if (keyData) { |
| encode(encoder, keyData); |
| CFRelease(keyData); |
| } |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<SecIdentityRef>& result) |
| { |
| RetainPtr<SecCertificateRef> certificate; |
| if (!decode(decoder, certificate)) |
| return false; |
| |
| bool hasKey; |
| if (!decoder.decode(hasKey)) |
| return false; |
| |
| if (!hasKey) |
| return true; |
| |
| RetainPtr<CFDataRef> keyData; |
| if (!decode(decoder, keyData)) |
| return false; |
| |
| #if PLATFORM(COCOA) |
| if (!hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials)) |
| return true; |
| #endif |
| |
| SecKeyRef key = nullptr; |
| #if PLATFORM(IOS_FAMILY) |
| if (secKeyRefDecodingAllowed) |
| SecKeyFindWithPersistentRef(keyData.get(), &key); |
| #endif |
| #if PLATFORM(MAC) |
| SecKeychainItemCopyFromPersistentReference(keyData.get(), (SecKeychainItemRef*)&key); |
| #endif |
| if (key) { |
| result = adoptCF(SecIdentityCreate(kCFAllocatorDefault, certificate.get(), key)); |
| CFRelease(key); |
| } |
| |
| return true; |
| } |
| |
| #if HAVE(SEC_KEYCHAIN) |
| void encode(Encoder& encoder, SecKeychainItemRef keychainItem) |
| { |
| RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials)); |
| |
| CFDataRef data; |
| if (SecKeychainItemCreatePersistentReference(keychainItem, &data) == errSecSuccess) { |
| encode(encoder, data); |
| CFRelease(data); |
| } |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<SecKeychainItemRef>& result) |
| { |
| RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials)); |
| |
| RetainPtr<CFDataRef> data; |
| if (!IPC::decode(decoder, data)) |
| return false; |
| |
| SecKeychainItemRef item; |
| if (SecKeychainItemCopyFromPersistentReference(data.get(), &item) != errSecSuccess || !item) |
| return false; |
| |
| result = adoptCF(item); |
| return true; |
| } |
| #endif |
| |
| #if HAVE(SEC_ACCESS_CONTROL) |
| void encode(Encoder& encoder, SecAccessControlRef accessControl) |
| { |
| RetainPtr<CFDataRef> data = adoptCF(SecAccessControlCopyData(accessControl)); |
| if (data) |
| encode(encoder, data.get()); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<SecAccessControlRef>& result) |
| { |
| RetainPtr<CFDataRef> data; |
| if (!decode(decoder, data)) |
| return false; |
| |
| result = adoptCF(SecAccessControlCreateFromData(kCFAllocatorDefault, data.get(), nullptr)); |
| if (!result) |
| return false; |
| |
| return true; |
| } |
| #endif |
| |
| #if HAVE(SEC_TRUST_SERIALIZATION) |
| void encode(Encoder& encoder, SecTrustRef trust) |
| { |
| auto data = adoptCF(SecTrustSerialize(trust, nullptr)); |
| if (!data) { |
| encoder << false; |
| return; |
| } |
| |
| encoder << true; |
| IPC::encode(encoder, data.get()); |
| } |
| |
| bool decode(Decoder& decoder, RetainPtr<SecTrustRef>& result) |
| { |
| bool hasTrust; |
| if (!decoder.decode(hasTrust)) |
| return false; |
| |
| if (!hasTrust) |
| return true; |
| |
| RetainPtr<CFDataRef> trustData; |
| if (!IPC::decode(decoder, trustData)) |
| return false; |
| |
| auto trust = adoptCF(SecTrustDeserialize(trustData.get(), nullptr)); |
| if (!trust) |
| return false; |
| |
| result = WTFMove(trust); |
| return true; |
| } |
| #endif |
| |
| } // namespace IPC |