]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
fa7225c8 | 2 | * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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 | |
11 | * file. | |
12 | * | |
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. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
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> | |
35 | ||
36 | #include "SecBridge.h" | |
37 | ||
38 | // %%% used by SecCertificate{Copy,Set}Preference | |
39 | #include <Security/SecKeychainItemPriv.h> | |
40 | #include <Security/SecIdentityPriv.h> | |
b04fe171 | 41 | #include <Security/SecItemPriv.h> |
b1ab9ed8 A |
42 | #include <security_keychain/KCCursor.h> |
43 | #include <security_cdsa_utilities/Schema.h> | |
5c19dc3a | 44 | #include <security_cdsa_utils/cuCdsaUtils.h> |
b1ab9ed8 | 45 | #include <sys/param.h> |
5c19dc3a | 46 | #include <syslog.h> |
b1ab9ed8 | 47 | #include "CertificateValues.h" |
427c49bc | 48 | |
d8f41ccd | 49 | #include "AppleBaselineEscrowCertificates.h" |
427c49bc | 50 | |
b1ab9ed8 | 51 | |
5c19dc3a | 52 | OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle); |
b1ab9ed8 A |
53 | extern CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage); |
54 | ||
5c19dc3a | 55 | #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); |
427c49bc A |
56 | |
57 | SEC_CONST_DECL (kSecCertificateProductionEscrowKey, "ProductionEscrowKey"); | |
d8f41ccd | 58 | SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey, "ProductionPCSEscrowKey"); |
427c49bc A |
59 | SEC_CONST_DECL (kSecCertificateEscrowFileName, "AppleESCertificates"); |
60 | ||
b1ab9ed8 A |
61 | |
62 | using namespace CssmClient; | |
63 | ||
6b200bc3 | 64 | CFTypeID static SecCertificateGetTypeID_osx(void) |
b1ab9ed8 A |
65 | { |
66 | BEGIN_SECAPI | |
67 | ||
68 | return gTypes().Certificate.typeID; | |
69 | ||
70 | END_SECAPI1(_kCFRuntimeNotATypeID) | |
71 | } | |
fa7225c8 A |
72 | |
73 | Boolean | |
74 | SecCertificateIsItemImplInstance(SecCertificateRef certificate) | |
75 | { | |
76 | if (certificate == NULL) { | |
77 | return false; | |
78 | } | |
6b200bc3 | 79 | |
fa7225c8 A |
80 | CFTypeID typeID = CFGetTypeID(certificate); |
81 | ||
82 | #if 0 /* debug code to verify type IDs */ | |
83 | syslog(LOG_ERR, "SecCertificate typeID=%d [STU=%d, OSX=%d, SKI=%d]", | |
84 | (int)typeID, | |
85 | (int)SecCertificateGetTypeID(), | |
86 | (int)SecCertificateGetTypeID_osx(), | |
87 | (int)SecKeychainItemGetTypeID()); | |
5c19dc3a | 88 | #endif |
fa7225c8 A |
89 | if (typeID == _kCFRuntimeNotATypeID) { |
90 | return false; | |
91 | } | |
92 | ||
93 | return (typeID == SecCertificateGetTypeID_osx() || | |
94 | typeID == SecKeychainItemGetTypeID()) ? true : false; | |
fa7225c8 | 95 | } |
b1ab9ed8 | 96 | |
5c19dc3a A |
97 | /* convert a new-world SecCertificateRef to an old-world ItemImpl instance */ |
98 | SecCertificateRef | |
99 | SecCertificateCreateItemImplInstance(SecCertificateRef certificate) | |
100 | { | |
5c19dc3a A |
101 | if (!certificate) { |
102 | return NULL; | |
103 | } | |
104 | SecCertificateRef implCertRef = (SecCertificateRef) SecCertificateCopyKeychainItem(certificate); | |
105 | if (implCertRef) { | |
106 | return implCertRef; | |
107 | } | |
108 | CFDataRef data = SecCertificateCopyData(certificate); | |
109 | if (!data) { | |
110 | return NULL; | |
111 | } | |
112 | try { | |
113 | CSSM_DATA cssmCertData; | |
114 | cssmCertData.Length = (data) ? (CSSM_SIZE)CFDataGetLength(data) : 0; | |
115 | cssmCertData.Data = (data) ? (uint8 *)CFDataGetBytePtr(data) : NULL; | |
b1ab9ed8 | 116 | |
5c19dc3a A |
117 | SecPointer<Certificate> certificatePtr(new Certificate(cssmCertData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER)); |
118 | implCertRef = certificatePtr->handle(); | |
119 | } | |
120 | catch (...) {} | |
121 | CFRelease(data); | |
122 | return implCertRef; | |
5c19dc3a A |
123 | } |
124 | ||
125 | /* convert an old-world ItemImpl instance to a new-world SecCertificateRef */ | |
126 | SecCertificateRef | |
127 | SecCertificateCreateFromItemImplInstance(SecCertificateRef certificate) | |
128 | { | |
5c19dc3a A |
129 | if (!certificate) { |
130 | return NULL; | |
131 | } | |
132 | SecCertificateRef result = NULL; | |
133 | CFDataRef data = NULL; | |
134 | try { | |
135 | CssmData certData = Certificate::required(certificate)->data(); | |
136 | if (certData.Data && certData.Length) { | |
137 | data = CFDataCreate(NULL, certData.Data, certData.Length); | |
138 | } | |
139 | if (!data) { | |
140 | if (certData.Data && !certData.Length) { | |
141 | /* zero-length certs can exist, so don't bother logging this */ | |
142 | } | |
143 | else { | |
144 | syslog(LOG_ERR, "WARNING: SecKeychainSearchCopyNext failed to retrieve certificate data (length=%ld, data=0x%lX)", | |
145 | (long)certData.Length, (uintptr_t)certData.Data); | |
146 | } | |
147 | return NULL; | |
148 | } | |
149 | } | |
150 | catch (...) {} | |
151 | ||
152 | result = SecCertificateCreateWithKeychainItem(NULL, data, certificate); | |
153 | if (data) | |
154 | CFRelease(data); | |
155 | return result; | |
5c19dc3a A |
156 | } |
157 | ||
fa7225c8 | 158 | |
5c19dc3a | 159 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
160 | OSStatus |
161 | SecCertificateCreateFromData(const CSSM_DATA *data, CSSM_CERT_TYPE type, CSSM_CERT_ENCODING encoding, SecCertificateRef *certificate) | |
162 | { | |
5c19dc3a A |
163 | /* bridge to support old functionality */ |
164 | if (!data || !data->Data || !data->Length || !certificate) { | |
165 | return errSecParam; | |
166 | } | |
167 | SecCertificateRef certRef = NULL; | |
fa7225c8 A |
168 | |
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. | |
173 | // | |
174 | // Assume that there will not exist a certificate > 4GiB, and fake this length field. | |
175 | CSSM_SIZE length = data->Length & 0xfffffffful; | |
176 | ||
177 | CFDataRef dataRef = CFDataCreate(NULL, data->Data, length); | |
5c19dc3a A |
178 | if (dataRef) { |
179 | certRef = SecCertificateCreateWithData(NULL, dataRef); | |
180 | CFRelease(dataRef); | |
181 | } | |
182 | *certificate = certRef; | |
183 | return (certRef) ? errSecSuccess : errSecUnknownFormat; | |
b1ab9ed8 A |
184 | } |
185 | ||
5c19dc3a | 186 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */ |
b1ab9ed8 A |
187 | OSStatus |
188 | SecCertificateAddToKeychain(SecCertificateRef certificate, SecKeychainRef keychain) | |
189 | { | |
fa7225c8 | 190 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 191 | BEGIN_SECCERTAPI |
b1ab9ed8 | 192 | |
5c19dc3a | 193 | Item item(Certificate::required(__itemImplRef)); |
b1ab9ed8 A |
194 | Keychain::optional(keychain)->add(item); |
195 | ||
5c19dc3a | 196 | END_SECCERTAPI |
b1ab9ed8 A |
197 | } |
198 | ||
5c19dc3a | 199 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
200 | OSStatus |
201 | SecCertificateGetData(SecCertificateRef certificate, CSSM_DATA_PTR data) | |
202 | { | |
5c19dc3a | 203 | BEGIN_SECCERTAPI |
b1ab9ed8 | 204 | |
fa7225c8 A |
205 | if (!certificate || !data) { |
206 | __secapiresult=errSecParam; | |
207 | } | |
208 | else if (SecCertificateIsItemImplInstance(certificate)) { | |
209 | Required(data) = Certificate::required(certificate)->data(); | |
210 | } | |
211 | else { | |
212 | data->Length = (CSSM_SIZE)SecCertificateGetLength(certificate); | |
213 | data->Data = (uint8*)SecCertificateGetBytePtr(certificate); | |
214 | } | |
b1ab9ed8 | 215 | |
5c19dc3a | 216 | END_SECCERTAPI |
e3d460c9 | 217 | } |
427c49bc | 218 | |
5c19dc3a | 219 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
220 | OSStatus |
221 | SecCertificateGetType(SecCertificateRef certificate, CSSM_CERT_TYPE *certificateType) | |
222 | { | |
fa7225c8 | 223 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 224 | BEGIN_SECCERTAPI |
b1ab9ed8 | 225 | |
5c19dc3a | 226 | Required(certificateType) = Certificate::required(__itemImplRef)->type(); |
b1ab9ed8 | 227 | |
5c19dc3a | 228 | END_SECCERTAPI |
b1ab9ed8 A |
229 | } |
230 | ||
5c19dc3a | 231 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
232 | OSStatus |
233 | SecCertificateGetSubject(SecCertificateRef certificate, const CSSM_X509_NAME **subject) | |
234 | { | |
fa7225c8 | 235 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 236 | BEGIN_SECCERTAPI |
b1ab9ed8 | 237 | |
5c19dc3a | 238 | Required(subject) = Certificate::required(__itemImplRef)->subjectName(); |
b1ab9ed8 | 239 | |
5c19dc3a | 240 | END_SECCERTAPI |
b1ab9ed8 A |
241 | } |
242 | ||
5c19dc3a | 243 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
244 | OSStatus |
245 | SecCertificateGetIssuer(SecCertificateRef certificate, const CSSM_X509_NAME **issuer) | |
246 | { | |
fa7225c8 | 247 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a A |
248 | BEGIN_SECCERTAPI |
249 | ||
250 | Required(issuer) = Certificate::required(__itemImplRef)->issuerName(); | |
251 | ||
252 | END_SECCERTAPI | |
253 | } | |
254 | ||
255 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ | |
256 | OSStatus | |
257 | SecCertificateGetCLHandle(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) | |
258 | { | |
fa7225c8 | 259 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a A |
260 | BEGIN_SECCERTAPI |
261 | ||
262 | Required(clHandle) = Certificate::required(__itemImplRef)->clHandle(); | |
263 | ||
264 | END_SECCERTAPI | |
5c19dc3a | 265 | } |
b1ab9ed8 | 266 | |
5c19dc3a A |
267 | /* private function; assumes input is old-style ItemImpl certificate reference, |
268 | and does not release that certificate reference! | |
269 | */ | |
b1ab9ed8 | 270 | OSStatus |
5c19dc3a | 271 | SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) |
b1ab9ed8 A |
272 | { |
273 | BEGIN_SECAPI | |
274 | ||
5c19dc3a | 275 | Required(clHandle) = Certificate::required(certificate)->clHandle(); |
b1ab9ed8 A |
276 | |
277 | END_SECAPI | |
278 | } | |
279 | ||
280 | /* | |
281 | * Private API to infer a display name for a SecCertificateRef which | |
282 | * may or may not be in a keychain. | |
5c19dc3a A |
283 | * |
284 | * OS X only | |
b1ab9ed8 A |
285 | */ |
286 | OSStatus | |
287 | SecCertificateInferLabel(SecCertificateRef certificate, CFStringRef *label) | |
288 | { | |
fa7225c8 | 289 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 290 | BEGIN_SECCERTAPI |
b1ab9ed8 | 291 | |
5c19dc3a | 292 | Certificate::required(__itemImplRef)->inferLabel(false, &Required(label)); |
b1ab9ed8 | 293 | |
5c19dc3a | 294 | END_SECCERTAPI |
b1ab9ed8 A |
295 | } |
296 | ||
5c19dc3a | 297 | /* OS X only (note: iOS version has different arguments and return value) */ |
b1ab9ed8 A |
298 | OSStatus |
299 | SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef *key) | |
300 | { | |
fa7225c8 | 301 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 302 | BEGIN_SECCERTAPI |
b1ab9ed8 | 303 | |
5c19dc3a | 304 | Required(key) = Certificate::required(__itemImplRef)->publicKey()->handle(); |
b1ab9ed8 | 305 | |
5c19dc3a | 306 | END_SECCERTAPI |
b1ab9ed8 A |
307 | } |
308 | ||
5c19dc3a | 309 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
310 | OSStatus |
311 | SecCertificateGetAlgorithmID(SecCertificateRef certificate, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) | |
312 | { | |
fa7225c8 | 313 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 314 | BEGIN_SECCERTAPI |
b1ab9ed8 | 315 | |
5c19dc3a | 316 | Required(algid) = Certificate::required(__itemImplRef)->algorithmID(); |
b1ab9ed8 | 317 | |
5c19dc3a | 318 | END_SECCERTAPI |
b1ab9ed8 A |
319 | } |
320 | ||
5c19dc3a | 321 | /* OS X only */ |
b1ab9ed8 A |
322 | OSStatus |
323 | SecCertificateCopySubjectComponent(SecCertificateRef certificate, const CSSM_OID *component, CFStringRef *result) | |
324 | { | |
fa7225c8 | 325 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 326 | BEGIN_SECCERTAPI |
b1ab9ed8 | 327 | |
5c19dc3a | 328 | Required(result) = Certificate::required(__itemImplRef)->distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, component); |
b1ab9ed8 | 329 | |
5c19dc3a | 330 | END_SECCERTAPI |
b1ab9ed8 A |
331 | } |
332 | ||
5c19dc3a | 333 | /* OS X only; deprecated SPI */ |
b1ab9ed8 A |
334 | OSStatus |
335 | SecCertificateGetCommonName(SecCertificateRef certificate, CFStringRef *commonName) | |
336 | { | |
337 | // deprecated SPI signature; replaced by SecCertificateCopyCommonName | |
338 | return SecCertificateCopyCommonName(certificate, commonName); | |
339 | } | |
340 | ||
5c19dc3a | 341 | /* OS X only; deprecated SPI */ |
b1ab9ed8 A |
342 | OSStatus |
343 | SecCertificateGetEmailAddress(SecCertificateRef certificate, CFStringRef *emailAddress) | |
344 | { | |
fa7225c8 | 345 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 346 | BEGIN_SECCERTAPI |
b1ab9ed8 | 347 | |
5c19dc3a | 348 | Required(emailAddress) = Certificate::required(__itemImplRef)->copyFirstEmailAddress(); |
b1ab9ed8 | 349 | |
5c19dc3a | 350 | END_SECCERTAPI |
b1ab9ed8 A |
351 | } |
352 | ||
5c19dc3a A |
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. | |
355 | * | |
356 | * OS X only | |
357 | */ | |
b1ab9ed8 A |
358 | OSStatus |
359 | SecCertificateCopyFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR **fieldValues) | |
360 | { | |
fa7225c8 | 361 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 362 | BEGIN_SECCERTAPI |
b1ab9ed8 | 363 | |
5c19dc3a | 364 | Required(fieldValues) = Certificate::required(__itemImplRef)->copyFieldValues(Required(field)); |
b1ab9ed8 | 365 | |
5c19dc3a | 366 | END_SECCERTAPI |
b1ab9ed8 A |
367 | } |
368 | ||
5c19dc3a | 369 | /* OS X only */ |
b1ab9ed8 A |
370 | OSStatus |
371 | SecCertificateReleaseFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValues) | |
372 | { | |
fa7225c8 | 373 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 374 | BEGIN_SECCERTAPI |
b1ab9ed8 | 375 | |
5c19dc3a | 376 | Certificate::required(__itemImplRef)->releaseFieldValues(Required(field), fieldValues); |
b1ab9ed8 | 377 | |
5c19dc3a | 378 | END_SECCERTAPI |
b1ab9ed8 A |
379 | } |
380 | ||
5c19dc3a | 381 | /* OS X only */ |
b1ab9ed8 A |
382 | OSStatus |
383 | SecCertificateCopyFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValue) | |
384 | { | |
fa7225c8 | 385 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 386 | BEGIN_SECCERTAPI |
b1ab9ed8 | 387 | |
5c19dc3a | 388 | Required(fieldValue) = Certificate::required(__itemImplRef)->copyFirstFieldValue(Required(field)); |
b1ab9ed8 | 389 | |
5c19dc3a | 390 | END_SECCERTAPI |
b1ab9ed8 A |
391 | } |
392 | ||
5c19dc3a | 393 | /* OS X only */ |
b1ab9ed8 A |
394 | OSStatus |
395 | SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR fieldValue) | |
396 | { | |
fa7225c8 | 397 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 398 | BEGIN_SECCERTAPI |
b1ab9ed8 | 399 | |
5c19dc3a | 400 | Certificate::required(__itemImplRef)->releaseFieldValue(Required(field), fieldValue); |
b1ab9ed8 | 401 | |
5c19dc3a | 402 | END_SECCERTAPI |
b1ab9ed8 A |
403 | } |
404 | ||
5c19dc3a | 405 | /* OS X only */ |
b1ab9ed8 A |
406 | OSStatus |
407 | SecCertificateFindByIssuerAndSN(CFTypeRef keychainOrArray,const CSSM_DATA *issuer, | |
408 | const CSSM_DATA *serialNumber, SecCertificateRef *certificate) | |
409 | { | |
b04fe171 A |
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); | |
415 | ||
416 | CFRef<CFDataRef> issuerData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)issuer->Data, issuer->Length, kCFAllocatorNull); | |
417 | CFDictionarySetValue(query, kSecAttrIssuer, issuerData); | |
418 | ||
419 | CFRef<CFDataRef> serialNumberData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)serialNumber->Data, serialNumber->Length, kCFAllocatorNull); | |
420 | CFDictionarySetValue(query, kSecAttrSerialNumber, serialNumberData); | |
421 | ||
422 | OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)certificate); | |
423 | if (status == errSecSuccess) { | |
424 | return status; | |
425 | } | |
426 | } | |
427 | ||
b1ab9ed8 A |
428 | BEGIN_SECAPI |
429 | ||
430 | StorageManager::KeychainList keychains; | |
431 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
432 | Required(certificate) = Certificate::findByIssuerAndSN(keychains, CssmData::required(issuer), CssmData::required(serialNumber))->handle(); | |
433 | ||
5c19dc3a A |
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); | |
439 | CFRelease(tmpRef); | |
5c19dc3a | 440 | |
b1ab9ed8 A |
441 | END_SECAPI |
442 | } | |
443 | ||
5c19dc3a | 444 | /* OS X only */ |
b1ab9ed8 A |
445 | OSStatus |
446 | SecCertificateFindBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, | |
447 | SecCertificateRef *certificate) | |
448 | { | |
b04fe171 A |
449 | if (subjectKeyID) { |
450 | CFRef<CFMutableDictionaryRef> query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
451 | CFDictionarySetValue(query, kSecClass, kSecClassCertificate); | |
452 | CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); | |
453 | CFDictionarySetValue(query, kSecAttrNoLegacy, kCFBooleanTrue); | |
454 | ||
455 | CFRef<CFDataRef> subjectKeyIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)subjectKeyID->Data, subjectKeyID->Length, kCFAllocatorNull); | |
456 | CFDictionarySetValue(query, kSecAttrSubjectKeyID, subjectKeyIDData); | |
457 | ||
458 | OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)certificate); | |
459 | if (status == errSecSuccess) { | |
460 | return status; | |
461 | } | |
462 | } | |
463 | ||
464 | BEGIN_SECAPI | |
b1ab9ed8 A |
465 | |
466 | StorageManager::KeychainList keychains; | |
467 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
468 | Required(certificate) = Certificate::findBySubjectKeyID(keychains, CssmData::required(subjectKeyID))->handle(); | |
469 | ||
5c19dc3a A |
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); | |
475 | CFRelease(tmpRef); | |
5c19dc3a | 476 | |
b1ab9ed8 A |
477 | END_SECAPI |
478 | } | |
479 | ||
5c19dc3a | 480 | /* OS X only */ |
b1ab9ed8 A |
481 | OSStatus |
482 | SecCertificateFindByEmail(CFTypeRef keychainOrArray, const char *emailAddress, SecCertificateRef *certificate) | |
483 | { | |
b04fe171 A |
484 | if (emailAddress) { |
485 | CFRef<CFMutableDictionaryRef> query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
486 | CFDictionarySetValue(query, kSecClass, kSecClassCertificate); | |
487 | CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); | |
488 | CFDictionarySetValue(query, kSecAttrNoLegacy, kCFBooleanTrue); | |
489 | ||
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); | |
496 | ||
497 | OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)certificate); | |
498 | if (status == errSecSuccess) { | |
499 | return status; | |
500 | } | |
501 | } | |
502 | ||
503 | BEGIN_SECAPI | |
b1ab9ed8 A |
504 | |
505 | StorageManager::KeychainList keychains; | |
506 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
507 | Required(certificate) = Certificate::findByEmail(keychains, emailAddress)->handle(); | |
508 | ||
5c19dc3a A |
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); | |
514 | CFRelease(tmpRef); | |
5c19dc3a | 515 | |
b1ab9ed8 A |
516 | END_SECAPI |
517 | } | |
518 | ||
5c19dc3a | 519 | /* OS X only */ |
b1ab9ed8 A |
520 | OSStatus |
521 | SecKeychainSearchCreateForCertificateByIssuerAndSN(CFTypeRef keychainOrArray, const CSSM_DATA *issuer, | |
522 | const CSSM_DATA *serialNumber, SecKeychainSearchRef *searchRef) | |
523 | { | |
524 | BEGIN_SECAPI | |
525 | ||
526 | Required(searchRef); | |
527 | ||
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(); | |
532 | ||
533 | END_SECAPI | |
534 | } | |
535 | ||
5c19dc3a | 536 | /* OS X only */ |
b1ab9ed8 A |
537 | OSStatus |
538 | SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(CFTypeRef keychainOrArray, CFDataRef issuer, | |
539 | CFDataRef serialNumber, SecKeychainSearchRef *searchRef) | |
540 | { | |
541 | BEGIN_SECAPI | |
542 | ||
543 | Required(searchRef); | |
544 | ||
545 | StorageManager::KeychainList keychains; | |
546 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
547 | Required(issuer); | |
548 | Required(serialNumber); | |
549 | KCCursor cursor(Certificate::cursorForIssuerAndSN_CF(keychains, issuer, serialNumber)); | |
550 | *searchRef = cursor->handle(); | |
551 | ||
552 | END_SECAPI | |
553 | } | |
554 | ||
5c19dc3a | 555 | /* OS X only */ |
b1ab9ed8 A |
556 | OSStatus |
557 | SecKeychainSearchCreateForCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, | |
558 | SecKeychainSearchRef *searchRef) | |
559 | { | |
560 | BEGIN_SECAPI | |
561 | ||
562 | Required(searchRef); | |
563 | ||
564 | StorageManager::KeychainList keychains; | |
565 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
566 | KCCursor cursor(Certificate::cursorForSubjectKeyID(keychains, CssmData::required(subjectKeyID))); | |
567 | *searchRef = cursor->handle(); | |
568 | ||
569 | END_SECAPI | |
570 | } | |
571 | ||
5c19dc3a | 572 | /* OS X only */ |
b1ab9ed8 A |
573 | OSStatus |
574 | SecKeychainSearchCreateForCertificateByEmail(CFTypeRef keychainOrArray, const char *emailAddress, | |
575 | SecKeychainSearchRef *searchRef) | |
576 | { | |
577 | BEGIN_SECAPI | |
578 | ||
579 | Required(searchRef); | |
580 | ||
581 | StorageManager::KeychainList keychains; | |
582 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
583 | KCCursor cursor(Certificate::cursorForEmail(keychains, emailAddress)); | |
584 | *searchRef = cursor->handle(); | |
585 | ||
586 | END_SECAPI | |
587 | } | |
588 | ||
5c19dc3a | 589 | /* OS X only */ |
b1ab9ed8 A |
590 | CSSM_RETURN |
591 | SecDigestGetData (CSSM_ALGORITHMS alg, CSSM_DATA* digest, const CSSM_DATA* data) | |
592 | { | |
593 | BEGIN_SECAPI | |
594 | // sanity checking | |
595 | if (!digest || !digest->Data || !digest->Length || !data || !data->Data || !data->Length) | |
427c49bc | 596 | return errSecParam; |
b1ab9ed8 A |
597 | |
598 | CSP csp(gGuidAppleCSP); | |
599 | Digest context(csp, alg); | |
600 | CssmData input(data->Data, data->Length); | |
601 | CssmData output(digest->Data, digest->Length); | |
602 | ||
603 | context.digest(input, output); | |
604 | digest->Length = output.length(); | |
605 | ||
606 | return CSSM_OK; | |
607 | END_SECAPI1(1); | |
608 | } | |
609 | ||
5c19dc3a | 610 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
611 | OSStatus |
612 | SecCertificateCopyPreference( | |
613 | CFStringRef name, | |
614 | CSSM_KEYUSE keyUsage, | |
615 | SecCertificateRef *certificate) | |
616 | { | |
617 | BEGIN_SECAPI | |
618 | ||
619 | Required(name); | |
620 | Required(certificate); | |
621 | StorageManager::KeychainList keychains; | |
622 | globals().storageManager.getSearchList(keychains); | |
623 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
624 | ||
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); | |
632 | if (keyUsage) | |
633 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); | |
634 | ||
635 | Item prefItem; | |
636 | if (!cursor->next(prefItem)) | |
637 | MacOSError::throwMe(errSecItemNotFound); | |
638 | ||
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); | |
643 | ||
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); | |
649 | if (pItemRef) | |
650 | CFRelease(pItemRef); | |
651 | if (status) | |
652 | return status; | |
653 | ||
654 | *certificate = (SecCertificateRef)certItemRef; | |
655 | ||
fa7225c8 A |
656 | if (certItemRef && (CFGetTypeID(certItemRef) == SecIdentityGetTypeID())) { |
657 | // SecKeychainItemCopyFromPersistentReference handed out an identity reference | |
658 | *certificate = NULL; | |
659 | status = SecIdentityCopyCertificate((SecIdentityRef)certItemRef, certificate); | |
660 | CFRelease(certItemRef); | |
661 | return status; | |
662 | } | |
5c19dc3a | 663 | |
b1ab9ed8 A |
664 | END_SECAPI |
665 | } | |
666 | ||
5c19dc3a | 667 | /* OS X only */ |
b1ab9ed8 A |
668 | SecCertificateRef |
669 | SecCertificateCopyPreferred( | |
670 | CFStringRef name, | |
671 | CFArrayRef keyUsage) | |
672 | { | |
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 | |
677 | ||
678 | SecCertificateRef certRef = NULL; | |
679 | CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage); | |
680 | OSStatus status = SecCertificateCopyPreference(name, keyUse, &certRef); | |
427c49bc | 681 | if (status != errSecSuccess && keyUse != CSSM_KEYUSE_ANY) |
b1ab9ed8 | 682 | status = SecCertificateCopyPreference(name, CSSM_KEYUSE_ANY, &certRef); |
427c49bc | 683 | if (status != errSecSuccess && keyUse != 0) |
b1ab9ed8 A |
684 | status = SecCertificateCopyPreference(name, 0, &certRef); |
685 | ||
686 | return certRef; | |
687 | } | |
688 | ||
5c19dc3a | 689 | /* OS X only; not exported */ |
427c49bc | 690 | static OSStatus |
b1ab9ed8 A |
691 | SecCertificateFindPreferenceItemWithNameAndKeyUsage( |
692 | CFTypeRef keychainOrArray, | |
693 | CFStringRef name, | |
694 | int32_t keyUsage, | |
695 | SecKeychainItemRef *itemRef) | |
696 | { | |
697 | BEGIN_SECAPI | |
698 | ||
699 | StorageManager::KeychainList keychains; | |
700 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
701 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
702 | ||
703 | char idUTF8[MAXPATHLEN]; | |
704 | idUTF8[0] = (char)'\0'; | |
705 | if (name) | |
706 | { | |
707 | if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8)) | |
708 | idUTF8[0] = (char)'\0'; | |
709 | } | |
710 | size_t idUTF8Len = strlen(idUTF8); | |
711 | if (!idUTF8Len) | |
427c49bc | 712 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
713 | |
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'); | |
717 | if (keyUsage) | |
718 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); | |
719 | ||
720 | Item item; | |
721 | if (!cursor->next(item)) | |
722 | MacOSError::throwMe(errSecItemNotFound); | |
723 | ||
724 | if (itemRef) | |
725 | *itemRef=item->handle(); | |
726 | ||
727 | END_SECAPI | |
728 | } | |
729 | ||
5c19dc3a | 730 | /* OS X only; not exported */ |
427c49bc | 731 | static |
b1ab9ed8 A |
732 | OSStatus SecCertificateDeletePreferenceItemWithNameAndKeyUsage( |
733 | CFTypeRef keychainOrArray, | |
734 | CFStringRef name, | |
735 | int32_t keyUsage) | |
736 | { | |
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.) | |
742 | ||
6b200bc3 | 743 | OSStatus status = errSecSuccess; |
b1ab9ed8 A |
744 | SecKeychainItemRef item = NULL; |
745 | int count = 0, maxUsages = 12; | |
746 | while (++count <= maxUsages && | |
427c49bc | 747 | (status = SecCertificateFindPreferenceItemWithNameAndKeyUsage(keychainOrArray, name, keyUsage, &item)) == errSecSuccess) { |
b1ab9ed8 A |
748 | status = SecKeychainItemDelete(item); |
749 | CFRelease(item); | |
750 | item = NULL; | |
751 | } | |
752 | ||
753 | // it's not an error if the item isn't found | |
427c49bc | 754 | return (status == errSecItemNotFound) ? errSecSuccess : status; |
b1ab9ed8 A |
755 | } |
756 | ||
5c19dc3a | 757 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */ |
b1ab9ed8 A |
758 | OSStatus SecCertificateSetPreference( |
759 | SecCertificateRef certificate, | |
760 | CFStringRef name, | |
761 | CSSM_KEYUSE keyUsage, | |
762 | CFDateRef date) | |
763 | { | |
764 | if (!name) { | |
427c49bc | 765 | return errSecParam; |
b1ab9ed8 A |
766 | } |
767 | if (!certificate) { | |
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); | |
771 | } | |
772 | ||
fa7225c8 | 773 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 774 | BEGIN_SECCERTAPI |
b1ab9ed8 A |
775 | |
776 | // determine the account attribute | |
777 | // | |
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. | |
784 | // | |
785 | CFStringRef labelStr = nil; | |
5c19dc3a | 786 | Certificate::required(__itemImplRef)->inferLabel(false, &labelStr); |
b1ab9ed8 A |
787 | if (!labelStr) { |
788 | MacOSError::throwMe(errSecDataTooLarge); // data is "in a format which cannot be displayed" | |
789 | } | |
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'; | |
797 | if (keyUsage) | |
798 | snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage); | |
799 | CssmData account(const_cast<char *>(accountUTF8), strlen(accountUTF8)); | |
800 | CFRelease(labelStr); | |
801 | ||
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)); | |
808 | ||
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); | |
816 | if (keyUsage) | |
817 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); | |
818 | if (date) | |
819 | ; // %%%TBI | |
820 | ||
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 | |
824 | ||
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); | |
831 | ||
832 | // date | |
833 | if (date) | |
834 | ; // %%%TBI | |
835 | ||
836 | // generic attribute (store persistent certificate reference) | |
837 | CFDataRef pItemRef = nil; | |
5c19dc3a | 838 | Certificate::required(__itemImplRef)->copyPersistentReference(pItemRef); |
b1ab9ed8 A |
839 | if (!pItemRef) { |
840 | MacOSError::throwMe(errSecInvalidItemRef); | |
841 | } | |
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); | |
846 | CFRelease(pItemRef); | |
847 | ||
848 | if (add) { | |
849 | Keychain keychain = nil; | |
850 | try { | |
851 | keychain = globals().storageManager.defaultKeychain(); | |
852 | if (!keychain->exists()) | |
853 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
854 | } | |
855 | catch(...) { | |
856 | keychain = globals().storageManager.defaultKeychainUI(item); | |
857 | } | |
858 | ||
859 | try { | |
860 | keychain->add(item); | |
861 | } | |
862 | catch (const MacOSError &err) { | |
863 | if (err.osStatus() != errSecDuplicateItem) | |
864 | throw; // if item already exists, fall through to update | |
865 | } | |
866 | } | |
867 | item->update(); | |
868 | ||
5c19dc3a | 869 | END_SECCERTAPI |
b1ab9ed8 A |
870 | } |
871 | ||
5c19dc3a | 872 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
873 | OSStatus SecCertificateSetPreferred( |
874 | SecCertificateRef certificate, | |
875 | CFStringRef name, | |
876 | CFArrayRef keyUsage) | |
877 | { | |
878 | CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage); | |
879 | return SecCertificateSetPreference(certificate, name, keyUse, NULL); | |
880 | } | |
881 | ||
5c19dc3a | 882 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
883 | CFDictionaryRef SecCertificateCopyValues(SecCertificateRef certificate, CFArrayRef keys, CFErrorRef *error) |
884 | { | |
885 | CFDictionaryRef result = NULL; | |
427c49bc | 886 | OSStatus __secapiresult; |
fa7225c8 | 887 | SecCertificateRef tmpcert = NULL; |
6b200bc3 | 888 | |
fa7225c8 A |
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); | |
894 | } | |
fa7225c8 A |
895 | if (certificate && !tmpcert) { |
896 | tmpcert = (SecCertificateRef) CFRetain(certificate); | |
897 | } | |
b1ab9ed8 A |
898 | try |
899 | { | |
fa7225c8 | 900 | CertificateValues cv(tmpcert); |
b1ab9ed8 A |
901 | result = cv.copyFieldValues(keys,error); |
902 | __secapiresult=0; | |
903 | } | |
904 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
905 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
906 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
907 | catch (...) { __secapiresult=errSecInternalComponent; } | |
fa7225c8 | 908 | if (tmpcert) { CFRelease(tmpcert); } |
427c49bc | 909 | return result; |
b1ab9ed8 A |
910 | } |
911 | ||
5c19dc3a | 912 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
913 | CFStringRef SecCertificateCopyLongDescription(CFAllocatorRef alloc, SecCertificateRef certificate, CFErrorRef *error) |
914 | { | |
915 | return SecCertificateCopyShortDescription(alloc, certificate, error); | |
916 | } | |
917 | ||
5c19dc3a | 918 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
919 | CFStringRef SecCertificateCopyShortDescription(CFAllocatorRef alloc, SecCertificateRef certificate, CFErrorRef *error) |
920 | { | |
921 | CFStringRef result = NULL; | |
5c19dc3a | 922 | OSStatus __secapiresult = SecCertificateInferLabel(certificate, &result); |
427c49bc | 923 | if (error!=NULL && __secapiresult!=errSecSuccess) |
b1ab9ed8 A |
924 | { |
925 | *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, | |
926 | __secapiresult ? __secapiresult : CSSM_ERRCODE_INTERNAL_ERROR, NULL); | |
927 | } | |
427c49bc | 928 | return result; |
b1ab9ed8 A |
929 | } |
930 | ||
5c19dc3a | 931 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
932 | CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate, CFErrorRef *error) |
933 | { | |
934 | CFDataRef result = NULL; | |
427c49bc | 935 | OSStatus __secapiresult; |
b1ab9ed8 A |
936 | try |
937 | { | |
938 | CertificateValues cv(certificate); | |
939 | result = cv.copySerialNumber(error); | |
940 | __secapiresult=0; | |
941 | } | |
942 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
943 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
944 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
945 | catch (...) { __secapiresult=errSecInternalComponent; } | |
946 | return result; | |
b1ab9ed8 A |
947 | } |
948 | ||
6b200bc3 | 949 | /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA) */ |
b1ab9ed8 A |
950 | CFDataRef SecCertificateCopyNormalizedIssuerContent(SecCertificateRef certificate, CFErrorRef *error) |
951 | { | |
952 | CFDataRef result = NULL; | |
427c49bc | 953 | OSStatus __secapiresult; |
b1ab9ed8 A |
954 | try |
955 | { | |
956 | CertificateValues cv(certificate); | |
427c49bc | 957 | result = cv.copyNormalizedIssuerContent(error); |
b1ab9ed8 A |
958 | __secapiresult=0; |
959 | } | |
960 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
961 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
962 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
963 | catch (...) { __secapiresult=errSecInternalComponent; } | |
964 | return result; | |
b1ab9ed8 A |
965 | } |
966 | ||
6b200bc3 | 967 | /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA) */ |
b1ab9ed8 A |
968 | CFDataRef SecCertificateCopyNormalizedSubjectContent(SecCertificateRef certificate, CFErrorRef *error) |
969 | { | |
970 | CFDataRef result = NULL; | |
427c49bc | 971 | OSStatus __secapiresult; |
b1ab9ed8 A |
972 | try |
973 | { | |
974 | CertificateValues cv(certificate); | |
427c49bc | 975 | result = cv.copyNormalizedSubjectContent(error); |
b1ab9ed8 A |
976 | __secapiresult=0; |
977 | } | |
978 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
979 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
980 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
981 | catch (...) { __secapiresult=errSecInternalComponent; } | |
982 | return result; | |
b1ab9ed8 A |
983 | } |
984 | ||
5c19dc3a | 985 | /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA) */ |
427c49bc A |
986 | bool SecCertificateIsValidX(SecCertificateRef certificate, CFAbsoluteTime verifyTime) |
987 | { | |
5c19dc3a A |
988 | /* |
989 | * deprecated function name | |
990 | */ | |
427c49bc A |
991 | return SecCertificateIsValid(certificate, verifyTime); |
992 | } | |
8a50f688 A |
993 | |
994 | /* OS X only */ | |
995 | CFDataRef SecCertificateCopyPublicKeySHA1DigestFromCertificateData(CFAllocatorRef allocator, | |
996 | CFDataRef der_certificate) | |
997 | { | |
998 | CFDataRef result = NULL; | |
999 | SecCertificateRef iosCertRef = SecCertificateCreateWithData(allocator, der_certificate); | |
1000 | if (NULL == iosCertRef) | |
1001 | { | |
1002 | return result; | |
1003 | } | |
1004 | ||
1005 | result = SecCertificateCopyPublicKeySHA1Digest(iosCertRef); | |
1006 | CFRelease(iosCertRef); | |
1007 | return result; | |
1008 | } | |
1009 |