]>
Commit | Line | Data |
---|---|---|
52b7d2ce A |
1 | |
2 | /* | |
3 | * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
7 | * The contents of this file constitute Original Code as defined in and | |
8 | * are subject to the Apple Public Source License Version 1.1 (the | |
9 | * "License"). You may not use this file except in compliance with the | |
10 | * License. Please obtain a copy of the License at | |
11 | * http://www.apple.com/publicsource and read it before using this file. | |
12 | * | |
13 | * This 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 OR NON-INFRINGEMENT. Please see the | |
18 | * License for the specific language governing rights and limitations | |
19 | * under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | /* | |
26 | * Racoon module for verifying and signing certificates through Security | |
27 | * Framework and CSSM | |
28 | */ | |
29 | ||
52b7d2ce A |
30 | #include <Security/SecCertificate.h> |
31 | #include <Security/SecPolicy.h> | |
d1e348cf A |
32 | #include <Security/SecTrust.h> |
33 | #include <Security/SecKey.h> | |
52b7d2ce | 34 | #include <Security/SecIdentity.h> |
85f41bec | 35 | #include <Security/SecItem.h> |
d1e348cf A |
36 | #include <TargetConditionals.h> |
37 | #if TARGET_OS_EMBEDDED | |
fce29cd9 A |
38 | #include <Security/SecTrustPriv.h> |
39 | #include <Security/SecPolicyPriv.h> | |
40 | #include <Security/SecCertificatePriv.h> | |
d1e348cf A |
41 | #else |
42 | #include <Security/SecBase.h> | |
52b7d2ce A |
43 | #include <Security/SecIdentityPriv.h> |
44 | #include <Security/SecIdentitySearch.h> | |
45 | #include <Security/SecKeychain.h> | |
46 | #include <Security/SecKeychainItem.h> | |
47 | #include <Security/SecKeychainItemPriv.h> | |
65c25746 | 48 | #include <Security/SecCertificateOIDs.h> |
52b7d2ce | 49 | #include <Security/SecKeyPriv.h> |
52b7d2ce A |
50 | #include <Security/oidsalg.h> |
51 | #include <Security/cssmapi.h> | |
52 | #include <Security/SecPolicySearch.h> | |
d1e348cf | 53 | #endif |
52b7d2ce | 54 | #include <CoreFoundation/CoreFoundation.h> |
65c25746 | 55 | #if !TARGET_OS_EMBEDDED |
52b7d2ce | 56 | #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> |
65c25746 | 57 | #endif |
52b7d2ce A |
58 | #include "plog.h" |
59 | #include "debug.h" | |
60 | #include "misc.h" | |
fce29cd9 | 61 | #include "oakley.h" |
65c25746 | 62 | #include "gcmalloc.h" |
52b7d2ce | 63 | |
52b7d2ce | 64 | |
d1e348cf | 65 | #include "crypto_cssm.h" |
52b7d2ce | 66 | |
85f41bec | 67 | |
e8d9021d | 68 | static OSStatus EvaluateCert(SecCertificateRef evalCertArray[], CFIndex evalCertArrayNumValues, CFTypeRef policyRef, SecKeyRef *publicKeyRef); |
52b7d2ce | 69 | |
d1e348cf | 70 | #if !TARGET_OS_EMBEDDED |
d1e348cf | 71 | #endif |
52b7d2ce | 72 | |
e8d9021d A |
73 | static SecPolicyRef |
74 | crypto_cssm_x509cert_get_SecPolicyRef (CFStringRef hostname) | |
52b7d2ce | 75 | { |
d1e348cf | 76 | SecPolicyRef policyRef = NULL; |
65c25746 A |
77 | CFDictionaryRef properties = NULL; |
78 | const void *key[] = { kSecPolicyName }; | |
79 | const void *value[] = { hostname }; | |
d1e348cf | 80 | |
e8d9021d | 81 | if (hostname) { |
65c25746 A |
82 | properties = CFDictionaryCreate(NULL, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
83 | if (properties == NULL) { | |
84 | plog(ASL_LEVEL_ERR, | |
85 | "unable to create dictionary for policy properties.\n"); | |
e8d9021d A |
86 | } |
87 | } | |
65c25746 A |
88 | policyRef = SecPolicyCreateWithProperties(kSecPolicyAppleIPsec, properties); |
89 | if (properties) | |
90 | CFRelease(properties); | |
e8d9021d A |
91 | return policyRef; |
92 | } | |
93 | ||
94 | SecCertificateRef | |
65c25746 | 95 | crypto_cssm_x509cert_CreateSecCertificateRef (vchar_t *cert) |
e8d9021d | 96 | { |
e8d9021d | 97 | SecCertificateRef certRef = NULL; |
52b7d2ce | 98 | |
65c25746 | 99 | CFDataRef cert_data = CFDataCreateWithBytesNoCopy(NULL, (uint8_t*)cert->v, cert->l, kCFAllocatorNull); |
d1e348cf A |
100 | if (cert_data) { |
101 | certRef = SecCertificateCreateWithData(NULL, cert_data); | |
102 | CFRelease(cert_data); | |
103 | } | |
85f41bec | 104 | |
d1e348cf | 105 | if (certRef == NULL) { |
65c25746 A |
106 | plog(ASL_LEVEL_ERR, |
107 | "unable to get a certifcate reference.\n"); | |
d1e348cf | 108 | } |
e8d9021d A |
109 | return certRef; |
110 | } | |
d1e348cf | 111 | |
65c25746 A |
112 | /* HACK!!! - temporary until this prototype gets moved */ |
113 | extern CFDataRef SecCertificateCopySubjectSequence( SecCertificateRef certificate); | |
114 | ||
115 | CFDataRef | |
116 | crypto_cssm_CopySubjectSequence(SecCertificateRef certRef) | |
117 | { | |
118 | CFDataRef subject = NULL; | |
119 | ||
120 | subject = SecCertificateCopySubjectSequence(certRef); | |
121 | return subject; | |
122 | ||
123 | } | |
124 | ||
125 | ||
e8d9021d A |
126 | static cert_status_t |
127 | crypto_cssm_check_x509cert_dates (SecCertificateRef certificateRef) | |
128 | { | |
129 | cert_status_t certStatus = CERT_STATUS_OK; | |
130 | #if TARGET_OS_EMBEDDED | |
131 | CFAbsoluteTime timeNow = 0; | |
132 | CFAbsoluteTime notvalidbeforedate = 0; | |
133 | CFAbsoluteTime notvalidafterdate = 0; | |
134 | CFDateRef nowcfdatedata = NULL; | |
135 | CFDateRef notvalidbeforedatedata = NULL; | |
136 | CFDateRef notvalidafterdatedata = NULL; | |
137 | CFArrayRef certProparray = NULL; | |
138 | CFDictionaryRef propDict = NULL; | |
139 | const void *datevalue = NULL; | |
140 | const void *labelvalue = NULL; | |
141 | CFGregorianDate gregoriandate; | |
142 | CFIndex count; | |
143 | CFIndex i; | |
144 | ||
145 | if ((certProparray = SecCertificateCopyProperties(certificateRef))){ | |
146 | if ((count = CFArrayGetCount( certProparray ))){ | |
147 | for( i = 0; i < count; i++) { | |
148 | if ((propDict = CFArrayGetValueAtIndex(certProparray, i))) { | |
149 | if ( CFDictionaryGetValueIfPresent(propDict, kSecPropertyKeyValue, (const void**)&datevalue)){ | |
150 | /* get kSecPropertyKeyLabel */ | |
151 | if ( (datevalue) && (CFDictionaryGetValueIfPresent(propDict, kSecPropertyKeyLabel, (const void**)&labelvalue))){ | |
152 | if ( (labelvalue) && (CFStringCompare( (CFStringRef)labelvalue, CFSTR("Not Valid Before"), 0) == kCFCompareEqualTo)){ | |
65c25746 | 153 | if ( (notvalidbeforedate = CFDateGetAbsoluteTime(datevalue))) { |
e8d9021d A |
154 | if (notvalidbeforedatedata) { |
155 | CFRelease(notvalidbeforedatedata); | |
156 | } | |
157 | notvalidbeforedatedata = CFDateCreate(NULL, notvalidbeforedate); | |
158 | } | |
159 | }else if ((labelvalue) && (CFStringCompare( (CFStringRef)labelvalue, CFSTR("Not Valid After"), 0 ) == kCFCompareEqualTo)){ | |
65c25746 | 160 | if ( (notvalidafterdate = CFDateGetAbsoluteTime(datevalue))) { |
e8d9021d A |
161 | if (notvalidafterdatedata) { |
162 | CFRelease(notvalidafterdatedata); | |
163 | } | |
164 | notvalidafterdatedata = CFDateCreate(NULL, notvalidafterdate); | |
165 | } | |
166 | } | |
167 | } | |
168 | } | |
169 | } | |
170 | } | |
d1e348cf | 171 | } |
d1e348cf | 172 | } |
e8d9021d A |
173 | |
174 | if ( (timeNow = CFAbsoluteTimeGetCurrent()) && (nowcfdatedata = CFDateCreate( NULL, timeNow))){ | |
175 | if ( notvalidbeforedatedata ){ | |
176 | gregoriandate = CFAbsoluteTimeGetGregorianDate(notvalidbeforedate, NULL); | |
65c25746 A |
177 | plog(ASL_LEVEL_DEBUG, |
178 | "Certificate not valid before yr %d, mon %d, days %d, hours %d, min %d\n", (int)gregoriandate.year, gregoriandate.month, gregoriandate.day, gregoriandate.hour, gregoriandate.minute); | |
e8d9021d | 179 | gregoriandate = CFAbsoluteTimeGetGregorianDate(notvalidafterdate, NULL); |
65c25746 A |
180 | plog(ASL_LEVEL_DEBUG, |
181 | "Certificate not valid after yr %d, mon %d, days %d, hours %d, min %d\n", (int)gregoriandate.year, gregoriandate.month, gregoriandate.day, gregoriandate.hour, gregoriandate.minute); | |
e8d9021d | 182 | if ( CFDateCompare( nowcfdatedata, notvalidbeforedatedata, NULL ) == kCFCompareLessThan){ |
65c25746 | 183 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
184 | "current time before valid time\n"); |
185 | certStatus = CERT_STATUS_PREMATURE; | |
186 | } else if (notvalidafterdatedata && (CFDateCompare( nowcfdatedata, notvalidafterdatedata, NULL ) == kCFCompareGreaterThan)){ | |
65c25746 | 187 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
188 | "current time after valid time\n"); |
189 | certStatus = CERT_STATUS_EXPIRED; | |
190 | }else { | |
65c25746 | 191 | plog(ASL_LEVEL_INFO, "Certificate expiration date is OK\n"); |
e8d9021d A |
192 | certStatus = CERT_STATUS_OK; |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | if (notvalidbeforedatedata) | |
198 | CFRelease(notvalidbeforedatedata); | |
199 | if (notvalidafterdatedata) | |
200 | CFRelease(notvalidafterdatedata); | |
201 | if (certProparray) | |
202 | CFRelease(certProparray); | |
203 | if (nowcfdatedata) | |
204 | CFRelease(nowcfdatedata); | |
205 | #endif | |
206 | return certStatus; | |
207 | } | |
208 | ||
209 | /* | |
210 | * Verify cert using security framework | |
211 | */ | |
e8d9021d | 212 | int crypto_cssm_check_x509cert (cert_t *hostcert, cert_t *certchain, CFStringRef hostname, SecKeyRef *publicKeyRef) |
e8d9021d A |
213 | { |
214 | cert_t *p; | |
215 | cert_status_t certStatus = 0; | |
216 | OSStatus status; | |
217 | CFIndex certArrayRefNumValues = 0; | |
218 | CFIndex n = 0; | |
219 | int certArraySiz; | |
220 | SecCertificateRef *certArrayRef = NULL; | |
221 | SecPolicyRef policyRef = crypto_cssm_x509cert_get_SecPolicyRef(hostname); | |
222 | ||
223 | if (!hostcert || !certchain) { | |
224 | return -1; | |
225 | } | |
226 | ||
227 | // find the total number of certs | |
228 | for (p = certchain; p; p = p->chain, n++); | |
229 | if (n> 1) { | |
65c25746 A |
230 | plog(ASL_LEVEL_DEBUG, |
231 | "%s: checking chain of %d certificates.\n", __FUNCTION__, (int)n); | |
e8d9021d A |
232 | } |
233 | ||
234 | certArraySiz = n * sizeof(CFTypeRef); | |
235 | certArrayRef = CFAllocatorAllocate(NULL, certArraySiz, 0); | |
236 | if (!certArrayRef) { | |
237 | return -1; | |
238 | } | |
239 | bzero(certArrayRef, certArraySiz); | |
65c25746 | 240 | if ((certArrayRef[certArrayRefNumValues] = crypto_cssm_x509cert_CreateSecCertificateRef(&hostcert->cert))) { |
e8d9021d A |
241 | /* don't overwrite any pending status */ |
242 | if (!hostcert->status) { | |
243 | hostcert->status = crypto_cssm_check_x509cert_dates(certArrayRef[certArrayRefNumValues]); | |
244 | if (hostcert->status) { | |
65c25746 | 245 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
246 | "host certificate failed date verification: %d.\n", hostcert->status); |
247 | certStatus = hostcert->status; | |
248 | } | |
249 | } | |
250 | certArrayRefNumValues++; | |
251 | } | |
252 | for (p = certchain; p && certArrayRefNumValues < n; p = p->chain) { | |
253 | if (p != hostcert) { | |
65c25746 | 254 | if ((certArrayRef[certArrayRefNumValues] = crypto_cssm_x509cert_CreateSecCertificateRef(&p->cert))) { |
e8d9021d A |
255 | /* don't overwrite any pending status */ |
256 | if (!p->status) { | |
257 | p->status = crypto_cssm_check_x509cert_dates(certArrayRef[certArrayRefNumValues]); | |
258 | if (p->status) { | |
65c25746 | 259 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
260 | "other certificate in chain failed date verification: %d.\n", p->status); |
261 | if (!certStatus) { | |
262 | certStatus = p->status; | |
263 | } | |
264 | } | |
265 | } | |
266 | certArrayRefNumValues++; | |
267 | } | |
268 | } | |
269 | } | |
52b7d2ce A |
270 | |
271 | // evaluate cert | |
e8d9021d | 272 | status = EvaluateCert(certArrayRef, certArrayRefNumValues, policyRef, publicKeyRef); |
e8d9021d A |
273 | |
274 | while (certArrayRefNumValues) { | |
275 | CFRelease(certArrayRef[--certArrayRefNumValues]); | |
276 | } | |
277 | CFAllocatorDeallocate(NULL, certArrayRef); | |
52b7d2ce | 278 | |
52b7d2ce A |
279 | if (policyRef) |
280 | CFRelease(policyRef); | |
281 | ||
282 | if (status != noErr && status != -1) { | |
65c25746 A |
283 | plog(ASL_LEVEL_ERR, |
284 | "error %d %s.\n", (int)status, GetSecurityErrorString(status)); | |
52b7d2ce | 285 | status = -1; |
e8d9021d | 286 | } else if (certStatus == CERT_STATUS_PREMATURE || certStatus == CERT_STATUS_EXPIRED) { |
fce29cd9 A |
287 | status = -1; |
288 | } | |
52b7d2ce | 289 | return status; |
e8d9021d A |
290 | |
291 | } | |
52b7d2ce | 292 | |
85f41bec | 293 | |
65c25746 | 294 | int crypto_cssm_verify_x509sign(SecKeyRef publicKeyRef, vchar_t *hash, vchar_t *signature, Boolean useSHA1) |
e8d9021d | 295 | { |
65c25746 | 296 | return SecKeyRawVerify(publicKeyRef, useSHA1 ? kSecPaddingPKCS1SHA1 : kSecPaddingPKCS1, (uint8_t*)hash->v, hash->l, (uint8_t*)signature->v, signature->l); |
52b7d2ce A |
297 | } |
298 | ||
299 | /* | |
300 | * Encrypt a hash via CSSM using the private key in the keychain | |
301 | * from an identity. | |
302 | */ | |
303 | vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash) | |
304 | { | |
305 | ||
e8d9021d | 306 | OSStatus status = -1; |
52b7d2ce | 307 | SecIdentityRef identityRef = NULL; |
d1e348cf A |
308 | SecKeyRef privateKeyRef = NULL; |
309 | vchar_t *sig = NULL; | |
310 | ||
d1e348cf A |
311 | |
312 | CFDictionaryRef persistFind = NULL; | |
85f41bec A |
313 | const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef, kSecClass}; |
314 | const void *values_persist[] = { kCFBooleanTrue, persistentCertRef, kSecClassIdentity}; | |
315 | ||
316 | #define SIG_BUF_SIZE 1024 | |
d1e348cf A |
317 | |
318 | /* find identity by persistent ref */ | |
319 | persistFind = CFDictionaryCreate(NULL, keys_persist, values_persist, | |
85f41bec | 320 | (sizeof(keys_persist) / sizeof(*keys_persist)), NULL, NULL); |
d1e348cf A |
321 | if (persistFind == NULL) |
322 | goto end; | |
323 | ||
324 | status = SecItemCopyMatching(persistFind, (CFTypeRef *)&identityRef); | |
325 | if (status != noErr) | |
326 | goto end; | |
327 | ||
328 | status = SecIdentityCopyPrivateKey(identityRef, &privateKeyRef); | |
329 | if (status != noErr) | |
330 | goto end; | |
331 | ||
332 | // alloc buffer for result | |
333 | sig = vmalloc(SIG_BUF_SIZE); | |
334 | if (sig == NULL) | |
335 | goto end; | |
336 | ||
65c25746 A |
337 | status = SecKeyRawSign(privateKeyRef, kSecPaddingPKCS1, (uint8_t*)hash->v, |
338 | hash->l, (uint8_t*)sig->v, &sig->l); | |
d1e348cf | 339 | |
52b7d2ce A |
340 | |
341 | end: | |
52b7d2ce A |
342 | if (identityRef) |
343 | CFRelease(identityRef); | |
344 | if (privateKeyRef) | |
345 | CFRelease(privateKeyRef); | |
d1e348cf | 346 | |
d1e348cf A |
347 | if (persistFind) |
348 | CFRelease(persistFind); | |
d1e348cf | 349 | |
52b7d2ce A |
350 | if (status != noErr) { |
351 | if (sig) { | |
352 | vfree(sig); | |
353 | sig = NULL; | |
354 | } | |
355 | } | |
356 | ||
357 | if (status != noErr && status != -1) { | |
65c25746 A |
358 | plog(ASL_LEVEL_ERR, |
359 | "error %d %s.\n", (int)status, GetSecurityErrorString(status)); | |
52b7d2ce A |
360 | status = -1; |
361 | } | |
362 | return sig; | |
363 | ||
364 | } | |
365 | ||
366 | ||
367 | /* | |
368 | * Retrieve a cert from the keychain | |
369 | */ | |
fce29cd9 A |
370 | vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef, |
371 | cert_status_t *certStatus) | |
52b7d2ce A |
372 | { |
373 | ||
e8d9021d | 374 | OSStatus status = -1; |
52b7d2ce | 375 | vchar_t *cert = NULL; |
65c25746 A |
376 | SecCertificateRef certificateRef = NULL; |
377 | CFDictionaryRef persistFind = NULL; | |
378 | size_t dataLen; | |
379 | CFDataRef certData = NULL; | |
52b7d2ce | 380 | SecIdentityRef identityRef = NULL; |
65c25746 A |
381 | const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef, kSecClass }; |
382 | const void *values_persist[] = { kCFBooleanTrue, persistentCertRef, kSecClassIdentity }; | |
d1e348cf A |
383 | |
384 | /* find identity by persistent ref */ | |
385 | persistFind = CFDictionaryCreate(NULL, keys_persist, values_persist, | |
e8d9021d | 386 | (sizeof(keys_persist) / sizeof(*keys_persist)), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
d1e348cf A |
387 | if (persistFind == NULL) |
388 | goto end; | |
65c25746 A |
389 | |
390 | status = SecItemCopyMatching(persistFind, (CFTypeRef *)&identityRef); | |
d1e348cf A |
391 | if (status != noErr) |
392 | goto end; | |
393 | ||
394 | status = SecIdentityCopyCertificate(identityRef, &certificateRef); | |
395 | if (status != noErr) | |
396 | goto end; | |
397 | ||
398 | certData = SecCertificateCopyData(certificateRef); | |
399 | if (certData == NULL) | |
400 | goto end; | |
401 | ||
402 | dataLen = CFDataGetLength(certData); | |
403 | if (dataLen == 0) | |
404 | goto end; | |
405 | ||
406 | cert = vmalloc(dataLen); | |
407 | if (cert == NULL) | |
408 | goto end; | |
409 | ||
65c25746 | 410 | CFDataGetBytes(certData, CFRangeMake(0, dataLen), (uint8_t*)cert->v); |
d1e348cf | 411 | |
fce29cd9 A |
412 | // verify expiry or missing fields |
413 | if (certStatus) { | |
e8d9021d | 414 | *certStatus = crypto_cssm_check_x509cert_dates(certificateRef); |
fce29cd9 | 415 | } |
52b7d2ce A |
416 | |
417 | end: | |
65c25746 A |
418 | if (identityRef) |
419 | CFRelease(identityRef); | |
52b7d2ce A |
420 | if (certificateRef) |
421 | CFRelease(certificateRef); | |
d1e348cf A |
422 | if (persistFind) |
423 | CFRelease(persistFind); | |
424 | if (certData) | |
425 | CFRelease(certData); | |
d1e348cf | 426 | |
52b7d2ce | 427 | if (status != noErr && status != -1) { |
65c25746 A |
428 | plog(ASL_LEVEL_ERR, |
429 | "error %d %s.\n", (int)status, GetSecurityErrorString(status)); | |
52b7d2ce A |
430 | status = -1; |
431 | } | |
432 | return cert; | |
433 | ||
434 | } | |
435 | ||
52b7d2ce A |
436 | /* |
437 | * Evaluate the trust of a cert using the policy provided | |
438 | */ | |
e8d9021d | 439 | static OSStatus EvaluateCert(SecCertificateRef evalCertArray[], CFIndex evalCertArrayNumValues, CFTypeRef policyRef, SecKeyRef *publicKeyRef) |
52b7d2ce A |
440 | { |
441 | OSStatus status; | |
442 | SecTrustRef trustRef = 0; | |
443 | SecTrustResultType evalResult; | |
fce29cd9 | 444 | |
fce29cd9 | 445 | CFArrayRef errorStrings; |
52b7d2ce | 446 | |
e8d9021d | 447 | CFArrayRef cfCertRef = CFArrayCreate((CFAllocatorRef) NULL, (void*)evalCertArray, evalCertArrayNumValues, |
d1e348cf | 448 | &kCFTypeArrayCallBacks); |
52b7d2ce A |
449 | |
450 | if (!cfCertRef) { | |
65c25746 | 451 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
452 | "unable to create CFArray.\n"); |
453 | return -1; | |
454 | } | |
455 | ||
456 | status = SecTrustCreateWithCertificates(cfCertRef, policyRef, &trustRef); | |
457 | if (status != noErr) | |
458 | goto end; | |
fce29cd9 | 459 | |
52b7d2ce A |
460 | status = SecTrustEvaluate(trustRef, &evalResult); |
461 | if (status != noErr) | |
462 | goto end; | |
463 | ||
464 | if (evalResult != kSecTrustResultProceed && evalResult != kSecTrustResultUnspecified) { | |
65c25746 | 465 | plog(ASL_LEVEL_ERR, "Error evaluating certificate.\n"); |
fce29cd9 A |
466 | |
467 | switch (evalResult) { | |
468 | case kSecTrustResultInvalid: | |
65c25746 | 469 | plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultInvalid.\n"); |
fce29cd9 A |
470 | break; |
471 | case kSecTrustResultProceed: | |
65c25746 | 472 | plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultProceed.\n"); |
fce29cd9 | 473 | break; |
fce29cd9 | 474 | case kSecTrustResultDeny: |
65c25746 | 475 | plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultDeny.\n"); |
fce29cd9 A |
476 | break; |
477 | case kSecTrustResultUnspecified: | |
65c25746 | 478 | plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultUnspecified.\n"); |
fce29cd9 A |
479 | break; |
480 | case kSecTrustResultRecoverableTrustFailure: | |
65c25746 | 481 | plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultRecoverableTrustFailure.\n"); |
fce29cd9 A |
482 | break; |
483 | case kSecTrustResultFatalTrustFailure: | |
65c25746 | 484 | plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultFatalTrustFailure.\n"); |
fce29cd9 A |
485 | break; |
486 | case kSecTrustResultOtherError: | |
65c25746 | 487 | plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultOtherError.\n"); |
fce29cd9 A |
488 | break; |
489 | default: | |
65c25746 | 490 | plog(ASL_LEVEL_DEBUG, "eval result unknown: value = %d.\n", (int)evalResult); |
fce29cd9 A |
491 | break; |
492 | } | |
493 | ||
fce29cd9 A |
494 | errorStrings = SecTrustCopyProperties(trustRef); |
495 | if (errorStrings) { | |
496 | ||
497 | CFDictionaryRef dict; | |
498 | CFStringRef val; | |
499 | const char *str; | |
500 | CFIndex count, maxcount = CFArrayGetCount(errorStrings); | |
501 | ||
65c25746 | 502 | plog(ASL_LEVEL_ERR, "---------------Returned error strings: ---------------.\n"); |
fce29cd9 A |
503 | for (count = 0; count < maxcount; count++) { |
504 | dict = CFArrayGetValueAtIndex(errorStrings, count); | |
505 | if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) { | |
506 | val = CFDictionaryGetValue(dict, kSecPropertyKeyType); | |
507 | if (val && (CFGetTypeID(val) == CFStringGetTypeID())) { | |
508 | str = CFStringGetCStringPtr(val, kCFStringEncodingMacRoman); | |
509 | if (str) | |
65c25746 | 510 | plog(ASL_LEVEL_ERR, "type = %s.\n", str); |
fce29cd9 A |
511 | } |
512 | val = CFDictionaryGetValue(dict, kSecPropertyKeyValue); | |
513 | if (val && (CFGetTypeID(val) == CFStringGetTypeID())) { | |
514 | str = CFStringGetCStringPtr(val, kCFStringEncodingMacRoman); | |
515 | if (str) | |
65c25746 | 516 | plog(ASL_LEVEL_ERR, "value = %s.\n", str); |
fce29cd9 A |
517 | } |
518 | } | |
519 | } | |
65c25746 | 520 | plog(ASL_LEVEL_ERR, "-----------------------------------------------------.\n"); |
fce29cd9 A |
521 | CFRelease(errorStrings); |
522 | } | |
85f41bec | 523 | |
52b7d2ce | 524 | status = -1; |
e8d9021d | 525 | goto end; |
52b7d2ce A |
526 | } |
527 | ||
e8d9021d A |
528 | /* get and return the public key */ |
529 | *publicKeyRef = SecTrustCopyPublicKey(trustRef); | |
e8d9021d | 530 | |
52b7d2ce A |
531 | end: |
532 | if (cfCertRef) | |
533 | CFRelease(cfCertRef); | |
534 | if (trustRef) | |
535 | CFRelease(trustRef); | |
536 | ||
537 | if (status != noErr && status != -1) { | |
65c25746 A |
538 | plog(ASL_LEVEL_ERR, |
539 | "error %d %s.\n", (int)status, GetSecurityErrorString(status)); | |
52b7d2ce A |
540 | status = -1; |
541 | } | |
542 | return status; | |
543 | } | |
544 | ||
52b7d2ce A |
545 | /* |
546 | * Return string representation of Security-related OSStatus. | |
547 | */ | |
548 | const char * | |
549 | GetSecurityErrorString(OSStatus err) | |
550 | { | |
551 | switch(err) { | |
552 | case noErr: | |
553 | return "noErr"; | |
52b7d2ce A |
554 | |
555 | /* SecBase.h: */ | |
556 | case errSecNotAvailable: | |
557 | return "errSecNotAvailable"; | |
65c25746 | 558 | |
d1e348cf | 559 | #if !TARGET_OS_EMBEDDED |
65c25746 A |
560 | case memFullErr: |
561 | return "memFullErr"; | |
562 | case paramErr: | |
563 | return "paramErr"; | |
564 | case unimpErr: | |
565 | return "unimpErr"; | |
566 | ||
567 | /* SecBase.h: */ | |
52b7d2ce A |
568 | case errSecReadOnly: |
569 | return "errSecReadOnly"; | |
570 | case errSecAuthFailed: | |
571 | return "errSecAuthFailed"; | |
572 | case errSecNoSuchKeychain: | |
573 | return "errSecNoSuchKeychain"; | |
574 | case errSecInvalidKeychain: | |
575 | return "errSecInvalidKeychain"; | |
576 | case errSecDuplicateKeychain: | |
577 | return "errSecDuplicateKeychain"; | |
578 | case errSecDuplicateCallback: | |
579 | return "errSecDuplicateCallback"; | |
580 | case errSecInvalidCallback: | |
581 | return "errSecInvalidCallback"; | |
52b7d2ce A |
582 | case errSecBufferTooSmall: |
583 | return "errSecBufferTooSmall"; | |
584 | case errSecDataTooLarge: | |
585 | return "errSecDataTooLarge"; | |
586 | case errSecNoSuchAttr: | |
587 | return "errSecNoSuchAttr"; | |
588 | case errSecInvalidItemRef: | |
589 | return "errSecInvalidItemRef"; | |
590 | case errSecInvalidSearchRef: | |
591 | return "errSecInvalidSearchRef"; | |
592 | case errSecNoSuchClass: | |
593 | return "errSecNoSuchClass"; | |
594 | case errSecNoDefaultKeychain: | |
595 | return "errSecNoDefaultKeychain"; | |
596 | case errSecInteractionNotAllowed: | |
597 | return "errSecInteractionNotAllowed"; | |
598 | case errSecReadOnlyAttr: | |
599 | return "errSecReadOnlyAttr"; | |
600 | case errSecWrongSecVersion: | |
601 | return "errSecWrongSecVersion"; | |
602 | case errSecKeySizeNotAllowed: | |
603 | return "errSecKeySizeNotAllowed"; | |
604 | case errSecNoStorageModule: | |
605 | return "errSecNoStorageModule"; | |
606 | case errSecNoCertificateModule: | |
607 | return "errSecNoCertificateModule"; | |
608 | case errSecNoPolicyModule: | |
609 | return "errSecNoPolicyModule"; | |
610 | case errSecInteractionRequired: | |
611 | return "errSecInteractionRequired"; | |
612 | case errSecDataNotAvailable: | |
613 | return "errSecDataNotAvailable"; | |
614 | case errSecDataNotModifiable: | |
615 | return "errSecDataNotModifiable"; | |
616 | case errSecCreateChainFailed: | |
617 | return "errSecCreateChainFailed"; | |
618 | case errSecACLNotSimple: | |
619 | return "errSecACLNotSimple"; | |
620 | case errSecPolicyNotFound: | |
621 | return "errSecPolicyNotFound"; | |
622 | case errSecInvalidTrustSetting: | |
623 | return "errSecInvalidTrustSetting"; | |
624 | case errSecNoAccessForItem: | |
625 | return "errSecNoAccessForItem"; | |
626 | case errSecInvalidOwnerEdit: | |
627 | return "errSecInvalidOwnerEdit"; | |
d1e348cf A |
628 | #endif |
629 | case errSecDuplicateItem: | |
630 | return "errSecDuplicateItem"; | |
631 | case errSecItemNotFound: | |
632 | return "errSecItemNotFound"; | |
52b7d2ce A |
633 | default: |
634 | return "<unknown>"; | |
635 | } | |
636 | } | |
637 |