Unreviewed, rolling out r245418.
[WebKit-https.git] / Source / WebKit / Shared / cf / ArgumentCodersCF.cpp
1 /*
2  * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 // FIXME: This is a .cpp but has ObjC in it?
27
28 #include "config.h"
29 #include "ArgumentCodersCF.h"
30
31 #include "DataReference.h"
32 #include "Decoder.h"
33 #include "Encoder.h"
34 #include <wtf/HashSet.h>
35 #include <wtf/ProcessPrivilege.h>
36 #include <wtf/Vector.h>
37 #include <wtf/cf/CFURLExtras.h>
38 #include <wtf/spi/cocoa/SecuritySPI.h>
39
40 #if USE(FOUNDATION)
41 #import <Foundation/Foundation.h>
42 #endif
43
44 #if USE(APPLE_INTERNAL_SDK)
45 #include <Security/SecIdentityPriv.h>
46 #endif
47
48 extern "C" SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey);
49
50 #if PLATFORM(IOS_FAMILY)
51 #if USE(APPLE_INTERNAL_SDK)
52 #include <Security/SecKeyPriv.h>
53 #endif
54
55 extern "C" OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData);
56 #endif
57
58 #if HAVE(SEC_ACCESS_CONTROL)
59 #if USE(APPLE_INTERNAL_SDK)
60 #include <Security/SecAccessControlPriv.h>
61 #endif
62
63 extern "C" SecAccessControlRef SecAccessControlCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error);
64 extern "C" CFDataRef SecAccessControlCopyData(SecAccessControlRef access_control);
65 #endif
66
67 namespace IPC {
68 using namespace WebCore;
69
70 CFTypeRef tokenNullTypeRef()
71 {
72     static CFStringRef tokenNullType = CFSTR("WKNull");
73     return tokenNullType;
74 }
75
76 enum CFType {
77     CFArray,
78     CFBoolean,
79     CFData,
80     CFDate,
81     CFDictionary,
82     CFNull,
83     CFNumber,
84     CFString,
85     CFURL,
86     SecCertificate,
87     SecIdentity,
88 #if HAVE(SEC_KEYCHAIN)
89     SecKeychainItem,
90 #endif
91 #if HAVE(SEC_ACCESS_CONTROL)
92     SecAccessControl,
93 #endif
94 #if HAVE(SEC_TRUST_SERIALIZATION)
95     SecTrust,
96 #endif
97     Null,
98     Unknown,
99 };
100
101 static CFType typeFromCFTypeRef(CFTypeRef type)
102 {
103     ASSERT(type);
104
105     if (type == tokenNullTypeRef())
106         return Null;
107
108     CFTypeID typeID = CFGetTypeID(type);
109     if (typeID == CFArrayGetTypeID())
110         return CFArray;
111     if (typeID == CFBooleanGetTypeID())
112         return CFBoolean;
113     if (typeID == CFDataGetTypeID())
114         return CFData;
115     if (typeID == CFDateGetTypeID())
116         return CFDate;
117     if (typeID == CFDictionaryGetTypeID())
118         return CFDictionary;
119     if (typeID == CFNullGetTypeID())
120         return CFNull;
121     if (typeID == CFNumberGetTypeID())
122         return CFNumber;
123     if (typeID == CFStringGetTypeID())
124         return CFString;
125     if (typeID == CFURLGetTypeID())
126         return CFURL;
127     if (typeID == SecCertificateGetTypeID())
128         return SecCertificate;
129     if (typeID == SecIdentityGetTypeID())
130         return SecIdentity;
131 #if HAVE(SEC_KEYCHAIN)
132     if (typeID == SecKeychainItemGetTypeID())
133         return SecKeychainItem;
134 #endif
135 #if HAVE(SEC_ACCESS_CONTROL)
136     if (typeID == SecAccessControlGetTypeID())
137         return SecAccessControl;
138 #endif
139 #if HAVE(SEC_TRUST_SERIALIZATION)
140     if (typeID == SecTrustGetTypeID())
141         return SecTrust;
142 #endif
143
144     ASSERT_NOT_REACHED();
145     return Unknown;
146 }
147
148 void encode(Encoder& encoder, CFTypeRef typeRef)
149 {
150     CFType type = typeFromCFTypeRef(typeRef);
151     encoder.encodeEnum(type);
152
153     switch (type) {
154     case CFArray:
155         encode(encoder, static_cast<CFArrayRef>(typeRef));
156         return;
157     case CFBoolean:
158         encode(encoder, static_cast<CFBooleanRef>(typeRef));
159         return;
160     case CFData:
161         encode(encoder, static_cast<CFDataRef>(typeRef));
162         return;
163     case CFDate:
164         encode(encoder, static_cast<CFDateRef>(typeRef));
165         return;
166     case CFDictionary:
167         encode(encoder, static_cast<CFDictionaryRef>(typeRef));
168         return;
169     case CFNull:
170         return;
171     case CFNumber:
172         encode(encoder, static_cast<CFNumberRef>(typeRef));
173         return;
174     case CFString:
175         encode(encoder, static_cast<CFStringRef>(typeRef));
176         return;
177     case CFURL:
178         encode(encoder, static_cast<CFURLRef>(typeRef));
179         return;
180     case SecCertificate:
181         encode(encoder, static_cast<SecCertificateRef>(const_cast<void*>(typeRef)));
182         return;
183     case SecIdentity:
184         encode(encoder, static_cast<SecIdentityRef>(const_cast<void*>(typeRef)));
185         return;
186 #if HAVE(SEC_KEYCHAIN)
187     case SecKeychainItem:
188         encode(encoder, static_cast<SecKeychainItemRef>(const_cast<void*>(typeRef)));
189         return;
190 #endif
191 #if HAVE(SEC_ACCESS_CONTROL)
192     case SecAccessControl:
193         encode(encoder, static_cast<SecAccessControlRef>(const_cast<void*>(typeRef)));
194         return;
195 #endif
196 #if HAVE(SEC_TRUST_SERIALIZATION)
197     case SecTrust:
198         encode(encoder, static_cast<SecTrustRef>(const_cast<void*>(typeRef)));
199         return;
200 #endif
201     case Null:
202         return;
203     case Unknown:
204         break;
205     }
206
207     ASSERT_NOT_REACHED();
208 }
209
210 bool decode(Decoder& decoder, RetainPtr<CFTypeRef>& result)
211 {
212     CFType type;
213     if (!decoder.decodeEnum(type))
214         return false;
215
216     switch (type) {
217     case CFArray: {
218         RetainPtr<CFArrayRef> array;
219         if (!decode(decoder, array))
220             return false;
221         result = adoptCF(array.leakRef());
222         return true;
223     }
224     case CFBoolean: {
225         RetainPtr<CFBooleanRef> boolean;
226         if (!decode(decoder, boolean))
227             return false;
228         result = adoptCF(boolean.leakRef());
229         return true;
230     }
231     case CFData: {
232         RetainPtr<CFDataRef> data;
233         if (!decode(decoder, data))
234             return false;
235         result = adoptCF(data.leakRef());
236         return true;
237     }
238     case CFDate: {
239         RetainPtr<CFDateRef> date;
240         if (!decode(decoder, date))
241             return false;
242         result = adoptCF(date.leakRef());
243         return true;
244     }
245     case CFDictionary: {
246         RetainPtr<CFDictionaryRef> dictionary;
247         if (!decode(decoder, dictionary))
248             return false;
249         result = adoptCF(dictionary.leakRef());
250         return true;
251     }
252     case CFNull:
253         result = adoptCF(kCFNull);
254         return true;
255     case CFNumber: {
256         RetainPtr<CFNumberRef> number;
257         if (!decode(decoder, number))
258             return false;
259         result = adoptCF(number.leakRef());
260         return true;
261     }
262     case CFString: {
263         RetainPtr<CFStringRef> string;
264         if (!decode(decoder, string))
265             return false;
266         result = adoptCF(string.leakRef());
267         return true;
268     }
269     case CFURL: {
270         RetainPtr<CFURLRef> url;
271         if (!decode(decoder, url))
272             return false;
273         result = adoptCF(url.leakRef());
274         return true;
275     }
276     case SecCertificate: {
277         RetainPtr<SecCertificateRef> certificate;
278         if (!decode(decoder, certificate))
279             return false;
280         result = adoptCF(certificate.leakRef());
281         return true;
282     }
283     case SecIdentity: {
284         RetainPtr<SecIdentityRef> identity;
285         if (!decode(decoder, identity))
286             return false;
287         result = adoptCF(identity.leakRef());
288         return true;
289     }
290 #if HAVE(SEC_KEYCHAIN)
291     case SecKeychainItem: {
292         RetainPtr<SecKeychainItemRef> keychainItem;
293         if (!decode(decoder, keychainItem))
294             return false;
295         result = adoptCF(keychainItem.leakRef());
296         return true;
297     }
298 #endif
299 #if HAVE(SEC_ACCESS_CONTROL)
300     case SecAccessControl: {
301         RetainPtr<SecAccessControlRef> accessControl;
302         if (!decode(decoder, accessControl))
303             return false;
304         result = adoptCF(accessControl.leakRef());
305         return true;
306     }
307 #endif
308 #if HAVE(SEC_TRUST_SERIALIZATION)
309     case SecTrust: {
310         RetainPtr<SecTrustRef> trust;
311         if (!decode(decoder, trust))
312             return false;
313         result = adoptCF(trust.leakRef());
314         return true;
315     }
316 #endif
317     case Null:
318         result = tokenNullTypeRef();
319         return true;
320     case Unknown:
321         ASSERT_NOT_REACHED();
322         return false;
323     }
324
325     return false;
326 }
327
328 void encode(Encoder& encoder, CFArrayRef array)
329 {
330     if (!array) {
331         encoder << true;
332         return;
333     }
334
335     encoder << false;
336
337     CFIndex size = CFArrayGetCount(array);
338     Vector<CFTypeRef, 32> values(size);
339
340     CFArrayGetValues(array, CFRangeMake(0, size), values.data());
341
342     HashSet<CFIndex> invalidIndicies;
343     for (CFIndex i = 0; i < size; ++i) {
344         // Ignore values we don't support.
345         ASSERT(typeFromCFTypeRef(values[i]) != Unknown);
346         if (typeFromCFTypeRef(values[i]) == Unknown)
347             invalidIndicies.add(i);
348     }
349
350     encoder << static_cast<uint64_t>(size - invalidIndicies.size());
351
352     for (CFIndex i = 0; i < size; ++i) {
353         if (invalidIndicies.contains(i))
354             continue;
355         encode(encoder, values[i]);
356     }
357 }
358
359 bool decode(Decoder& decoder, RetainPtr<CFArrayRef>& result)
360 {
361     bool isNull = false;
362     if (!decoder.decode(isNull))
363         return false;
364
365     if (isNull) {
366         result = nullptr;
367         return true;
368     }
369
370     uint64_t size;
371     if (!decoder.decode(size))
372         return false;
373
374     RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
375
376     for (size_t i = 0; i < size; ++i) {
377         RetainPtr<CFTypeRef> element;
378         if (!decode(decoder, element))
379             return false;
380
381         CFArrayAppendValue(array.get(), element.get());
382     }
383
384     result = adoptCF(array.leakRef());
385     return true;
386 }
387
388 void encode(Encoder& encoder, CFBooleanRef boolean)
389 {
390     encoder << static_cast<bool>(CFBooleanGetValue(boolean));
391 }
392
393 bool decode(Decoder& decoder, RetainPtr<CFBooleanRef>& result)
394 {
395     bool boolean;
396     if (!decoder.decode(boolean))
397         return false;
398
399     result = adoptCF(boolean ? kCFBooleanTrue : kCFBooleanFalse);
400     return true;
401 }
402
403 void encode(Encoder& encoder, CFDataRef data)
404 {
405     CFIndex length = CFDataGetLength(data);
406     const UInt8* bytePtr = CFDataGetBytePtr(data);
407
408     encoder << IPC::DataReference(bytePtr, length);
409 }
410
411 bool decode(Decoder& decoder, RetainPtr<CFDataRef>& result)
412 {
413     IPC::DataReference dataReference;
414     if (!decoder.decode(dataReference))
415         return false;
416
417     result = adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size()));
418     return true;
419 }
420
421 void encode(Encoder& encoder, CFDateRef date)
422 {
423     encoder << static_cast<double>(CFDateGetAbsoluteTime(date));
424 }
425
426 bool decode(Decoder& decoder, RetainPtr<CFDateRef>& result)
427 {
428     double absoluteTime;
429     if (!decoder.decode(absoluteTime))
430         return false;
431
432     result = adoptCF(CFDateCreate(0, absoluteTime));
433     return true;
434 }
435
436 void encode(Encoder& encoder, CFDictionaryRef dictionary)
437 {
438     if (!dictionary) {
439         encoder << true;
440         return;
441     }
442
443     encoder << false;
444
445     CFIndex size = CFDictionaryGetCount(dictionary);
446     Vector<CFTypeRef, 32> keys(size);
447     Vector<CFTypeRef, 32> values(size);
448     
449     CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data());
450
451     HashSet<CFTypeRef> invalidKeys;
452     for (CFIndex i = 0; i < size; ++i) {
453         ASSERT(keys[i]);
454         ASSERT(values[i]);
455
456         // Ignore keys/values we don't support.
457         ASSERT(typeFromCFTypeRef(keys[i]) != Unknown);
458         ASSERT(typeFromCFTypeRef(values[i]) != Unknown);
459         if (typeFromCFTypeRef(keys[i]) == Unknown || typeFromCFTypeRef(values[i]) == Unknown)
460             invalidKeys.add(keys[i]);
461     }
462
463     encoder << static_cast<uint64_t>(size - invalidKeys.size());
464
465     for (CFIndex i = 0; i < size; ++i) {
466         if (invalidKeys.contains(keys[i]))
467             continue;
468
469         encode(encoder, keys[i]);
470         encode(encoder, values[i]);
471     }
472 }
473
474 bool decode(Decoder& decoder, RetainPtr<CFDictionaryRef>& result)
475 {
476     bool isNull = false;
477     if (!decoder.decode(isNull))
478         return false;
479
480     if (isNull) {
481         result = nullptr;
482         return true;
483     }
484
485     uint64_t size;
486     if (!decoder.decode(size))
487         return false;
488
489     RetainPtr<CFMutableDictionaryRef> dictionary = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
490     for (uint64_t i = 0; i < size; ++i) {
491         RetainPtr<CFTypeRef> key;
492         if (!decode(decoder, key))
493             return false;
494
495         RetainPtr<CFTypeRef> value;
496         if (!decode(decoder, value))
497             return false;
498
499         CFDictionarySetValue(dictionary.get(), key.get(), value.get());
500     }
501
502     result = adoptCF(dictionary.leakRef());
503     return true;
504 }
505
506 void encode(Encoder& encoder, CFNumberRef number)
507 {
508     CFNumberType numberType = CFNumberGetType(number);
509
510     Vector<uint8_t> buffer(CFNumberGetByteSize(number));
511     bool result = CFNumberGetValue(number, numberType, buffer.data());
512     ASSERT_UNUSED(result, result);
513
514     encoder.encodeEnum(numberType);
515     encoder << IPC::DataReference(buffer);
516 }
517
518 static size_t sizeForNumberType(CFNumberType numberType)
519 {
520     switch (numberType) {
521     case kCFNumberSInt8Type:
522         return sizeof(SInt8);
523     case kCFNumberSInt16Type:
524         return sizeof(SInt16);
525     case kCFNumberSInt32Type:
526         return sizeof(SInt32);
527     case kCFNumberSInt64Type:
528         return sizeof(SInt64);
529     case kCFNumberFloat32Type:
530         return sizeof(Float32);
531     case kCFNumberFloat64Type:
532         return sizeof(Float64);
533     case kCFNumberCharType:
534         return sizeof(char);
535     case kCFNumberShortType:
536         return sizeof(short);
537     case kCFNumberIntType:
538         return sizeof(int);
539     case kCFNumberLongType:
540         return sizeof(long);
541     case kCFNumberLongLongType:
542         return sizeof(long long);
543     case kCFNumberFloatType:
544         return sizeof(float);
545     case kCFNumberDoubleType:
546         return sizeof(double);
547     case kCFNumberCFIndexType:
548         return sizeof(CFIndex);
549     case kCFNumberNSIntegerType:
550         return sizeof(long);
551     case kCFNumberCGFloatType:
552         return sizeof(double);
553     }
554
555     return 0;
556 }
557
558 bool decode(Decoder& decoder, RetainPtr<CFNumberRef>& result)
559 {
560     CFNumberType numberType;
561     if (!decoder.decodeEnum(numberType))
562         return false;
563
564     IPC::DataReference dataReference;
565     if (!decoder.decode(dataReference))
566         return false;
567
568     size_t neededBufferSize = sizeForNumberType(numberType);
569     if (!neededBufferSize || dataReference.size() != neededBufferSize)
570         return false;
571
572     ASSERT(dataReference.data());
573     CFNumberRef number = CFNumberCreate(0, numberType, dataReference.data());
574     result = adoptCF(number);
575
576     return true;
577 }
578
579 void encode(Encoder& encoder, CFStringRef string)
580 {
581     CFIndex length = CFStringGetLength(string);
582     CFStringEncoding encoding = CFStringGetFastestEncoding(string);
583
584     CFRange range = CFRangeMake(0, length);
585     CFIndex bufferLength = 0;
586
587     CFIndex numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, 0, 0, &bufferLength);
588     ASSERT(numConvertedBytes == length);
589
590     Vector<UInt8, 128> buffer(bufferLength);
591     numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, buffer.data(), buffer.size(), &bufferLength);
592     ASSERT(numConvertedBytes == length);
593
594     encoder.encodeEnum(encoding);
595     encoder << IPC::DataReference(buffer);
596 }
597
598 bool decode(Decoder& decoder, RetainPtr<CFStringRef>& result)
599 {
600     CFStringEncoding encoding;
601     if (!decoder.decodeEnum(encoding))
602         return false;
603
604     if (!CFStringIsEncodingAvailable(encoding))
605         return false;
606     
607     IPC::DataReference dataReference;
608     if (!decoder.decode(dataReference))
609         return false;
610
611     CFStringRef string = CFStringCreateWithBytes(0, dataReference.data(), dataReference.size(), encoding, false);
612     if (!string)
613         return false;
614
615     result = adoptCF(string);
616     return true;
617 }
618
619 void encode(Encoder& encoder, CFURLRef url)
620 {
621     CFURLRef baseURL = CFURLGetBaseURL(url);
622     encoder << static_cast<bool>(baseURL);
623     if (baseURL)
624         encode(encoder, baseURL);
625
626     WTF::URLCharBuffer urlBytes;
627     WTF::getURLBytes(url, urlBytes);
628     IPC::DataReference dataReference(reinterpret_cast<const uint8_t*>(urlBytes.data()), urlBytes.size());
629     encoder << dataReference;
630 }
631
632 bool decode(Decoder& decoder, RetainPtr<CFURLRef>& result)
633 {
634     RetainPtr<CFURLRef> baseURL;
635     bool hasBaseURL;
636     if (!decoder.decode(hasBaseURL))
637         return false;
638     if (hasBaseURL) {
639         if (!decode(decoder, baseURL))
640             return false;
641     }
642
643     IPC::DataReference urlBytes;
644     if (!decoder.decode(urlBytes))
645         return false;
646
647 #if USE(FOUNDATION)
648     // FIXME: Move this to ArgumentCodersCFMac.mm and change this file back to be C++
649     // instead of Objective-C++.
650     if (urlBytes.isEmpty()) {
651         // CFURL can't hold an empty URL, unlike NSURL.
652         // FIXME: This discards base URL, which seems incorrect.
653         result = (__bridge CFURLRef)[NSURL URLWithString:@""];
654         return true;
655     }
656 #endif
657
658     result = WTF::createCFURLFromBuffer(reinterpret_cast<const char*>(urlBytes.data()), urlBytes.size(), baseURL.get());
659     return result;
660 }
661
662 void encode(Encoder& encoder, SecCertificateRef certificate)
663 {
664     RetainPtr<CFDataRef> data = adoptCF(SecCertificateCopyData(certificate));
665     encode(encoder, data.get());
666 }
667
668 bool decode(Decoder& decoder, RetainPtr<SecCertificateRef>& result)
669 {
670     RetainPtr<CFDataRef> data;
671     if (!decode(decoder, data))
672         return false;
673
674     result = adoptCF(SecCertificateCreateWithData(0, data.get()));
675     return true;
676 }
677
678 #if PLATFORM(IOS_FAMILY)
679 static bool secKeyRefDecodingAllowed;
680
681 void setAllowsDecodingSecKeyRef(bool allowsDecodingSecKeyRef)
682 {
683     secKeyRefDecodingAllowed = allowsDecodingSecKeyRef;
684 }
685
686 static CFDataRef copyPersistentRef(SecKeyRef key)
687 {
688     RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials));
689     // This function differs from SecItemCopyPersistentRef in that it specifies an access group.
690     // This is necessary in case there are multiple copies of the key in the keychain, because we
691     // need a reference to the one that the Networking process will be able to access.
692     CFDataRef persistentRef = nullptr;
693     SecItemCopyMatching((CFDictionaryRef)@{
694         (id)kSecReturnPersistentRef: @YES,
695         (id)kSecValueRef: (id)key,
696         (id)kSecAttrSynchronizable: (id)kSecAttrSynchronizableAny,
697         (id)kSecAttrAccessGroup: @"com.apple.identities",
698     }, (CFTypeRef*)&persistentRef);
699
700     return persistentRef;
701 }
702 #endif
703
704 void encode(Encoder& encoder, SecIdentityRef identity)
705 {
706     SecCertificateRef certificate = nullptr;
707     SecIdentityCopyCertificate(identity, &certificate);
708     encode(encoder, certificate);
709     CFRelease(certificate);
710
711     SecKeyRef key = nullptr;
712     SecIdentityCopyPrivateKey(identity, &key);
713
714     CFDataRef keyData = nullptr;
715 #if PLATFORM(IOS_FAMILY)
716     keyData = copyPersistentRef(key);
717 #endif
718 #if PLATFORM(MAC)
719     RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials));
720     SecKeychainItemCreatePersistentReference((SecKeychainItemRef)key, &keyData);
721 #endif
722     CFRelease(key);
723
724     encoder << !!keyData;
725     if (keyData) {
726         encode(encoder, keyData);
727         CFRelease(keyData);
728     }
729 }
730
731 bool decode(Decoder& decoder, RetainPtr<SecIdentityRef>& result)
732 {
733     RetainPtr<SecCertificateRef> certificate;
734     if (!decode(decoder, certificate))
735         return false;
736
737     bool hasKey;
738     if (!decoder.decode(hasKey))
739         return false;
740
741     if (!hasKey)
742         return true;
743
744     RetainPtr<CFDataRef> keyData;
745     if (!decode(decoder, keyData))
746         return false;
747
748 #if PLATFORM(COCOA)
749     if (!hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials))
750         return true;
751 #endif
752
753     SecKeyRef key = nullptr;
754 #if PLATFORM(IOS_FAMILY)
755     if (secKeyRefDecodingAllowed)
756         SecKeyFindWithPersistentRef(keyData.get(), &key);
757 #endif
758 #if PLATFORM(MAC)
759     SecKeychainItemCopyFromPersistentReference(keyData.get(), (SecKeychainItemRef*)&key);
760 #endif
761     if (key) {
762         result = adoptCF(SecIdentityCreate(kCFAllocatorDefault, certificate.get(), key));
763         CFRelease(key);
764     }
765
766     return true;
767 }
768
769 #if HAVE(SEC_KEYCHAIN)
770 void encode(Encoder& encoder, SecKeychainItemRef keychainItem)
771 {
772     RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials));
773
774     CFDataRef data;
775     if (SecKeychainItemCreatePersistentReference(keychainItem, &data) == errSecSuccess) {
776         encode(encoder, data);
777         CFRelease(data);
778     }
779 }
780
781 bool decode(Decoder& decoder, RetainPtr<SecKeychainItemRef>& result)
782 {
783     RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials));
784
785     RetainPtr<CFDataRef> data;
786     if (!IPC::decode(decoder, data))
787         return false;
788
789     SecKeychainItemRef item;
790     if (SecKeychainItemCopyFromPersistentReference(data.get(), &item) != errSecSuccess || !item)
791         return false;
792     
793     result = adoptCF(item);
794     return true;
795 }
796 #endif
797
798 #if HAVE(SEC_ACCESS_CONTROL)
799 void encode(Encoder& encoder, SecAccessControlRef accessControl)
800 {
801     RetainPtr<CFDataRef> data = adoptCF(SecAccessControlCopyData(accessControl));
802     if (data)
803         encode(encoder, data.get());
804 }
805
806 bool decode(Decoder& decoder, RetainPtr<SecAccessControlRef>& result)
807 {
808     RetainPtr<CFDataRef> data;
809     if (!decode(decoder, data))
810         return false;
811
812     result = adoptCF(SecAccessControlCreateFromData(kCFAllocatorDefault, data.get(), nullptr));
813     if (!result)
814         return false;
815
816     return true;
817 }
818 #endif
819
820 #if HAVE(SEC_TRUST_SERIALIZATION)
821 void encode(Encoder& encoder, SecTrustRef trust)
822 {
823     auto data = adoptCF(SecTrustSerialize(trust, nullptr));
824     if (!data) {
825         encoder << false;
826         return;
827     }
828
829     encoder << true;
830     IPC::encode(encoder, data.get());
831 }
832
833 bool decode(Decoder& decoder, RetainPtr<SecTrustRef>& result)
834 {
835     bool hasTrust;
836     if (!decoder.decode(hasTrust))
837         return false;
838
839     if (!hasTrust)
840         return true;
841
842     RetainPtr<CFDataRef> trustData;
843     if (!IPC::decode(decoder, trustData))
844         return false;
845
846     auto trust = adoptCF(SecTrustDeserialize(trustData.get(), nullptr));
847     if (!trust)
848         return false;
849
850     result = WTFMove(trust);
851     return true;
852 }
853 #endif
854
855 } // namespace IPC