]>
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 | |
5c19dc3a | 49 | OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle); |
b1ab9ed8 A |
50 | extern CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage); |
51 | ||
427c49bc | 52 | |
427c49bc | 53 | |
b1ab9ed8 A |
54 | |
55 | using namespace CssmClient; | |
56 | ||
6b200bc3 | 57 | CFTypeID static SecCertificateGetTypeID_osx(void) |
b1ab9ed8 A |
58 | { |
59 | BEGIN_SECAPI | |
60 | ||
61 | return gTypes().Certificate.typeID; | |
62 | ||
63 | END_SECAPI1(_kCFRuntimeNotATypeID) | |
64 | } | |
fa7225c8 A |
65 | |
66 | Boolean | |
67 | SecCertificateIsItemImplInstance(SecCertificateRef certificate) | |
68 | { | |
69 | if (certificate == NULL) { | |
70 | return false; | |
71 | } | |
6b200bc3 | 72 | |
fa7225c8 A |
73 | CFTypeID typeID = CFGetTypeID(certificate); |
74 | ||
75 | #if 0 /* debug code to verify type IDs */ | |
76 | syslog(LOG_ERR, "SecCertificate typeID=%d [STU=%d, OSX=%d, SKI=%d]", | |
77 | (int)typeID, | |
78 | (int)SecCertificateGetTypeID(), | |
79 | (int)SecCertificateGetTypeID_osx(), | |
80 | (int)SecKeychainItemGetTypeID()); | |
5c19dc3a | 81 | #endif |
fa7225c8 A |
82 | if (typeID == _kCFRuntimeNotATypeID) { |
83 | return false; | |
84 | } | |
85 | ||
86 | return (typeID == SecCertificateGetTypeID_osx() || | |
87 | typeID == SecKeychainItemGetTypeID()) ? true : false; | |
fa7225c8 | 88 | } |
b1ab9ed8 | 89 | |
5c19dc3a A |
90 | /* convert a new-world SecCertificateRef to an old-world ItemImpl instance */ |
91 | SecCertificateRef | |
92 | SecCertificateCreateItemImplInstance(SecCertificateRef certificate) | |
93 | { | |
5c19dc3a A |
94 | if (!certificate) { |
95 | return NULL; | |
96 | } | |
97 | SecCertificateRef implCertRef = (SecCertificateRef) SecCertificateCopyKeychainItem(certificate); | |
98 | if (implCertRef) { | |
99 | return implCertRef; | |
100 | } | |
101 | CFDataRef data = SecCertificateCopyData(certificate); | |
102 | if (!data) { | |
103 | return NULL; | |
104 | } | |
105 | try { | |
106 | CSSM_DATA cssmCertData; | |
107 | cssmCertData.Length = (data) ? (CSSM_SIZE)CFDataGetLength(data) : 0; | |
108 | cssmCertData.Data = (data) ? (uint8 *)CFDataGetBytePtr(data) : NULL; | |
b1ab9ed8 | 109 | |
5c19dc3a A |
110 | SecPointer<Certificate> certificatePtr(new Certificate(cssmCertData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER)); |
111 | implCertRef = certificatePtr->handle(); | |
112 | } | |
113 | catch (...) {} | |
114 | CFRelease(data); | |
115 | return implCertRef; | |
5c19dc3a A |
116 | } |
117 | ||
118 | /* convert an old-world ItemImpl instance to a new-world SecCertificateRef */ | |
119 | SecCertificateRef | |
120 | SecCertificateCreateFromItemImplInstance(SecCertificateRef certificate) | |
121 | { | |
5c19dc3a A |
122 | if (!certificate) { |
123 | return NULL; | |
124 | } | |
125 | SecCertificateRef result = NULL; | |
126 | CFDataRef data = NULL; | |
127 | try { | |
128 | CssmData certData = Certificate::required(certificate)->data(); | |
129 | if (certData.Data && certData.Length) { | |
130 | data = CFDataCreate(NULL, certData.Data, certData.Length); | |
131 | } | |
132 | if (!data) { | |
133 | if (certData.Data && !certData.Length) { | |
134 | /* zero-length certs can exist, so don't bother logging this */ | |
135 | } | |
136 | else { | |
137 | syslog(LOG_ERR, "WARNING: SecKeychainSearchCopyNext failed to retrieve certificate data (length=%ld, data=0x%lX)", | |
138 | (long)certData.Length, (uintptr_t)certData.Data); | |
139 | } | |
140 | return NULL; | |
141 | } | |
142 | } | |
143 | catch (...) {} | |
144 | ||
145 | result = SecCertificateCreateWithKeychainItem(NULL, data, certificate); | |
146 | if (data) | |
147 | CFRelease(data); | |
148 | return result; | |
5c19dc3a A |
149 | } |
150 | ||
fa7225c8 | 151 | |
5c19dc3a | 152 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
153 | OSStatus |
154 | SecCertificateCreateFromData(const CSSM_DATA *data, CSSM_CERT_TYPE type, CSSM_CERT_ENCODING encoding, SecCertificateRef *certificate) | |
155 | { | |
5c19dc3a A |
156 | /* bridge to support old functionality */ |
157 | if (!data || !data->Data || !data->Length || !certificate) { | |
158 | return errSecParam; | |
159 | } | |
160 | SecCertificateRef certRef = NULL; | |
fa7225c8 A |
161 | |
162 | // <rdar://problem/24403998> REG: Adobe {Photoshop, InDesign} CC(2015) crashes on launch | |
163 | // If you take the length that SecKeychainItemCopyContent gives you (a Uint32) and assign it incorrectly | |
164 | // to a CSSM_DATA Length field (a CSSM_SIZE, i.e., a size_t), the upper 32 bits aren't set. If those bits | |
165 | // are non-zero, the length is incredibly wrong. | |
166 | // | |
167 | // Assume that there will not exist a certificate > 4GiB, and fake this length field. | |
168 | CSSM_SIZE length = data->Length & 0xfffffffful; | |
169 | ||
170 | CFDataRef dataRef = CFDataCreate(NULL, data->Data, length); | |
5c19dc3a A |
171 | if (dataRef) { |
172 | certRef = SecCertificateCreateWithData(NULL, dataRef); | |
173 | CFRelease(dataRef); | |
174 | } | |
175 | *certificate = certRef; | |
176 | return (certRef) ? errSecSuccess : errSecUnknownFormat; | |
b1ab9ed8 A |
177 | } |
178 | ||
5c19dc3a | 179 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */ |
b1ab9ed8 A |
180 | OSStatus |
181 | SecCertificateAddToKeychain(SecCertificateRef certificate, SecKeychainRef keychain) | |
182 | { | |
fa7225c8 | 183 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 184 | BEGIN_SECCERTAPI |
b1ab9ed8 | 185 | |
5c19dc3a | 186 | Item item(Certificate::required(__itemImplRef)); |
b1ab9ed8 A |
187 | Keychain::optional(keychain)->add(item); |
188 | ||
5c19dc3a | 189 | END_SECCERTAPI |
b1ab9ed8 A |
190 | } |
191 | ||
5c19dc3a | 192 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
193 | OSStatus |
194 | SecCertificateGetData(SecCertificateRef certificate, CSSM_DATA_PTR data) | |
195 | { | |
5c19dc3a | 196 | BEGIN_SECCERTAPI |
b1ab9ed8 | 197 | |
fa7225c8 A |
198 | if (!certificate || !data) { |
199 | __secapiresult=errSecParam; | |
200 | } | |
201 | else if (SecCertificateIsItemImplInstance(certificate)) { | |
202 | Required(data) = Certificate::required(certificate)->data(); | |
203 | } | |
204 | else { | |
205 | data->Length = (CSSM_SIZE)SecCertificateGetLength(certificate); | |
206 | data->Data = (uint8*)SecCertificateGetBytePtr(certificate); | |
207 | } | |
b1ab9ed8 | 208 | |
5c19dc3a | 209 | END_SECCERTAPI |
e3d460c9 | 210 | } |
427c49bc | 211 | |
5c19dc3a | 212 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
213 | OSStatus |
214 | SecCertificateGetType(SecCertificateRef certificate, CSSM_CERT_TYPE *certificateType) | |
215 | { | |
fa7225c8 | 216 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 217 | BEGIN_SECCERTAPI |
b1ab9ed8 | 218 | |
5c19dc3a | 219 | Required(certificateType) = Certificate::required(__itemImplRef)->type(); |
b1ab9ed8 | 220 | |
5c19dc3a | 221 | END_SECCERTAPI |
b1ab9ed8 A |
222 | } |
223 | ||
5c19dc3a | 224 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
225 | OSStatus |
226 | SecCertificateGetSubject(SecCertificateRef certificate, const CSSM_X509_NAME **subject) | |
227 | { | |
fa7225c8 | 228 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 229 | BEGIN_SECCERTAPI |
b1ab9ed8 | 230 | |
5c19dc3a | 231 | Required(subject) = Certificate::required(__itemImplRef)->subjectName(); |
b1ab9ed8 | 232 | |
5c19dc3a | 233 | END_SECCERTAPI |
b1ab9ed8 A |
234 | } |
235 | ||
5c19dc3a | 236 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
237 | OSStatus |
238 | SecCertificateGetIssuer(SecCertificateRef certificate, const CSSM_X509_NAME **issuer) | |
239 | { | |
fa7225c8 | 240 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a A |
241 | BEGIN_SECCERTAPI |
242 | ||
243 | Required(issuer) = Certificate::required(__itemImplRef)->issuerName(); | |
244 | ||
245 | END_SECCERTAPI | |
246 | } | |
247 | ||
248 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ | |
249 | OSStatus | |
250 | SecCertificateGetCLHandle(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) | |
251 | { | |
fa7225c8 | 252 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a A |
253 | BEGIN_SECCERTAPI |
254 | ||
255 | Required(clHandle) = Certificate::required(__itemImplRef)->clHandle(); | |
256 | ||
257 | END_SECCERTAPI | |
5c19dc3a | 258 | } |
b1ab9ed8 | 259 | |
5c19dc3a A |
260 | /* private function; assumes input is old-style ItemImpl certificate reference, |
261 | and does not release that certificate reference! | |
262 | */ | |
b1ab9ed8 | 263 | OSStatus |
5c19dc3a | 264 | SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) |
b1ab9ed8 A |
265 | { |
266 | BEGIN_SECAPI | |
267 | ||
5c19dc3a | 268 | Required(clHandle) = Certificate::required(certificate)->clHandle(); |
b1ab9ed8 A |
269 | |
270 | END_SECAPI | |
271 | } | |
272 | ||
273 | /* | |
274 | * Private API to infer a display name for a SecCertificateRef which | |
275 | * may or may not be in a keychain. | |
5c19dc3a A |
276 | * |
277 | * OS X only | |
b1ab9ed8 A |
278 | */ |
279 | OSStatus | |
280 | SecCertificateInferLabel(SecCertificateRef certificate, CFStringRef *label) | |
281 | { | |
fa7225c8 | 282 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 283 | BEGIN_SECCERTAPI |
b1ab9ed8 | 284 | |
5c19dc3a | 285 | Certificate::required(__itemImplRef)->inferLabel(false, &Required(label)); |
b1ab9ed8 | 286 | |
5c19dc3a | 287 | END_SECCERTAPI |
b1ab9ed8 A |
288 | } |
289 | ||
5c19dc3a | 290 | /* OS X only (note: iOS version has different arguments and return value) */ |
b1ab9ed8 A |
291 | OSStatus |
292 | SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef *key) | |
293 | { | |
fa7225c8 | 294 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 295 | BEGIN_SECCERTAPI |
b1ab9ed8 | 296 | |
5c19dc3a | 297 | Required(key) = Certificate::required(__itemImplRef)->publicKey()->handle(); |
b1ab9ed8 | 298 | |
5c19dc3a | 299 | END_SECCERTAPI |
b1ab9ed8 A |
300 | } |
301 | ||
5c19dc3a | 302 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
303 | OSStatus |
304 | SecCertificateGetAlgorithmID(SecCertificateRef certificate, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) | |
305 | { | |
fa7225c8 | 306 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 307 | BEGIN_SECCERTAPI |
b1ab9ed8 | 308 | |
5c19dc3a | 309 | Required(algid) = Certificate::required(__itemImplRef)->algorithmID(); |
b1ab9ed8 | 310 | |
5c19dc3a | 311 | END_SECCERTAPI |
b1ab9ed8 A |
312 | } |
313 | ||
5c19dc3a | 314 | /* OS X only */ |
b1ab9ed8 A |
315 | OSStatus |
316 | SecCertificateCopySubjectComponent(SecCertificateRef certificate, const CSSM_OID *component, CFStringRef *result) | |
317 | { | |
fa7225c8 | 318 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 319 | BEGIN_SECCERTAPI |
b1ab9ed8 | 320 | |
5c19dc3a | 321 | Required(result) = Certificate::required(__itemImplRef)->distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, component); |
b1ab9ed8 | 322 | |
5c19dc3a | 323 | END_SECCERTAPI |
b1ab9ed8 A |
324 | } |
325 | ||
5c19dc3a | 326 | /* OS X only; deprecated SPI */ |
b1ab9ed8 A |
327 | OSStatus |
328 | SecCertificateGetCommonName(SecCertificateRef certificate, CFStringRef *commonName) | |
329 | { | |
330 | // deprecated SPI signature; replaced by SecCertificateCopyCommonName | |
331 | return SecCertificateCopyCommonName(certificate, commonName); | |
332 | } | |
333 | ||
5c19dc3a | 334 | /* OS X only; deprecated SPI */ |
b1ab9ed8 A |
335 | OSStatus |
336 | SecCertificateGetEmailAddress(SecCertificateRef certificate, CFStringRef *emailAddress) | |
337 | { | |
fa7225c8 | 338 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 339 | BEGIN_SECCERTAPI |
b1ab9ed8 | 340 | |
5c19dc3a | 341 | Required(emailAddress) = Certificate::required(__itemImplRef)->copyFirstEmailAddress(); |
b1ab9ed8 | 342 | |
5c19dc3a | 343 | END_SECCERTAPI |
b1ab9ed8 A |
344 | } |
345 | ||
5c19dc3a A |
346 | /* Return a zero terminated list of CSSM_DATA_PTR's with the values of the field specified by field. |
347 | * Caller must call releaseFieldValues to free the storage allocated by this call. | |
348 | * | |
349 | * OS X only | |
350 | */ | |
b1ab9ed8 A |
351 | OSStatus |
352 | SecCertificateCopyFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR **fieldValues) | |
353 | { | |
fa7225c8 | 354 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 355 | BEGIN_SECCERTAPI |
b1ab9ed8 | 356 | |
5c19dc3a | 357 | Required(fieldValues) = Certificate::required(__itemImplRef)->copyFieldValues(Required(field)); |
b1ab9ed8 | 358 | |
5c19dc3a | 359 | END_SECCERTAPI |
b1ab9ed8 A |
360 | } |
361 | ||
5c19dc3a | 362 | /* OS X only */ |
b1ab9ed8 A |
363 | OSStatus |
364 | SecCertificateReleaseFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValues) | |
365 | { | |
fa7225c8 | 366 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 367 | BEGIN_SECCERTAPI |
b1ab9ed8 | 368 | |
5c19dc3a | 369 | Certificate::required(__itemImplRef)->releaseFieldValues(Required(field), fieldValues); |
b1ab9ed8 | 370 | |
5c19dc3a | 371 | END_SECCERTAPI |
b1ab9ed8 A |
372 | } |
373 | ||
5c19dc3a | 374 | /* OS X only */ |
b1ab9ed8 A |
375 | OSStatus |
376 | SecCertificateCopyFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValue) | |
377 | { | |
fa7225c8 | 378 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 379 | BEGIN_SECCERTAPI |
b1ab9ed8 | 380 | |
5c19dc3a | 381 | Required(fieldValue) = Certificate::required(__itemImplRef)->copyFirstFieldValue(Required(field)); |
b1ab9ed8 | 382 | |
5c19dc3a | 383 | END_SECCERTAPI |
b1ab9ed8 A |
384 | } |
385 | ||
5c19dc3a | 386 | /* OS X only */ |
b1ab9ed8 A |
387 | OSStatus |
388 | SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR fieldValue) | |
389 | { | |
fa7225c8 | 390 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 391 | BEGIN_SECCERTAPI |
b1ab9ed8 | 392 | |
5c19dc3a | 393 | Certificate::required(__itemImplRef)->releaseFieldValue(Required(field), fieldValue); |
b1ab9ed8 | 394 | |
5c19dc3a | 395 | END_SECCERTAPI |
b1ab9ed8 A |
396 | } |
397 | ||
5c19dc3a | 398 | /* OS X only */ |
b1ab9ed8 A |
399 | OSStatus |
400 | SecCertificateFindByIssuerAndSN(CFTypeRef keychainOrArray,const CSSM_DATA *issuer, | |
401 | const CSSM_DATA *serialNumber, SecCertificateRef *certificate) | |
402 | { | |
b04fe171 A |
403 | if (issuer && serialNumber) { |
404 | CFRef<CFMutableDictionaryRef> query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
405 | CFDictionarySetValue(query, kSecClass, kSecClassCertificate); | |
406 | CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); | |
b54c578e | 407 | CFDictionarySetValue(query, kSecUseDataProtectionKeychain, kCFBooleanTrue); |
b04fe171 A |
408 | |
409 | CFRef<CFDataRef> issuerData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)issuer->Data, issuer->Length, kCFAllocatorNull); | |
410 | CFDictionarySetValue(query, kSecAttrIssuer, issuerData); | |
411 | ||
412 | CFRef<CFDataRef> serialNumberData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)serialNumber->Data, serialNumber->Length, kCFAllocatorNull); | |
413 | CFDictionarySetValue(query, kSecAttrSerialNumber, serialNumberData); | |
414 | ||
415 | OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)certificate); | |
416 | if (status == errSecSuccess) { | |
417 | return status; | |
418 | } | |
419 | } | |
420 | ||
b1ab9ed8 A |
421 | BEGIN_SECAPI |
422 | ||
423 | StorageManager::KeychainList keychains; | |
424 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
425 | Required(certificate) = Certificate::findByIssuerAndSN(keychains, CssmData::required(issuer), CssmData::required(serialNumber))->handle(); | |
426 | ||
5c19dc3a A |
427 | // convert ItemImpl-based SecCertificateRef to new-world version before returning |
428 | CssmData certData = Certificate::required(*certificate)->data(); | |
429 | CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length)); | |
430 | SecCertificateRef tmpRef = *certificate; | |
431 | *certificate = SecCertificateCreateWithData(NULL, cfData); | |
432 | CFRelease(tmpRef); | |
5c19dc3a | 433 | |
b1ab9ed8 A |
434 | END_SECAPI |
435 | } | |
436 | ||
5c19dc3a | 437 | /* OS X only */ |
b1ab9ed8 A |
438 | OSStatus |
439 | SecCertificateFindBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, | |
440 | SecCertificateRef *certificate) | |
441 | { | |
b04fe171 A |
442 | if (subjectKeyID) { |
443 | CFRef<CFMutableDictionaryRef> query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
444 | CFDictionarySetValue(query, kSecClass, kSecClassCertificate); | |
445 | CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); | |
b54c578e | 446 | CFDictionarySetValue(query, kSecUseDataProtectionKeychain, kCFBooleanTrue); |
b04fe171 A |
447 | |
448 | CFRef<CFDataRef> subjectKeyIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)subjectKeyID->Data, subjectKeyID->Length, kCFAllocatorNull); | |
449 | CFDictionarySetValue(query, kSecAttrSubjectKeyID, subjectKeyIDData); | |
450 | ||
451 | OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)certificate); | |
452 | if (status == errSecSuccess) { | |
453 | return status; | |
454 | } | |
455 | } | |
456 | ||
457 | BEGIN_SECAPI | |
b1ab9ed8 A |
458 | |
459 | StorageManager::KeychainList keychains; | |
460 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
461 | Required(certificate) = Certificate::findBySubjectKeyID(keychains, CssmData::required(subjectKeyID))->handle(); | |
462 | ||
5c19dc3a A |
463 | // convert ItemImpl-based SecCertificateRef to new-world version before returning |
464 | CssmData certData = Certificate::required(*certificate)->data(); | |
465 | CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length)); | |
466 | SecCertificateRef tmpRef = *certificate; | |
467 | *certificate = SecCertificateCreateWithData(NULL, cfData); | |
468 | CFRelease(tmpRef); | |
5c19dc3a | 469 | |
b1ab9ed8 A |
470 | END_SECAPI |
471 | } | |
472 | ||
5c19dc3a | 473 | /* OS X only */ |
b1ab9ed8 A |
474 | OSStatus |
475 | SecCertificateFindByEmail(CFTypeRef keychainOrArray, const char *emailAddress, SecCertificateRef *certificate) | |
476 | { | |
b04fe171 A |
477 | if (emailAddress) { |
478 | CFRef<CFMutableDictionaryRef> query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
479 | CFDictionarySetValue(query, kSecClass, kSecClassCertificate); | |
480 | CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); | |
b54c578e | 481 | CFDictionarySetValue(query, kSecUseDataProtectionKeychain, kCFBooleanTrue); |
b04fe171 A |
482 | |
483 | CFRef<CFStringRef> emailAddressString = CFStringCreateWithCString(kCFAllocatorDefault, emailAddress, kCFStringEncodingUTF8); | |
484 | CFTypeRef keys[] = { kSecPolicyName }; | |
485 | CFTypeRef values[] = { emailAddressString }; | |
486 | CFRef<CFDictionaryRef> properties = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
487 | CFRef<SecPolicyRef> policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, properties); | |
488 | CFDictionarySetValue(query, kSecMatchPolicy, policy); | |
489 | ||
490 | OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)certificate); | |
491 | if (status == errSecSuccess) { | |
492 | return status; | |
493 | } | |
494 | } | |
495 | ||
496 | BEGIN_SECAPI | |
b1ab9ed8 A |
497 | |
498 | StorageManager::KeychainList keychains; | |
499 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
500 | Required(certificate) = Certificate::findByEmail(keychains, emailAddress)->handle(); | |
501 | ||
5c19dc3a A |
502 | // convert ItemImpl-based SecCertificateRef to new-world version before returning |
503 | CssmData certData = Certificate::required(*certificate)->data(); | |
504 | CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length)); | |
505 | SecCertificateRef tmpRef = *certificate; | |
506 | *certificate = SecCertificateCreateWithData(NULL, cfData); | |
507 | CFRelease(tmpRef); | |
5c19dc3a | 508 | |
b1ab9ed8 A |
509 | END_SECAPI |
510 | } | |
511 | ||
5c19dc3a | 512 | /* OS X only */ |
b1ab9ed8 A |
513 | OSStatus |
514 | SecKeychainSearchCreateForCertificateByIssuerAndSN(CFTypeRef keychainOrArray, const CSSM_DATA *issuer, | |
515 | const CSSM_DATA *serialNumber, SecKeychainSearchRef *searchRef) | |
516 | { | |
517 | BEGIN_SECAPI | |
518 | ||
519 | Required(searchRef); | |
520 | ||
521 | StorageManager::KeychainList keychains; | |
522 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
523 | KCCursor cursor(Certificate::cursorForIssuerAndSN(keychains, CssmData::required(issuer), CssmData::required(serialNumber))); | |
524 | *searchRef = cursor->handle(); | |
525 | ||
526 | END_SECAPI | |
527 | } | |
528 | ||
5c19dc3a | 529 | /* OS X only */ |
b1ab9ed8 A |
530 | OSStatus |
531 | SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(CFTypeRef keychainOrArray, CFDataRef issuer, | |
532 | CFDataRef serialNumber, SecKeychainSearchRef *searchRef) | |
533 | { | |
534 | BEGIN_SECAPI | |
535 | ||
536 | Required(searchRef); | |
537 | ||
538 | StorageManager::KeychainList keychains; | |
539 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
540 | Required(issuer); | |
541 | Required(serialNumber); | |
542 | KCCursor cursor(Certificate::cursorForIssuerAndSN_CF(keychains, issuer, serialNumber)); | |
543 | *searchRef = cursor->handle(); | |
544 | ||
545 | END_SECAPI | |
546 | } | |
547 | ||
5c19dc3a | 548 | /* OS X only */ |
b1ab9ed8 A |
549 | OSStatus |
550 | SecKeychainSearchCreateForCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, | |
551 | SecKeychainSearchRef *searchRef) | |
552 | { | |
553 | BEGIN_SECAPI | |
554 | ||
555 | Required(searchRef); | |
556 | ||
557 | StorageManager::KeychainList keychains; | |
558 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
559 | KCCursor cursor(Certificate::cursorForSubjectKeyID(keychains, CssmData::required(subjectKeyID))); | |
560 | *searchRef = cursor->handle(); | |
561 | ||
562 | END_SECAPI | |
563 | } | |
564 | ||
5c19dc3a | 565 | /* OS X only */ |
b1ab9ed8 A |
566 | OSStatus |
567 | SecKeychainSearchCreateForCertificateByEmail(CFTypeRef keychainOrArray, const char *emailAddress, | |
568 | SecKeychainSearchRef *searchRef) | |
569 | { | |
570 | BEGIN_SECAPI | |
571 | ||
572 | Required(searchRef); | |
573 | ||
574 | StorageManager::KeychainList keychains; | |
575 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
576 | KCCursor cursor(Certificate::cursorForEmail(keychains, emailAddress)); | |
577 | *searchRef = cursor->handle(); | |
578 | ||
579 | END_SECAPI | |
580 | } | |
581 | ||
5c19dc3a | 582 | /* OS X only */ |
b1ab9ed8 A |
583 | CSSM_RETURN |
584 | SecDigestGetData (CSSM_ALGORITHMS alg, CSSM_DATA* digest, const CSSM_DATA* data) | |
585 | { | |
586 | BEGIN_SECAPI | |
587 | // sanity checking | |
588 | if (!digest || !digest->Data || !digest->Length || !data || !data->Data || !data->Length) | |
427c49bc | 589 | return errSecParam; |
b1ab9ed8 A |
590 | |
591 | CSP csp(gGuidAppleCSP); | |
592 | Digest context(csp, alg); | |
593 | CssmData input(data->Data, data->Length); | |
594 | CssmData output(digest->Data, digest->Length); | |
595 | ||
596 | context.digest(input, output); | |
597 | digest->Length = output.length(); | |
598 | ||
599 | return CSSM_OK; | |
600 | END_SECAPI1(1); | |
601 | } | |
602 | ||
5c19dc3a | 603 | /* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ |
b1ab9ed8 A |
604 | OSStatus |
605 | SecCertificateCopyPreference( | |
606 | CFStringRef name, | |
607 | CSSM_KEYUSE keyUsage, | |
608 | SecCertificateRef *certificate) | |
609 | { | |
610 | BEGIN_SECAPI | |
611 | ||
612 | Required(name); | |
613 | Required(certificate); | |
614 | StorageManager::KeychainList keychains; | |
615 | globals().storageManager.getSearchList(keychains); | |
616 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
617 | ||
618 | char idUTF8[MAXPATHLEN]; | |
619 | if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8)) | |
620 | idUTF8[0] = (char)'\0'; | |
621 | CssmData service(const_cast<char *>(idUTF8), strlen(idUTF8)); | |
622 | FourCharCode itemType = 'cprf'; | |
623 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service); | |
624 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType); | |
625 | if (keyUsage) | |
626 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); | |
627 | ||
628 | Item prefItem; | |
629 | if (!cursor->next(prefItem)) | |
630 | MacOSError::throwMe(errSecItemNotFound); | |
631 | ||
632 | // get persistent certificate reference | |
633 | SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } }; | |
634 | SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs }; | |
635 | prefItem->getContent(NULL, &itemAttrList, NULL, NULL); | |
636 | ||
637 | // find certificate, given persistent reference data | |
638 | CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull); | |
639 | SecKeychainItemRef certItemRef = nil; | |
640 | OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef); //%%% need to make this a method of ItemImpl | |
641 | prefItem->freeContent(&itemAttrList, NULL); | |
642 | if (pItemRef) | |
643 | CFRelease(pItemRef); | |
644 | if (status) | |
645 | return status; | |
646 | ||
647 | *certificate = (SecCertificateRef)certItemRef; | |
648 | ||
fa7225c8 A |
649 | if (certItemRef && (CFGetTypeID(certItemRef) == SecIdentityGetTypeID())) { |
650 | // SecKeychainItemCopyFromPersistentReference handed out an identity reference | |
651 | *certificate = NULL; | |
652 | status = SecIdentityCopyCertificate((SecIdentityRef)certItemRef, certificate); | |
653 | CFRelease(certItemRef); | |
654 | return status; | |
655 | } | |
5c19dc3a | 656 | |
b1ab9ed8 A |
657 | END_SECAPI |
658 | } | |
659 | ||
5c19dc3a | 660 | /* OS X only */ |
b1ab9ed8 A |
661 | SecCertificateRef |
662 | SecCertificateCopyPreferred( | |
663 | CFStringRef name, | |
664 | CFArrayRef keyUsage) | |
665 | { | |
666 | // This function will look for a matching preference in the following order: | |
667 | // - matches the name and the supplied key use | |
668 | // - matches the name and the special 'ANY' key use | |
669 | // - matches the name with no key usage constraint | |
670 | ||
671 | SecCertificateRef certRef = NULL; | |
672 | CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage); | |
673 | OSStatus status = SecCertificateCopyPreference(name, keyUse, &certRef); | |
427c49bc | 674 | if (status != errSecSuccess && keyUse != CSSM_KEYUSE_ANY) |
b1ab9ed8 | 675 | status = SecCertificateCopyPreference(name, CSSM_KEYUSE_ANY, &certRef); |
427c49bc | 676 | if (status != errSecSuccess && keyUse != 0) |
b1ab9ed8 A |
677 | status = SecCertificateCopyPreference(name, 0, &certRef); |
678 | ||
679 | return certRef; | |
680 | } | |
681 | ||
5c19dc3a | 682 | /* OS X only; not exported */ |
427c49bc | 683 | static OSStatus |
b1ab9ed8 A |
684 | SecCertificateFindPreferenceItemWithNameAndKeyUsage( |
685 | CFTypeRef keychainOrArray, | |
686 | CFStringRef name, | |
687 | int32_t keyUsage, | |
688 | SecKeychainItemRef *itemRef) | |
689 | { | |
690 | BEGIN_SECAPI | |
691 | ||
692 | StorageManager::KeychainList keychains; | |
693 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
694 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
695 | ||
696 | char idUTF8[MAXPATHLEN]; | |
697 | idUTF8[0] = (char)'\0'; | |
698 | if (name) | |
699 | { | |
700 | if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8)) | |
701 | idUTF8[0] = (char)'\0'; | |
702 | } | |
703 | size_t idUTF8Len = strlen(idUTF8); | |
704 | if (!idUTF8Len) | |
427c49bc | 705 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
706 | |
707 | CssmData service(const_cast<char *>(idUTF8), idUTF8Len); | |
708 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service); | |
709 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'cprf'); | |
710 | if (keyUsage) | |
711 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); | |
712 | ||
713 | Item item; | |
714 | if (!cursor->next(item)) | |
715 | MacOSError::throwMe(errSecItemNotFound); | |
716 | ||
717 | if (itemRef) | |
718 | *itemRef=item->handle(); | |
719 | ||
720 | END_SECAPI | |
721 | } | |
722 | ||
5c19dc3a | 723 | /* OS X only; not exported */ |
427c49bc | 724 | static |
b1ab9ed8 A |
725 | OSStatus SecCertificateDeletePreferenceItemWithNameAndKeyUsage( |
726 | CFTypeRef keychainOrArray, | |
727 | CFStringRef name, | |
728 | int32_t keyUsage) | |
729 | { | |
730 | // when a specific key usage is passed, we'll only match & delete that pref; | |
731 | // when a key usage of 0 is passed, all matching prefs should be deleted. | |
732 | // maxUsages represents the most matches there could theoretically be, so | |
733 | // cut things off at that point if we're still finding items (if they can't | |
734 | // be deleted for some reason, we'd never break out of the loop.) | |
735 | ||
6b200bc3 | 736 | OSStatus status = errSecSuccess; |
b1ab9ed8 A |
737 | SecKeychainItemRef item = NULL; |
738 | int count = 0, maxUsages = 12; | |
739 | while (++count <= maxUsages && | |
427c49bc | 740 | (status = SecCertificateFindPreferenceItemWithNameAndKeyUsage(keychainOrArray, name, keyUsage, &item)) == errSecSuccess) { |
b1ab9ed8 A |
741 | status = SecKeychainItemDelete(item); |
742 | CFRelease(item); | |
743 | item = NULL; | |
744 | } | |
745 | ||
746 | // it's not an error if the item isn't found | |
427c49bc | 747 | return (status == errSecItemNotFound) ? errSecSuccess : status; |
b1ab9ed8 A |
748 | } |
749 | ||
5c19dc3a | 750 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */ |
b1ab9ed8 A |
751 | OSStatus SecCertificateSetPreference( |
752 | SecCertificateRef certificate, | |
753 | CFStringRef name, | |
754 | CSSM_KEYUSE keyUsage, | |
755 | CFDateRef date) | |
756 | { | |
757 | if (!name) { | |
427c49bc | 758 | return errSecParam; |
b1ab9ed8 A |
759 | } |
760 | if (!certificate) { | |
761 | // treat NULL certificate as a request to clear the preference | |
762 | // (note: if keyUsage is 0, this clears all key usage prefs for name) | |
763 | return SecCertificateDeletePreferenceItemWithNameAndKeyUsage(NULL, name, keyUsage); | |
764 | } | |
765 | ||
fa7225c8 | 766 | // This macro creates an ItemImpl certificate if it does not exist |
5c19dc3a | 767 | BEGIN_SECCERTAPI |
b1ab9ed8 A |
768 | |
769 | // determine the account attribute | |
770 | // | |
771 | // This attribute must be synthesized from certificate label + pref item type + key usage, | |
772 | // as only the account and service attributes can make a generic keychain item unique. | |
773 | // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that | |
774 | // we can save a certificate preference if an identity preference already exists for the | |
775 | // given service name, and vice-versa. | |
776 | // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. | |
777 | // | |
778 | CFStringRef labelStr = nil; | |
5c19dc3a | 779 | Certificate::required(__itemImplRef)->inferLabel(false, &labelStr); |
b1ab9ed8 A |
780 | if (!labelStr) { |
781 | MacOSError::throwMe(errSecDataTooLarge); // data is "in a format which cannot be displayed" | |
782 | } | |
783 | CFIndex accountUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr), kCFStringEncodingUTF8) + 1; | |
784 | const char *templateStr = "%s [key usage 0x%X]"; | |
785 | const int keyUsageMaxStrLen = 8; | |
786 | accountUTF8Len += strlen(templateStr) + keyUsageMaxStrLen; | |
79b9da22 A |
787 | char *accountUTF8 = (char *)malloc(accountUTF8Len); |
788 | if (!accountUTF8) { | |
789 | MacOSError::throwMe(errSecMemoryError); | |
790 | } | |
b1ab9ed8 A |
791 | if (!CFStringGetCString(labelStr, accountUTF8, accountUTF8Len-1, kCFStringEncodingUTF8)) |
792 | accountUTF8[0] = (char)'\0'; | |
793 | if (keyUsage) | |
794 | snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage); | |
79b9da22 A |
795 | CssmDataContainer account(const_cast<char *>(accountUTF8), strlen(accountUTF8)); |
796 | free(accountUTF8); | |
b1ab9ed8 A |
797 | CFRelease(labelStr); |
798 | ||
799 | // service attribute (name provided by the caller) | |
800 | CFIndex serviceUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(name), kCFStringEncodingUTF8) + 1;; | |
79b9da22 A |
801 | char *serviceUTF8 = (char *)malloc(serviceUTF8Len); |
802 | if (!serviceUTF8) { | |
803 | MacOSError::throwMe(errSecMemoryError); | |
804 | } | |
b1ab9ed8 A |
805 | if (!CFStringGetCString(name, serviceUTF8, serviceUTF8Len-1, kCFStringEncodingUTF8)) |
806 | serviceUTF8[0] = (char)'\0'; | |
79b9da22 A |
807 | CssmDataContainer service(const_cast<char *>(serviceUTF8), strlen(serviceUTF8)); |
808 | free(serviceUTF8); | |
b1ab9ed8 A |
809 | |
810 | // look for existing preference item, in case this is an update | |
811 | StorageManager::KeychainList keychains; | |
812 | globals().storageManager.getSearchList(keychains); | |
813 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
814 | FourCharCode itemType = 'cprf'; | |
815 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service); | |
816 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType); | |
817 | if (keyUsage) | |
818 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); | |
819 | if (date) | |
820 | ; // %%%TBI | |
821 | ||
822 | Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false); | |
823 | bool add = (!cursor->next(item)); | |
824 | // at this point, we either have a new item to add or an existing item to update | |
825 | ||
826 | // set item attribute values | |
827 | item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); | |
828 | item->setAttribute(Schema::attributeInfo(kSecTypeItemAttr), itemType); | |
829 | item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); | |
830 | item->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); | |
831 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); | |
832 | ||
833 | // date | |
834 | if (date) | |
835 | ; // %%%TBI | |
836 | ||
837 | // generic attribute (store persistent certificate reference) | |
838 | CFDataRef pItemRef = nil; | |
5c19dc3a | 839 | Certificate::required(__itemImplRef)->copyPersistentReference(pItemRef); |
b1ab9ed8 A |
840 | if (!pItemRef) { |
841 | MacOSError::throwMe(errSecInvalidItemRef); | |
842 | } | |
843 | const UInt8 *dataPtr = CFDataGetBytePtr(pItemRef); | |
844 | CFIndex dataLen = CFDataGetLength(pItemRef); | |
845 | CssmData pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr)), dataLen); | |
846 | item->setAttribute(Schema::attributeInfo(kSecGenericItemAttr), pref); | |
847 | CFRelease(pItemRef); | |
848 | ||
849 | if (add) { | |
850 | Keychain keychain = nil; | |
851 | try { | |
852 | keychain = globals().storageManager.defaultKeychain(); | |
853 | if (!keychain->exists()) | |
854 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
855 | } | |
856 | catch(...) { | |
857 | keychain = globals().storageManager.defaultKeychainUI(item); | |
858 | } | |
859 | ||
860 | try { | |
861 | keychain->add(item); | |
862 | } | |
863 | catch (const MacOSError &err) { | |
864 | if (err.osStatus() != errSecDuplicateItem) | |
865 | throw; // if item already exists, fall through to update | |
866 | } | |
867 | } | |
868 | item->update(); | |
869 | ||
5c19dc3a | 870 | END_SECCERTAPI |
b1ab9ed8 A |
871 | } |
872 | ||
5c19dc3a | 873 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
874 | OSStatus SecCertificateSetPreferred( |
875 | SecCertificateRef certificate, | |
876 | CFStringRef name, | |
877 | CFArrayRef keyUsage) | |
878 | { | |
879 | CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage); | |
880 | return SecCertificateSetPreference(certificate, name, keyUse, NULL); | |
881 | } | |
882 | ||
5c19dc3a | 883 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
884 | CFDictionaryRef SecCertificateCopyValues(SecCertificateRef certificate, CFArrayRef keys, CFErrorRef *error) |
885 | { | |
886 | CFDictionaryRef result = NULL; | |
427c49bc | 887 | OSStatus __secapiresult; |
fa7225c8 | 888 | SecCertificateRef tmpcert = NULL; |
6b200bc3 | 889 | |
fa7225c8 A |
890 | // convert input to a new-style certificate reference if necessary, |
891 | // since the implementation of CertificateValues calls SecCertificate API functions | |
892 | // which now assume a unified certificate reference. | |
893 | if (SecCertificateIsItemImplInstance(certificate)) { | |
894 | tmpcert = SecCertificateCreateFromItemImplInstance(certificate); | |
895 | } | |
fa7225c8 A |
896 | if (certificate && !tmpcert) { |
897 | tmpcert = (SecCertificateRef) CFRetain(certificate); | |
898 | } | |
b1ab9ed8 A |
899 | try |
900 | { | |
fa7225c8 | 901 | CertificateValues cv(tmpcert); |
b1ab9ed8 A |
902 | result = cv.copyFieldValues(keys,error); |
903 | __secapiresult=0; | |
904 | } | |
905 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
906 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
907 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
908 | catch (...) { __secapiresult=errSecInternalComponent; } | |
fa7225c8 | 909 | if (tmpcert) { CFRelease(tmpcert); } |
427c49bc | 910 | return result; |
b1ab9ed8 A |
911 | } |
912 | ||
5c19dc3a | 913 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
914 | CFStringRef SecCertificateCopyLongDescription(CFAllocatorRef alloc, SecCertificateRef certificate, CFErrorRef *error) |
915 | { | |
916 | return SecCertificateCopyShortDescription(alloc, certificate, error); | |
917 | } | |
918 | ||
5c19dc3a | 919 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
920 | CFStringRef SecCertificateCopyShortDescription(CFAllocatorRef alloc, SecCertificateRef certificate, CFErrorRef *error) |
921 | { | |
922 | CFStringRef result = NULL; | |
5c19dc3a | 923 | OSStatus __secapiresult = SecCertificateInferLabel(certificate, &result); |
427c49bc | 924 | if (error!=NULL && __secapiresult!=errSecSuccess) |
b1ab9ed8 A |
925 | { |
926 | *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, | |
927 | __secapiresult ? __secapiresult : CSSM_ERRCODE_INTERNAL_ERROR, NULL); | |
928 | } | |
427c49bc | 929 | return result; |
b1ab9ed8 A |
930 | } |
931 | ||
5c19dc3a | 932 | /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ |
b1ab9ed8 A |
933 | CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate, CFErrorRef *error) |
934 | { | |
935 | CFDataRef result = NULL; | |
427c49bc | 936 | OSStatus __secapiresult; |
b1ab9ed8 A |
937 | try |
938 | { | |
939 | CertificateValues cv(certificate); | |
940 | result = cv.copySerialNumber(error); | |
941 | __secapiresult=0; | |
942 | } | |
943 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
944 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
945 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
946 | catch (...) { __secapiresult=errSecInternalComponent; } | |
947 | return result; | |
b1ab9ed8 A |
948 | } |
949 | ||
6b200bc3 | 950 | /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA) */ |
b1ab9ed8 A |
951 | CFDataRef SecCertificateCopyNormalizedIssuerContent(SecCertificateRef certificate, CFErrorRef *error) |
952 | { | |
953 | CFDataRef result = NULL; | |
427c49bc | 954 | OSStatus __secapiresult; |
b1ab9ed8 A |
955 | try |
956 | { | |
957 | CertificateValues cv(certificate); | |
427c49bc | 958 | result = cv.copyNormalizedIssuerContent(error); |
b1ab9ed8 A |
959 | __secapiresult=0; |
960 | } | |
961 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
962 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
963 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
964 | catch (...) { __secapiresult=errSecInternalComponent; } | |
965 | return result; | |
b1ab9ed8 A |
966 | } |
967 | ||
6b200bc3 | 968 | /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA) */ |
b1ab9ed8 A |
969 | CFDataRef SecCertificateCopyNormalizedSubjectContent(SecCertificateRef certificate, CFErrorRef *error) |
970 | { | |
971 | CFDataRef result = NULL; | |
427c49bc | 972 | OSStatus __secapiresult; |
b1ab9ed8 A |
973 | try |
974 | { | |
975 | CertificateValues cv(certificate); | |
427c49bc | 976 | result = cv.copyNormalizedSubjectContent(error); |
b1ab9ed8 A |
977 | __secapiresult=0; |
978 | } | |
979 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
980 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
981 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
982 | catch (...) { __secapiresult=errSecInternalComponent; } | |
983 | return result; | |
b1ab9ed8 A |
984 | } |
985 | ||
5c19dc3a | 986 | /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA) */ |
427c49bc A |
987 | bool SecCertificateIsValidX(SecCertificateRef certificate, CFAbsoluteTime verifyTime) |
988 | { | |
5c19dc3a A |
989 | /* |
990 | * deprecated function name | |
991 | */ | |
427c49bc A |
992 | return SecCertificateIsValid(certificate, verifyTime); |
993 | } | |
8a50f688 A |
994 | |
995 | /* OS X only */ | |
996 | CFDataRef SecCertificateCopyPublicKeySHA1DigestFromCertificateData(CFAllocatorRef allocator, | |
997 | CFDataRef der_certificate) | |
998 | { | |
999 | CFDataRef result = NULL; | |
1000 | SecCertificateRef iosCertRef = SecCertificateCreateWithData(allocator, der_certificate); | |
1001 | if (NULL == iosCertRef) | |
1002 | { | |
1003 | return result; | |
1004 | } | |
1005 | ||
1006 | result = SecCertificateCopyPublicKeySHA1Digest(iosCertRef); | |
1007 | CFRelease(iosCertRef); | |
1008 | return result; | |
1009 | } | |
1010 |