2 * Copyright (c) 2002-2016 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@
24 #include <Security/SecCertificate.h>
25 #include <Security/SecCertificatePriv.h>
26 #include <security_keychain/Certificate.h>
27 #include <security_keychain/Item.h>
28 #include <security_keychain/KCCursor.h>
29 #include <Security/cssmapi.h>
30 #include <Security/cssmapple.h>
31 #include <security_cdsa_client/cspclient.h>
32 #include <security_cdsa_client/clclient.h>
33 #include <security_cdsa_client/tpclient.h>
34 #include <Security/cssmtype.h>
36 #include "SecBridge.h"
38 // %%% used by SecCertificate{Copy,Set}Preference
39 #include <Security/SecKeychainItemPriv.h>
40 #include <Security/SecIdentityPriv.h>
41 #include <Security/SecItemPriv.h>
42 #include <security_keychain/KCCursor.h>
43 #include <security_cdsa_utilities/Schema.h>
44 #include <security_cdsa_utils/cuCdsaUtils.h>
45 #include <sys/param.h>
47 #include "CertificateValues.h"
49 #include "AppleBaselineEscrowCertificates.h"
52 OSStatus
SecCertificateGetCLHandle_legacy(SecCertificateRef certificate
, CSSM_CL_HANDLE
*clHandle
);
53 extern CSSM_KEYUSE
ConvertArrayToKeyUsage(CFArrayRef usage
);
55 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
57 SEC_CONST_DECL (kSecCertificateProductionEscrowKey
, "ProductionEscrowKey");
58 SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey
, "ProductionPCSEscrowKey");
59 SEC_CONST_DECL (kSecCertificateEscrowFileName
, "AppleESCertificates");
62 using namespace CssmClient
;
64 CFTypeID
static SecCertificateGetTypeID_osx(void)
68 return gTypes().Certificate
.typeID
;
70 END_SECAPI1(_kCFRuntimeNotATypeID
)
74 SecCertificateIsItemImplInstance(SecCertificateRef certificate
)
76 if (certificate
== NULL
) {
80 CFTypeID typeID
= CFGetTypeID(certificate
);
82 #if 0 /* debug code to verify type IDs */
83 syslog(LOG_ERR
, "SecCertificate typeID=%d [STU=%d, OSX=%d, SKI=%d]",
85 (int)SecCertificateGetTypeID(),
86 (int)SecCertificateGetTypeID_osx(),
87 (int)SecKeychainItemGetTypeID());
89 if (typeID
== _kCFRuntimeNotATypeID
) {
93 return (typeID
== SecCertificateGetTypeID_osx() ||
94 typeID
== SecKeychainItemGetTypeID()) ? true : false;
97 /* convert a new-world SecCertificateRef to an old-world ItemImpl instance */
99 SecCertificateCreateItemImplInstance(SecCertificateRef certificate
)
104 SecCertificateRef implCertRef
= (SecCertificateRef
) SecCertificateCopyKeychainItem(certificate
);
108 CFDataRef data
= SecCertificateCopyData(certificate
);
113 CSSM_DATA cssmCertData
;
114 cssmCertData
.Length
= (data
) ? (CSSM_SIZE
)CFDataGetLength(data
) : 0;
115 cssmCertData
.Data
= (data
) ? (uint8
*)CFDataGetBytePtr(data
) : NULL
;
117 SecPointer
<Certificate
> certificatePtr(new Certificate(cssmCertData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
));
118 implCertRef
= certificatePtr
->handle();
125 /* convert an old-world ItemImpl instance to a new-world SecCertificateRef */
127 SecCertificateCreateFromItemImplInstance(SecCertificateRef certificate
)
132 SecCertificateRef result
= NULL
;
133 CFDataRef data
= NULL
;
135 CssmData certData
= Certificate::required(certificate
)->data();
136 if (certData
.Data
&& certData
.Length
) {
137 data
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
);
140 if (certData
.Data
&& !certData
.Length
) {
141 /* zero-length certs can exist, so don't bother logging this */
144 syslog(LOG_ERR
, "WARNING: SecKeychainSearchCopyNext failed to retrieve certificate data (length=%ld, data=0x%lX)",
145 (long)certData
.Length
, (uintptr_t)certData
.Data
);
152 result
= SecCertificateCreateWithKeychainItem(NULL
, data
, certificate
);
159 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
161 SecCertificateCreateFromData(const CSSM_DATA
*data
, CSSM_CERT_TYPE type
, CSSM_CERT_ENCODING encoding
, SecCertificateRef
*certificate
)
163 /* bridge to support old functionality */
164 if (!data
|| !data
->Data
|| !data
->Length
|| !certificate
) {
167 SecCertificateRef certRef
= NULL
;
169 // <rdar://problem/24403998> REG: Adobe {Photoshop, InDesign} CC(2015) crashes on launch
170 // If you take the length that SecKeychainItemCopyContent gives you (a Uint32) and assign it incorrectly
171 // to a CSSM_DATA Length field (a CSSM_SIZE, i.e., a size_t), the upper 32 bits aren't set. If those bits
172 // are non-zero, the length is incredibly wrong.
174 // Assume that there will not exist a certificate > 4GiB, and fake this length field.
175 CSSM_SIZE length
= data
->Length
& 0xfffffffful
;
177 CFDataRef dataRef
= CFDataCreate(NULL
, data
->Data
, length
);
179 certRef
= SecCertificateCreateWithData(NULL
, dataRef
);
182 *certificate
= certRef
;
183 return (certRef
) ? errSecSuccess
: errSecUnknownFormat
;
186 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
188 SecCertificateAddToKeychain(SecCertificateRef certificate
, SecKeychainRef keychain
)
190 // This macro creates an ItemImpl certificate if it does not exist
193 Item
item(Certificate::required(__itemImplRef
));
194 Keychain::optional(keychain
)->add(item
);
199 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
201 SecCertificateGetData(SecCertificateRef certificate
, CSSM_DATA_PTR data
)
205 if (!certificate
|| !data
) {
206 __secapiresult
=errSecParam
;
208 else if (SecCertificateIsItemImplInstance(certificate
)) {
209 Required(data
) = Certificate::required(certificate
)->data();
212 data
->Length
= (CSSM_SIZE
)SecCertificateGetLength(certificate
);
213 data
->Data
= (uint8
*)SecCertificateGetBytePtr(certificate
);
219 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
221 SecCertificateGetType(SecCertificateRef certificate
, CSSM_CERT_TYPE
*certificateType
)
223 // This macro creates an ItemImpl certificate if it does not exist
226 Required(certificateType
) = Certificate::required(__itemImplRef
)->type();
231 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
233 SecCertificateGetSubject(SecCertificateRef certificate
, const CSSM_X509_NAME
**subject
)
235 // This macro creates an ItemImpl certificate if it does not exist
238 Required(subject
) = Certificate::required(__itemImplRef
)->subjectName();
243 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
245 SecCertificateGetIssuer(SecCertificateRef certificate
, const CSSM_X509_NAME
**issuer
)
247 // This macro creates an ItemImpl certificate if it does not exist
250 Required(issuer
) = Certificate::required(__itemImplRef
)->issuerName();
255 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
257 SecCertificateGetCLHandle(SecCertificateRef certificate
, CSSM_CL_HANDLE
*clHandle
)
259 // This macro creates an ItemImpl certificate if it does not exist
262 Required(clHandle
) = Certificate::required(__itemImplRef
)->clHandle();
267 /* private function; assumes input is old-style ItemImpl certificate reference,
268 and does not release that certificate reference!
271 SecCertificateGetCLHandle_legacy(SecCertificateRef certificate
, CSSM_CL_HANDLE
*clHandle
)
275 Required(clHandle
) = Certificate::required(certificate
)->clHandle();
281 * Private API to infer a display name for a SecCertificateRef which
282 * may or may not be in a keychain.
287 SecCertificateInferLabel(SecCertificateRef certificate
, CFStringRef
*label
)
289 // This macro creates an ItemImpl certificate if it does not exist
292 Certificate::required(__itemImplRef
)->inferLabel(false, &Required(label
));
297 /* OS X only (note: iOS version has different arguments and return value) */
299 SecCertificateCopyPublicKey(SecCertificateRef certificate
, SecKeyRef
*key
)
301 // This macro creates an ItemImpl certificate if it does not exist
304 Required(key
) = Certificate::required(__itemImplRef
)->publicKey()->handle();
309 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
311 SecCertificateGetAlgorithmID(SecCertificateRef certificate
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
313 // This macro creates an ItemImpl certificate if it does not exist
316 Required(algid
) = Certificate::required(__itemImplRef
)->algorithmID();
323 SecCertificateCopySubjectComponent(SecCertificateRef certificate
, const CSSM_OID
*component
, CFStringRef
*result
)
325 // This macro creates an ItemImpl certificate if it does not exist
328 Required(result
) = Certificate::required(__itemImplRef
)->distinguishedName(&CSSMOID_X509V1SubjectNameCStruct
, component
);
333 /* OS X only; deprecated SPI */
335 SecCertificateGetCommonName(SecCertificateRef certificate
, CFStringRef
*commonName
)
337 // deprecated SPI signature; replaced by SecCertificateCopyCommonName
338 return SecCertificateCopyCommonName(certificate
, commonName
);
341 /* OS X only; deprecated SPI */
343 SecCertificateGetEmailAddress(SecCertificateRef certificate
, CFStringRef
*emailAddress
)
345 // This macro creates an ItemImpl certificate if it does not exist
348 Required(emailAddress
) = Certificate::required(__itemImplRef
)->copyFirstEmailAddress();
353 /* Return a zero terminated list of CSSM_DATA_PTR's with the values of the field specified by field.
354 * Caller must call releaseFieldValues to free the storage allocated by this call.
359 SecCertificateCopyFieldValues(SecCertificateRef certificate
, const CSSM_OID
*field
, CSSM_DATA_PTR
**fieldValues
)
361 // This macro creates an ItemImpl certificate if it does not exist
364 Required(fieldValues
) = Certificate::required(__itemImplRef
)->copyFieldValues(Required(field
));
371 SecCertificateReleaseFieldValues(SecCertificateRef certificate
, const CSSM_OID
*field
, CSSM_DATA_PTR
*fieldValues
)
373 // This macro creates an ItemImpl certificate if it does not exist
376 Certificate::required(__itemImplRef
)->releaseFieldValues(Required(field
), fieldValues
);
383 SecCertificateCopyFirstFieldValue(SecCertificateRef certificate
, const CSSM_OID
*field
, CSSM_DATA_PTR
*fieldValue
)
385 // This macro creates an ItemImpl certificate if it does not exist
388 Required(fieldValue
) = Certificate::required(__itemImplRef
)->copyFirstFieldValue(Required(field
));
395 SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate
, const CSSM_OID
*field
, CSSM_DATA_PTR fieldValue
)
397 // This macro creates an ItemImpl certificate if it does not exist
400 Certificate::required(__itemImplRef
)->releaseFieldValue(Required(field
), fieldValue
);
407 SecCertificateFindByIssuerAndSN(CFTypeRef keychainOrArray
,const CSSM_DATA
*issuer
,
408 const CSSM_DATA
*serialNumber
, SecCertificateRef
*certificate
)
410 if (issuer
&& serialNumber
) {
411 CFRef
<CFMutableDictionaryRef
> query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
412 CFDictionarySetValue(query
, kSecClass
, kSecClassCertificate
);
413 CFDictionarySetValue(query
, kSecReturnRef
, kCFBooleanTrue
);
414 CFDictionarySetValue(query
, kSecAttrNoLegacy
, kCFBooleanTrue
);
416 CFRef
<CFDataRef
> issuerData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)issuer
->Data
, issuer
->Length
, kCFAllocatorNull
);
417 CFDictionarySetValue(query
, kSecAttrIssuer
, issuerData
);
419 CFRef
<CFDataRef
> serialNumberData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)serialNumber
->Data
, serialNumber
->Length
, kCFAllocatorNull
);
420 CFDictionarySetValue(query
, kSecAttrSerialNumber
, serialNumberData
);
422 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)certificate
);
423 if (status
== errSecSuccess
) {
430 StorageManager::KeychainList keychains
;
431 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
432 Required(certificate
) = Certificate::findByIssuerAndSN(keychains
, CssmData::required(issuer
), CssmData::required(serialNumber
))->handle();
434 // convert ItemImpl-based SecCertificateRef to new-world version before returning
435 CssmData certData
= Certificate::required(*certificate
)->data();
436 CFRef
<CFDataRef
> cfData(CFDataCreate(NULL
, certData
.Data
, certData
.Length
));
437 SecCertificateRef tmpRef
= *certificate
;
438 *certificate
= SecCertificateCreateWithData(NULL
, cfData
);
446 SecCertificateFindBySubjectKeyID(CFTypeRef keychainOrArray
, const CSSM_DATA
*subjectKeyID
,
447 SecCertificateRef
*certificate
)
450 CFRef
<CFMutableDictionaryRef
> query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
451 CFDictionarySetValue(query
, kSecClass
, kSecClassCertificate
);
452 CFDictionarySetValue(query
, kSecReturnRef
, kCFBooleanTrue
);
453 CFDictionarySetValue(query
, kSecAttrNoLegacy
, kCFBooleanTrue
);
455 CFRef
<CFDataRef
> subjectKeyIDData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)subjectKeyID
->Data
, subjectKeyID
->Length
, kCFAllocatorNull
);
456 CFDictionarySetValue(query
, kSecAttrSubjectKeyID
, subjectKeyIDData
);
458 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)certificate
);
459 if (status
== errSecSuccess
) {
466 StorageManager::KeychainList keychains
;
467 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
468 Required(certificate
) = Certificate::findBySubjectKeyID(keychains
, CssmData::required(subjectKeyID
))->handle();
470 // convert ItemImpl-based SecCertificateRef to new-world version before returning
471 CssmData certData
= Certificate::required(*certificate
)->data();
472 CFRef
<CFDataRef
> cfData(CFDataCreate(NULL
, certData
.Data
, certData
.Length
));
473 SecCertificateRef tmpRef
= *certificate
;
474 *certificate
= SecCertificateCreateWithData(NULL
, cfData
);
482 SecCertificateFindByEmail(CFTypeRef keychainOrArray
, const char *emailAddress
, SecCertificateRef
*certificate
)
485 CFRef
<CFMutableDictionaryRef
> query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
486 CFDictionarySetValue(query
, kSecClass
, kSecClassCertificate
);
487 CFDictionarySetValue(query
, kSecReturnRef
, kCFBooleanTrue
);
488 CFDictionarySetValue(query
, kSecAttrNoLegacy
, kCFBooleanTrue
);
490 CFRef
<CFStringRef
> emailAddressString
= CFStringCreateWithCString(kCFAllocatorDefault
, emailAddress
, kCFStringEncodingUTF8
);
491 CFTypeRef keys
[] = { kSecPolicyName
};
492 CFTypeRef values
[] = { emailAddressString
};
493 CFRef
<CFDictionaryRef
> properties
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
494 CFRef
<SecPolicyRef
> policy
= SecPolicyCreateWithProperties(kSecPolicyAppleSMIME
, properties
);
495 CFDictionarySetValue(query
, kSecMatchPolicy
, policy
);
497 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)certificate
);
498 if (status
== errSecSuccess
) {
505 StorageManager::KeychainList keychains
;
506 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
507 Required(certificate
) = Certificate::findByEmail(keychains
, emailAddress
)->handle();
509 // convert ItemImpl-based SecCertificateRef to new-world version before returning
510 CssmData certData
= Certificate::required(*certificate
)->data();
511 CFRef
<CFDataRef
> cfData(CFDataCreate(NULL
, certData
.Data
, certData
.Length
));
512 SecCertificateRef tmpRef
= *certificate
;
513 *certificate
= SecCertificateCreateWithData(NULL
, cfData
);
521 SecKeychainSearchCreateForCertificateByIssuerAndSN(CFTypeRef keychainOrArray
, const CSSM_DATA
*issuer
,
522 const CSSM_DATA
*serialNumber
, SecKeychainSearchRef
*searchRef
)
528 StorageManager::KeychainList keychains
;
529 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
530 KCCursor
cursor(Certificate::cursorForIssuerAndSN(keychains
, CssmData::required(issuer
), CssmData::required(serialNumber
)));
531 *searchRef
= cursor
->handle();
538 SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(CFTypeRef keychainOrArray
, CFDataRef issuer
,
539 CFDataRef serialNumber
, SecKeychainSearchRef
*searchRef
)
545 StorageManager::KeychainList keychains
;
546 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
548 Required(serialNumber
);
549 KCCursor
cursor(Certificate::cursorForIssuerAndSN_CF(keychains
, issuer
, serialNumber
));
550 *searchRef
= cursor
->handle();
557 SecKeychainSearchCreateForCertificateBySubjectKeyID(CFTypeRef keychainOrArray
, const CSSM_DATA
*subjectKeyID
,
558 SecKeychainSearchRef
*searchRef
)
564 StorageManager::KeychainList keychains
;
565 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
566 KCCursor
cursor(Certificate::cursorForSubjectKeyID(keychains
, CssmData::required(subjectKeyID
)));
567 *searchRef
= cursor
->handle();
574 SecKeychainSearchCreateForCertificateByEmail(CFTypeRef keychainOrArray
, const char *emailAddress
,
575 SecKeychainSearchRef
*searchRef
)
581 StorageManager::KeychainList keychains
;
582 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
583 KCCursor
cursor(Certificate::cursorForEmail(keychains
, emailAddress
));
584 *searchRef
= cursor
->handle();
591 SecDigestGetData (CSSM_ALGORITHMS alg
, CSSM_DATA
* digest
, const CSSM_DATA
* data
)
595 if (!digest
|| !digest
->Data
|| !digest
->Length
|| !data
|| !data
->Data
|| !data
->Length
)
598 CSP
csp(gGuidAppleCSP
);
599 Digest
context(csp
, alg
);
600 CssmData
input(data
->Data
, data
->Length
);
601 CssmData
output(digest
->Data
, digest
->Length
);
603 context
.digest(input
, output
);
604 digest
->Length
= output
.length();
610 /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */
612 SecCertificateCopyPreference(
614 CSSM_KEYUSE keyUsage
,
615 SecCertificateRef
*certificate
)
620 Required(certificate
);
621 StorageManager::KeychainList keychains
;
622 globals().storageManager
.getSearchList(keychains
);
623 KCCursor
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
);
625 char idUTF8
[MAXPATHLEN
];
626 if (!CFStringGetCString(name
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
))
627 idUTF8
[0] = (char)'\0';
628 CssmData
service(const_cast<char *>(idUTF8
), strlen(idUTF8
));
629 FourCharCode itemType
= 'cprf';
630 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
);
631 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), itemType
);
633 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
);
636 if (!cursor
->next(prefItem
))
637 MacOSError::throwMe(errSecItemNotFound
);
639 // get persistent certificate reference
640 SecKeychainAttribute itemAttrs
[] = { { kSecGenericItemAttr
, 0, NULL
} };
641 SecKeychainAttributeList itemAttrList
= { sizeof(itemAttrs
) / sizeof(itemAttrs
[0]), itemAttrs
};
642 prefItem
->getContent(NULL
, &itemAttrList
, NULL
, NULL
);
644 // find certificate, given persistent reference data
645 CFDataRef pItemRef
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)itemAttrs
[0].data
, itemAttrs
[0].length
, kCFAllocatorNull
);
646 SecKeychainItemRef certItemRef
= nil
;
647 OSStatus status
= SecKeychainItemCopyFromPersistentReference(pItemRef
, &certItemRef
); //%%% need to make this a method of ItemImpl
648 prefItem
->freeContent(&itemAttrList
, NULL
);
654 *certificate
= (SecCertificateRef
)certItemRef
;
656 if (certItemRef
&& (CFGetTypeID(certItemRef
) == SecIdentityGetTypeID())) {
657 // SecKeychainItemCopyFromPersistentReference handed out an identity reference
659 status
= SecIdentityCopyCertificate((SecIdentityRef
)certItemRef
, certificate
);
660 CFRelease(certItemRef
);
669 SecCertificateCopyPreferred(
673 // This function will look for a matching preference in the following order:
674 // - matches the name and the supplied key use
675 // - matches the name and the special 'ANY' key use
676 // - matches the name with no key usage constraint
678 SecCertificateRef certRef
= NULL
;
679 CSSM_KEYUSE keyUse
= ConvertArrayToKeyUsage(keyUsage
);
680 OSStatus status
= SecCertificateCopyPreference(name
, keyUse
, &certRef
);
681 if (status
!= errSecSuccess
&& keyUse
!= CSSM_KEYUSE_ANY
)
682 status
= SecCertificateCopyPreference(name
, CSSM_KEYUSE_ANY
, &certRef
);
683 if (status
!= errSecSuccess
&& keyUse
!= 0)
684 status
= SecCertificateCopyPreference(name
, 0, &certRef
);
689 /* OS X only; not exported */
691 SecCertificateFindPreferenceItemWithNameAndKeyUsage(
692 CFTypeRef keychainOrArray
,
695 SecKeychainItemRef
*itemRef
)
699 StorageManager::KeychainList keychains
;
700 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
701 KCCursor
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
);
703 char idUTF8
[MAXPATHLEN
];
704 idUTF8
[0] = (char)'\0';
707 if (!CFStringGetCString(name
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
))
708 idUTF8
[0] = (char)'\0';
710 size_t idUTF8Len
= strlen(idUTF8
);
712 MacOSError::throwMe(errSecParam
);
714 CssmData
service(const_cast<char *>(idUTF8
), idUTF8Len
);
715 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
);
716 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), (FourCharCode
)'cprf');
718 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
);
721 if (!cursor
->next(item
))
722 MacOSError::throwMe(errSecItemNotFound
);
725 *itemRef
=item
->handle();
730 /* OS X only; not exported */
732 OSStatus
SecCertificateDeletePreferenceItemWithNameAndKeyUsage(
733 CFTypeRef keychainOrArray
,
737 // when a specific key usage is passed, we'll only match & delete that pref;
738 // when a key usage of 0 is passed, all matching prefs should be deleted.
739 // maxUsages represents the most matches there could theoretically be, so
740 // cut things off at that point if we're still finding items (if they can't
741 // be deleted for some reason, we'd never break out of the loop.)
743 OSStatus status
= errSecSuccess
;
744 SecKeychainItemRef item
= NULL
;
745 int count
= 0, maxUsages
= 12;
746 while (++count
<= maxUsages
&&
747 (status
= SecCertificateFindPreferenceItemWithNameAndKeyUsage(keychainOrArray
, name
, keyUsage
, &item
)) == errSecSuccess
) {
748 status
= SecKeychainItemDelete(item
);
753 // it's not an error if the item isn't found
754 return (status
== errSecItemNotFound
) ? errSecSuccess
: status
;
757 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
758 OSStatus
SecCertificateSetPreference(
759 SecCertificateRef certificate
,
761 CSSM_KEYUSE keyUsage
,
768 // treat NULL certificate as a request to clear the preference
769 // (note: if keyUsage is 0, this clears all key usage prefs for name)
770 return SecCertificateDeletePreferenceItemWithNameAndKeyUsage(NULL
, name
, keyUsage
);
773 // This macro creates an ItemImpl certificate if it does not exist
776 // determine the account attribute
778 // This attribute must be synthesized from certificate label + pref item type + key usage,
779 // as only the account and service attributes can make a generic keychain item unique.
780 // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that
781 // we can save a certificate preference if an identity preference already exists for the
782 // given service name, and vice-versa.
783 // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string.
785 CFStringRef labelStr
= nil
;
786 Certificate::required(__itemImplRef
)->inferLabel(false, &labelStr
);
788 MacOSError::throwMe(errSecDataTooLarge
); // data is "in a format which cannot be displayed"
790 CFIndex accountUTF8Len
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr
), kCFStringEncodingUTF8
) + 1;
791 const char *templateStr
= "%s [key usage 0x%X]";
792 const int keyUsageMaxStrLen
= 8;
793 accountUTF8Len
+= strlen(templateStr
) + keyUsageMaxStrLen
;
794 char accountUTF8
[accountUTF8Len
];
795 if (!CFStringGetCString(labelStr
, accountUTF8
, accountUTF8Len
-1, kCFStringEncodingUTF8
))
796 accountUTF8
[0] = (char)'\0';
798 snprintf(accountUTF8
, accountUTF8Len
-1, templateStr
, accountUTF8
, keyUsage
);
799 CssmData
account(const_cast<char *>(accountUTF8
), strlen(accountUTF8
));
802 // service attribute (name provided by the caller)
803 CFIndex serviceUTF8Len
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(name
), kCFStringEncodingUTF8
) + 1;;
804 char serviceUTF8
[serviceUTF8Len
];
805 if (!CFStringGetCString(name
, serviceUTF8
, serviceUTF8Len
-1, kCFStringEncodingUTF8
))
806 serviceUTF8
[0] = (char)'\0';
807 CssmData
service(const_cast<char *>(serviceUTF8
), strlen(serviceUTF8
));
809 // look for existing preference item, in case this is an update
810 StorageManager::KeychainList keychains
;
811 globals().storageManager
.getSearchList(keychains
);
812 KCCursor
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
);
813 FourCharCode itemType
= 'cprf';
814 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
);
815 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), itemType
);
817 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
);
821 Item
item(kSecGenericPasswordItemClass
, 'aapl', 0, NULL
, false);
822 bool add
= (!cursor
->next(item
));
823 // at this point, we either have a new item to add or an existing item to update
825 // set item attribute values
826 item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), service
);
827 item
->setAttribute(Schema::attributeInfo(kSecTypeItemAttr
), itemType
);
828 item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
);
829 item
->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
);
830 item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), service
);
836 // generic attribute (store persistent certificate reference)
837 CFDataRef pItemRef
= nil
;
838 Certificate::required(__itemImplRef
)->copyPersistentReference(pItemRef
);
840 MacOSError::throwMe(errSecInvalidItemRef
);
842 const UInt8
*dataPtr
= CFDataGetBytePtr(pItemRef
);
843 CFIndex dataLen
= CFDataGetLength(pItemRef
);
844 CssmData
pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr
)), dataLen
);
845 item
->setAttribute(Schema::attributeInfo(kSecGenericItemAttr
), pref
);
849 Keychain keychain
= nil
;
851 keychain
= globals().storageManager
.defaultKeychain();
852 if (!keychain
->exists())
853 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
856 keychain
= globals().storageManager
.defaultKeychainUI(item
);
862 catch (const MacOSError
&err
) {
863 if (err
.osStatus() != errSecDuplicateItem
)
864 throw; // if item already exists, fall through to update
872 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
873 OSStatus
SecCertificateSetPreferred(
874 SecCertificateRef certificate
,
878 CSSM_KEYUSE keyUse
= ConvertArrayToKeyUsage(keyUsage
);
879 return SecCertificateSetPreference(certificate
, name
, keyUse
, NULL
);
882 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
883 CFDictionaryRef
SecCertificateCopyValues(SecCertificateRef certificate
, CFArrayRef keys
, CFErrorRef
*error
)
885 CFDictionaryRef result
= NULL
;
886 OSStatus __secapiresult
;
887 SecCertificateRef tmpcert
= NULL
;
889 // convert input to a new-style certificate reference if necessary,
890 // since the implementation of CertificateValues calls SecCertificate API functions
891 // which now assume a unified certificate reference.
892 if (SecCertificateIsItemImplInstance(certificate
)) {
893 tmpcert
= SecCertificateCreateFromItemImplInstance(certificate
);
895 if (certificate
&& !tmpcert
) {
896 tmpcert
= (SecCertificateRef
) CFRetain(certificate
);
900 CertificateValues
cv(tmpcert
);
901 result
= cv
.copyFieldValues(keys
,error
);
904 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
905 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
906 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
907 catch (...) { __secapiresult
=errSecInternalComponent
; }
908 if (tmpcert
) { CFRelease(tmpcert
); }
912 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
913 CFStringRef
SecCertificateCopyLongDescription(CFAllocatorRef alloc
, SecCertificateRef certificate
, CFErrorRef
*error
)
915 return SecCertificateCopyShortDescription(alloc
, certificate
, error
);
918 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
919 CFStringRef
SecCertificateCopyShortDescription(CFAllocatorRef alloc
, SecCertificateRef certificate
, CFErrorRef
*error
)
921 CFStringRef result
= NULL
;
922 OSStatus __secapiresult
= SecCertificateInferLabel(certificate
, &result
);
923 if (error
!=NULL
&& __secapiresult
!=errSecSuccess
)
925 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
,
926 __secapiresult
? __secapiresult
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
931 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
932 CFDataRef
SecCertificateCopySerialNumber(SecCertificateRef certificate
, CFErrorRef
*error
)
934 CFDataRef result
= NULL
;
935 OSStatus __secapiresult
;
938 CertificateValues
cv(certificate
);
939 result
= cv
.copySerialNumber(error
);
942 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
943 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
944 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
945 catch (...) { __secapiresult
=errSecInternalComponent
; }
949 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA) */
950 CFDataRef
SecCertificateCopyNormalizedIssuerContent(SecCertificateRef certificate
, CFErrorRef
*error
)
952 CFDataRef result
= NULL
;
953 OSStatus __secapiresult
;
956 CertificateValues
cv(certificate
);
957 result
= cv
.copyNormalizedIssuerContent(error
);
960 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
961 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
962 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
963 catch (...) { __secapiresult
=errSecInternalComponent
; }
967 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA) */
968 CFDataRef
SecCertificateCopyNormalizedSubjectContent(SecCertificateRef certificate
, CFErrorRef
*error
)
970 CFDataRef result
= NULL
;
971 OSStatus __secapiresult
;
974 CertificateValues
cv(certificate
);
975 result
= cv
.copyNormalizedSubjectContent(error
);
978 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
979 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
980 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
981 catch (...) { __secapiresult
=errSecInternalComponent
; }
985 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA) */
986 bool SecCertificateIsValidX(SecCertificateRef certificate
, CFAbsoluteTime verifyTime
)
989 * deprecated function name
991 return SecCertificateIsValid(certificate
, verifyTime
);
995 CFDataRef
SecCertificateCopyPublicKeySHA1DigestFromCertificateData(CFAllocatorRef allocator
,
996 CFDataRef der_certificate
)
998 CFDataRef result
= NULL
;
999 SecCertificateRef iosCertRef
= SecCertificateCreateWithData(allocator
, der_certificate
);
1000 if (NULL
== iosCertRef
)
1005 result
= SecCertificateCopyPublicKeySHA1Digest(iosCertRef
);
1006 CFRelease(iosCertRef
);