2 * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
30 #include <Security/SecItem.h>
31 #include <Security/SecItemPriv.h>
32 #include <Security/SecItemInternal.h>
33 #ifndef SECITEM_SHIM_OSX
34 #include <Security/SecKey.h>
35 #include <Security/SecKeyPriv.h>
36 #include <Security/SecCertificateInternal.h>
37 #include <Security/SecIdentity.h>
38 #include <Security/SecIdentityPriv.h>
39 #include <Security/SecRandom.h>
40 #include <Security/SecBasePriv.h>
41 #endif // *** END SECITEM_SHIM_OSX ***
49 #include <sys/param.h>
51 #include <Security/SecBase.h>
52 #include <CoreFoundation/CFData.h>
53 #include <CoreFoundation/CFDate.h>
54 #include <CoreFoundation/CFDictionary.h>
55 #include <CoreFoundation/CFNumber.h>
56 #include <CoreFoundation/CFString.h>
57 #include <CoreFoundation/CFURL.h>
58 #include <CommonCrypto/CommonDigest.h>
59 #include <libkern/OSByteOrder.h>
60 #include <security_utilities/debugging.h>
62 #include <Security/SecInternal.h>
63 #include <TargetConditionals.h>
64 #include "securityd_client.h"
65 #include "securityd_server.h"
66 #include <AssertMacros.h>
68 #include <sys/types.h>
72 #ifndef SECITEM_SHIM_OSX
73 #include <libDER/asn1Types.h>
74 #endif // *** END SECITEM_SHIM_OSX ***
76 /* label when certificate data is joined with key data */
77 #define CERTIFICATE_DATA_COLUMN_LABEL "certdata"
79 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
80 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
82 Currently in need of conversion below:
83 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
84 @@@ kSecMatchPolicy allows a query with a SecPolicyRef
85 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
86 currently implemented at all, but when it is needs to short circuit to
87 local evaluation, different from the sql query abilities
90 #ifndef SECITEM_SHIM_OSX
91 static CFDictionaryRef
92 SecItemCopyAttributeDictionary(CFTypeRef ref
) {
93 CFDictionaryRef refDictionary
= NULL
;
94 CFTypeID typeID
= CFGetTypeID(ref
);
95 if (typeID
== SecKeyGetTypeID()) {
96 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
97 } else if (typeID
== SecCertificateGetTypeID()) {
99 SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
100 } else if (typeID
== SecIdentityGetTypeID()) {
102 SecIdentityRef identity
= (SecIdentityRef
)ref
;
103 SecCertificateRef cert
= NULL
;
104 SecKeyRef key
= NULL
;
105 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
106 !SecIdentityCopyPrivateKey(identity
, &key
))
108 CFDataRef data
= SecCertificateCopyData(cert
);
109 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
111 if (key_dict
&& data
) {
112 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
113 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
,
114 CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
), data
);
116 CFReleaseNull(key_dict
);
122 refDictionary
= NULL
;
124 return refDictionary
;
128 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
129 CFTypeRef ref
= NULL
;
130 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
131 if (CFEqual(class, kSecClassCertificate
)) {
132 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
133 } else if (CFEqual(class, kSecClassKey
)) {
134 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
135 } else if (CFEqual(class, kSecClassIdentity
)) {
136 CFAllocatorRef allocator
= NULL
;
137 CFDataRef data
= CFDictionaryGetValue(refAttributes
, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
));
138 SecCertificateRef cert
= SecCertificateCreateWithData(allocator
, data
);
139 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
141 ref
= SecIdentityCreate(allocator
, cert
, key
);
145 /* We don't support SecKeychainItemRefs yet. */
146 } else if (CFEqual(class, kSecClassGenericPassword
)) {
147 } else if (CFEqual(class, kSecClassInternetPassword
)) {
148 } else if (CFEqual(class, kSecClassAppleSharePassword
)) {
156 /* Turn the returned dictionary that contains all the attributes to create a
157 ref into the exact result the client asked for */
158 static CFTypeRef
makeRef(CFTypeRef ref
, bool return_data
, bool return_attributes
)
160 CFTypeRef result
= NULL
;
161 if (!ref
|| (CFGetTypeID(ref
) != CFDictionaryGetTypeID()))
164 CFTypeRef return_ref
= SecItemCreateFromAttributeDictionary(ref
);
166 if (return_data
|| return_attributes
) {
167 if (return_attributes
)
168 result
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, ref
);
170 result
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
173 CFDictionarySetValue((CFMutableDictionaryRef
)result
, kSecValueRef
, return_ref
);
174 CFRelease(return_ref
);
178 CFDictionaryRemoveValue((CFMutableDictionaryRef
)result
, kSecValueData
);
186 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
189 return -1 /* unimpErr */;
193 static void merge_dictionary_by_overwrite(const void *key
, const void *value
, void *context
)
195 if (!CFEqual(key
, kSecValueRef
))
196 CFDictionarySetValue((CFMutableDictionaryRef
)context
, key
, value
);
199 static void copy_applier(const void *key
, const void *value
, void *context
)
201 CFDictionarySetValue(context
, key
, value
);
204 static OSStatus
cook_query(CFDictionaryRef query
, CFMutableDictionaryRef
*explode
)
206 /* If a ref was specified we get it's attribute dictionary and parse it. */
207 CFMutableDictionaryRef args
= NULL
;
208 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
210 CFDictionaryRef refAttributes
= SecItemCopyAttributeDictionary(value
);
212 return errSecValueRefUnsupported
;
214 /* Replace any attributes we already got from the ref with the ones
215 from the attributes dictionary the caller passed us. This allows
216 a caller to add an item using attributes from the ref and still
217 override some of them in the dictionary directly. */
218 args
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, refAttributes
);
219 CFRelease(refAttributes
);
220 CFDictionaryApplyFunction(query
, merge_dictionary_by_overwrite
, args
);
222 value
= CFDictionaryGetValue(query
, kSecAttrIssuer
);
224 /* convert DN to canonical issuer, if value is DN (top level sequence) */
225 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
226 DERDecodedInfo content
;
227 if (!DERDecodeItem(&name
, &content
) &&
228 (content
.tag
== ASN1_CONSTR_SEQUENCE
))
230 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
231 if (canonical_issuer
) {
233 args
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
234 /* This is necessary because we rely on non NULL callbacks */
235 CFDictionaryApplyFunction(query
, copy_applier
, args
);
237 /* Overwrite with new issuer */
238 CFDictionarySetValue(args
, kSecAttrIssuer
, canonical_issuer
);
239 CFRelease(canonical_issuer
);
247 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, ...);
249 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
250 OSStatus
*return_status
, CFTypeRef
*return_result
)
252 bool handled
= false;
253 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
255 CFTypeID typeID
= CFGetTypeID(value
);
256 if (typeID
== SecIdentityGetTypeID()) {
258 OSStatus status
= errSecSuccess
;
259 SecIdentityRef identity
= (SecIdentityRef
)value
;
260 SecCertificateRef cert
= NULL
;
261 SecKeyRef key
= NULL
;
262 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
263 !SecIdentityCopyPrivateKey(identity
, &key
))
265 CFMutableDictionaryRef partial_query
=
266 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
267 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
268 CFTypeRef result
= NULL
;
269 bool duplicate_cert
= false;
270 /* an identity is first and foremost a key, but it can have multiple
271 certs associated with it: so we identify it by the cert */
272 status
= operation(partial_query
, return_result
? &result
: NULL
);
273 if ((operation
== (secitem_operation
)SecItemAdd
) &&
274 (status
== errSecDuplicateItem
)) {
275 duplicate_cert
= true;
276 status
= errSecSuccess
;
279 if (!status
|| status
== errSecItemNotFound
) {
280 bool skip_key_operation
= false;
282 /* if the key is still in use, skip deleting it */
283 if (operation
== (secitem_operation
)SecItemDelete
) {
284 // find certs with cert.pkhh == keys.klbl
285 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
286 CFDataRef pkhh
= NULL
;
288 key_dict
= SecKeyCopyAttributeDictionary(key
);
290 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
291 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
292 const void *vals
[] = { kSecClassCertificate
, pkhh
};
294 query_dict
= CFDictionaryCreate(NULL
, keys
,
295 vals
, (sizeof(keys
) / sizeof(*keys
)),
298 if (noErr
== SecItemCopyMatching(query_dict
, NULL
))
299 skip_key_operation
= true;
300 CFReleaseSafe(query_dict
);
301 CFReleaseSafe(key_dict
);
304 if (!skip_key_operation
) {
305 /* now perform the operation for the key */
306 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
307 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
308 status
= operation(partial_query
, NULL
);
309 if ((operation
== (secitem_operation
)SecItemAdd
) &&
310 (status
== errSecDuplicateItem
) &&
312 status
= errSecSuccess
;
315 /* add and copy matching for an identityref have a persistent ref result */
318 /* result is a persistent ref to a cert */
320 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
)) {
321 *return_result
= _SecItemMakePersistentRef(kSecClassIdentity
, rowid
);
327 CFReleaseNull(partial_query
);
330 status
= errSecInvalidItemRef
;
334 *return_status
= status
;
337 value
= CFDictionaryGetValue(attributes
, kSecClass
);
338 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
339 (operation
== (secitem_operation
)SecItemDelete
)) {
340 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
341 CFDictionaryRemoveValue(dict
, kSecClass
);
342 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
343 OSStatus status
= SecItemDelete(dict
);
345 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
346 status
= SecItemDelete(dict
);
349 *return_status
= status
;
356 static void infer_cert_label(CFDictionaryRef attributes
, CFMutableDictionaryRef args
)
358 if (!args
|| !attributes
)
361 if (CFDictionaryContainsKey(attributes
, kSecAttrLabel
))
364 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
, kSecValueRef
);
365 if (!value_ref
|| (CFGetTypeID(value_ref
) != SecCertificateGetTypeID()))
368 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
369 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
371 CFDictionarySetValue(args
, kSecAttrLabel
, label
);
372 CFReleaseNull(label
);
376 /* A persistent ref is just the class and the rowid of the record. */
377 CFDataRef
_SecItemMakePersistentRef(CFTypeRef
class, sqlite_int64 rowid
)
379 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
382 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
383 kCFStringEncodingUTF8
))
385 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
386 return CFDataCreate(NULL
, bytes
, sizeof(bytes
));
391 /* AUDIT[securityd](done):
392 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
394 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
)
396 bool valid_ref
= false;
397 if (CFGetTypeID(persistent_ref
) == CFDataGetTypeID() &&
398 CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
399 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
400 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
402 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
403 bytes
, CFStringGetLength(kSecClassGenericPassword
),
404 kCFStringEncodingUTF8
, true);
405 const void *valid_classes
[] = { kSecClassGenericPassword
,
406 kSecClassInternetPassword
,
407 kSecClassAppleSharePassword
,
408 kSecClassCertificate
,
412 for (i
=0; i
< sizeof(valid_classes
)/sizeof(*valid_classes
); i
++) {
413 if (CFEqual(valid_classes
[i
], class)) {
415 *return_class
= valid_classes
[i
];
417 *return_rowid
= rowid
;
427 static bool cf_bool_value(CFTypeRef cf_bool
)
429 return (cf_bool
&& CFEqual(kCFBooleanTrue
, cf_bool
));
433 result_post(CFDictionaryRef query
, CFTypeRef raw_result
, CFTypeRef
*result
) {
437 bool return_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
438 bool return_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
439 bool return_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
442 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
443 CFIndex i
, count
= CFArrayGetCount(raw_result
);
444 CFMutableArrayRef tmp_array
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
445 for (i
= 0; i
< count
; i
++) {
446 CFTypeRef ref
= makeRef(CFArrayGetValueAtIndex(raw_result
, i
), return_data
, return_attributes
);
448 CFArrayAppendValue(tmp_array
, ref
);
454 *result
= makeRef(raw_result
, return_data
, return_attributes
);
456 CFRelease(raw_result
);
458 *result
= raw_result
;
460 #endif // *** END SECITEM_SHIM_OSX ***
464 SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef
*result
)
466 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
)
467 #endif // *** END SECITEM_SHIM_OSX ***
469 CFMutableDictionaryRef args
= NULL
;
470 CFTypeRef raw_result
= NULL
;
473 #ifndef SECITEM_SHIM_OSX
474 require_quiet(!explode_identity(attributes
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
475 require_noerr_quiet(status
= cook_query(attributes
, &args
), errOut
);
476 infer_cert_label(attributes
, args
);
477 #endif // *** END SECITEM_SHIM_OSX ***
480 status
= SECURITYD_AG(sec_item_add
, attributes
, &raw_result
);
481 #ifndef SECITEM_SHIM_OSX
482 result_post(attributes
, raw_result
, result
);
483 #endif // *** END SECITEM_SHIM_OSX ***
492 SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef
*result
)
494 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef
*result
)
495 #endif // *** END SECITEM_SHIM_OSX ***
497 CFMutableDictionaryRef args
= NULL
;
498 CFTypeRef raw_result
= NULL
;
501 #ifndef SECITEM_SHIM_OSX
502 require_quiet(!explode_identity(query
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
503 require_noerr_quiet(status
= cook_query(query
, &args
), errOut
);
504 #endif // *** END SECITEM_SHIM_OSX ***
508 status
= SECURITYD_AG(sec_item_copy_matching
, query
, &raw_result
);
509 #ifndef SECITEM_SHIM_OSX
510 result_post(query
, raw_result
, result
);
511 #endif // *** END SECITEM_SHIM_OSX ***
520 SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
)
522 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
)
523 #endif // *** END SECITEM_SHIM_OSX ***
525 CFMutableDictionaryRef args
= NULL
;
528 #ifndef SECITEM_SHIM_OSX
529 require_noerr_quiet(status
= cook_query(query
, &args
), errOut
);
530 #endif // *** END SECITEM_SHIM_OSX ***
535 status
= gSecurityd
->sec_item_update(query
, attributesToUpdate
, SecAccessGroupsGetCurrent());
537 const void *values
[] = { (const void *)query
, (const void *)attributesToUpdate
};
538 CFArrayRef pair
= CFArrayCreate(kCFAllocatorDefault
, values
, 2, NULL
/*&kCFTypeArrayCallBacks*/);
540 status
= ServerCommandSendReceive(sec_item_update_id
, pair
, NULL
);
543 status
= errSecAllocate
;
552 static void copy_all_keys_and_values(const void *key
, const void *value
, void *context
)
554 CFDictionaryAddValue((CFMutableDictionaryRef
)context
, key
, value
);
557 static OSStatus
explode_persistent_identity_ref(CFDictionaryRef query
, CFMutableDictionaryRef
*delete_query
)
559 OSStatus status
= errSecSuccess
;
560 CFTypeRef persist
= CFDictionaryGetValue(query
, kSecValuePersistentRef
);
562 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
)
563 && CFEqual(class, kSecClassIdentity
)) {
564 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
565 const void *vals
[] = { kCFBooleanTrue
, persist
};
566 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
567 vals
, (sizeof(keys
) / sizeof(*keys
)), NULL
, NULL
);
568 CFTypeRef item_query
= NULL
;
569 status
= SecItemCopyMatching(persistent_query
, &item_query
);
570 CFReleaseNull(persistent_query
);
573 CFMutableDictionaryRef new_query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
574 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
576 CFDictionaryApplyFunction(query
, copy_all_keys_and_values
, new_query
);
577 CFDictionaryRemoveValue(new_query
, kSecValuePersistentRef
);
578 CFDictionarySetValue(new_query
, kSecValueRef
, item_query
);
579 *delete_query
= new_query
;
581 status
= errSecAllocate
;
582 CFRelease(item_query
);
590 SecItemDelete_ios(CFDictionaryRef query
)
592 SecItemDelete(CFDictionaryRef query
)
593 #endif // *** END SECITEM_SHIM_OSX ***
595 CFMutableDictionaryRef args1
= NULL
, args2
= NULL
;
598 #ifndef SECITEM_SHIM_OSX
599 require_noerr_quiet(status
= explode_persistent_identity_ref(query
, &args1
), errOut
);
602 require_quiet(!explode_identity(query
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
603 require_noerr_quiet(status
= cook_query(query
, &args2
), errOut
);
604 #endif // *** END SECITEM_SHIM_OSX ***
609 status
= gSecurityd
->sec_item_delete(query
,
610 SecAccessGroupsGetCurrent());
612 status
= ServerCommandSendReceive(sec_item_delete_id
, query
, NULL
);
616 CFReleaseSafe(args1
);
617 CFReleaseSafe(args2
);
622 SecItemDeleteAll(void)
624 OSStatus status
= noErr
;
626 #ifndef SECITEM_SHIM_OSX
627 SecTrustStoreRef ts
= SecTrustStoreForDomain(kSecTrustStoreDomainUser
);
628 if (!gSecurityd
->sec_truststore_remove_all(ts
))
629 status
= errSecInternal
;
630 #endif // *** END SECITEM_SHIM_OSX ***
631 if (!gSecurityd
->sec_item_delete_all())
632 status
= errSecInternal
;
634 status
= ServerCommandSendReceive(sec_delete_all_id
, NULL
, NULL
);
639 OSStatus
_SecMigrateKeychain(int32_t handle_in
, CFDataRef data_in
,
640 int32_t *handle_out
, CFDataRef
*data_out
)
642 CFMutableArrayRef args
= NULL
;
643 CFTypeRef raw_result
= NULL
;
644 CFNumberRef hin
= NULL
, hout
= NULL
;
645 OSStatus status
= errSecAllocate
;
647 require_quiet(args
= CFArrayCreateMutable(kCFAllocatorDefault
, 2, NULL
), errOut
);
648 require_quiet(hin
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &handle_in
), errOut
);
649 CFArrayAppendValue(args
, hin
);
651 CFArrayAppendValue(args
, data_in
);
653 require_noerr_quiet(status
= SECURITYD(sec_migrate_keychain
, args
, &raw_result
), errOut
);
654 hout
= CFArrayGetValueAtIndex(raw_result
, 0);
657 if (CFArrayGetCount(raw_result
) > 1) {
658 data
= CFArrayGetValueAtIndex(raw_result
, 1);
659 require_quiet(CFGetTypeID(data
) == CFDataGetTypeID(), errOut
);
670 CFReleaseSafe(raw_result
);
674 /* TODO: Move to a location shared between securityd and Security framework. */
675 const char *restore_keychain_location
= "/Library/Keychains/keychain.restoring";
677 OSStatus
_SecRestoreKeychain(const char *path
)
679 OSStatus status
= errSecInternal
;
681 require_quiet(!geteuid(), out
);
682 struct passwd
*pass
= NULL
;
683 require_quiet(pass
= getpwnam("_securityd"), out
);
684 uid_t securityUID
= pass
->pw_uid
;
685 struct group
*grp
= NULL
;
686 require_quiet(grp
= getgrnam("wheel"), out
);
687 gid_t wheelGID
= grp
->gr_gid
;
689 require_noerr_quiet(rename(path
, restore_keychain_location
), out
);
690 require_noerr_quiet(chmod(restore_keychain_location
, 0600), out
);
691 require_noerr_quiet(chown(restore_keychain_location
, securityUID
, wheelGID
),
694 status
= ServerCommandSendReceive(sec_restore_keychain_id
, NULL
, NULL
);
695 require_noerr_quiet(unlink(restore_keychain_location
), out
);
701 CFDataRef
_SecKeychainCopyOTABackup(void) {
702 CFTypeRef raw_result
= NULL
;
703 CFDataRef backup
= NULL
;
706 require_noerr_quiet(status
= SECURITYD(sec_keychain_backup
, NULL
,
707 &raw_result
), errOut
);
708 if (raw_result
&& CFGetTypeID(raw_result
) == CFDataGetTypeID()) {
710 raw_result
= NULL
; /* So it doesn't get released below. */
714 CFReleaseSafe(raw_result
);
718 CFDataRef
_SecKeychainCopyBackup(CFDataRef backupKeybag
, CFDataRef password
) {
719 CFMutableArrayRef args
;
720 CFTypeRef raw_result
= NULL
;
721 CFDataRef backup
= NULL
;
724 require_quiet(args
= CFArrayCreateMutable(kCFAllocatorDefault
, 2, NULL
),
726 CFArrayAppendValue(args
, backupKeybag
);
728 CFArrayAppendValue(args
, password
);
730 require_noerr_quiet(status
= SECURITYD(sec_keychain_backup
, args
,
731 &raw_result
), errOut
);
732 if (raw_result
&& CFGetTypeID(raw_result
) == CFDataGetTypeID()) {
734 raw_result
= NULL
; /* So it doesn't get released below. */
739 CFReleaseSafe(raw_result
);
743 bool _SecKeychainRestoreBackup(CFDataRef backup
, CFDataRef backupKeybag
,
744 CFDataRef password
) {
745 CFMutableArrayRef args
= NULL
;
746 CFTypeRef raw_result
= NULL
;
747 OSStatus status
= errSecAllocate
;
749 require_quiet(args
= CFArrayCreateMutable(kCFAllocatorDefault
, 3, NULL
),
751 CFArrayAppendValue(args
, backup
);
752 CFArrayAppendValue(args
, backupKeybag
);
754 CFArrayAppendValue(args
, password
);
756 require_noerr_quiet(status
= SECURITYD(sec_keychain_restore
, args
, NULL
),
761 CFReleaseSafe(raw_result
);