]>
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> |
d1e348cf A |
35 | |
36 | #include <TargetConditionals.h> | |
37 | #if TARGET_OS_EMBEDDED | |
38 | #include <Security/SecItem.h> | |
fce29cd9 A |
39 | #include <Security/SecTrustPriv.h> |
40 | #include <Security/SecPolicyPriv.h> | |
41 | #include <Security/SecCertificatePriv.h> | |
d1e348cf A |
42 | #else |
43 | #include <Security/SecBase.h> | |
52b7d2ce A |
44 | #include <Security/SecIdentityPriv.h> |
45 | #include <Security/SecIdentitySearch.h> | |
46 | #include <Security/SecKeychain.h> | |
47 | #include <Security/SecKeychainItem.h> | |
48 | #include <Security/SecKeychainItemPriv.h> | |
d1e348cf | 49 | |
52b7d2ce | 50 | #include <Security/SecKeyPriv.h> |
52b7d2ce A |
51 | #include <Security/oidsalg.h> |
52 | #include <Security/cssmapi.h> | |
53 | #include <Security/SecPolicySearch.h> | |
d1e348cf A |
54 | #endif |
55 | ||
52b7d2ce A |
56 | #include <CoreFoundation/CoreFoundation.h> |
57 | #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> | |
58 | #include "plog.h" | |
59 | #include "debug.h" | |
60 | #include "misc.h" | |
fce29cd9 | 61 | #include "oakley.h" |
52b7d2ce | 62 | |
52b7d2ce | 63 | |
d1e348cf | 64 | #include "crypto_cssm.h" |
52b7d2ce A |
65 | |
66 | ||
52b7d2ce | 67 | static OSStatus EvaluateCert(SecCertificateRef cert, CFTypeRef policyRef); |
52b7d2ce | 68 | static const char *GetSecurityErrorString(OSStatus err); |
d1e348cf A |
69 | #if !TARGET_OS_EMBEDDED |
70 | static OSStatus FindPolicy(const CSSM_OID *policyOID, SecPolicyRef *policyRef); | |
71 | static OSStatus CopySystemKeychain(SecKeychainRef *keychainRef); | |
72 | #endif | |
52b7d2ce A |
73 | |
74 | /* | |
75 | * Verify cert using security framework | |
76 | */ | |
fce29cd9 | 77 | int crypto_cssm_check_x509cert(vchar_t *cert, CFStringRef hostname, cert_status_t certStatus) |
52b7d2ce A |
78 | { |
79 | OSStatus status; | |
d1e348cf A |
80 | SecCertificateRef certRef = NULL; |
81 | SecPolicyRef policyRef = NULL; | |
82 | ||
83 | #if !TARGET_OS_EMBEDDED | |
52b7d2ce A |
84 | CSSM_DATA certData; |
85 | CSSM_OID ourPolicyOID = CSSMOID_APPLE_TP_IP_SEC; | |
52b7d2ce A |
86 | |
87 | // create cert ref | |
88 | certData.Length = cert->l; | |
89 | certData.Data = (uint8 *)cert->v; | |
90 | status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, | |
91 | &certRef); | |
92 | if (status != noErr) | |
93 | goto end; | |
94 | ||
95 | // get our policy object | |
96 | status = FindPolicy(&ourPolicyOID, &policyRef); | |
97 | if (status != noErr) | |
98 | goto end; | |
52b7d2ce A |
99 | // no options used at present - verification of subjectAltName fields, etc. |
100 | // are done elsewhere in racoon in oakley_check_certid() | |
d1e348cf A |
101 | |
102 | #else | |
103 | CFDataRef cert_data = CFDataCreateWithBytesNoCopy(NULL, cert->v, cert->l, kCFAllocatorNull); | |
104 | if (cert_data) { | |
105 | certRef = SecCertificateCreateWithData(NULL, cert_data); | |
106 | CFRelease(cert_data); | |
107 | } | |
108 | ||
109 | if (certRef == NULL) { | |
110 | plog(LLV_ERROR, LOCATION, NULL, | |
111 | "unable to create a certRef.\n"); | |
112 | status = -1; | |
113 | goto end; | |
114 | } | |
115 | ||
116 | if (hostname) { | |
fce29cd9 | 117 | policyRef = SecPolicyCreateIPSec(FALSE, hostname); |
d1e348cf A |
118 | if (policyRef == NULL) { |
119 | plog(LLV_ERROR, LOCATION, NULL, | |
120 | "unable to create a SSL policyRef.\n"); | |
121 | status = -1; | |
122 | goto end; | |
123 | } | |
d1e348cf A |
124 | } |
125 | ||
126 | #endif | |
52b7d2ce A |
127 | |
128 | // evaluate cert | |
129 | status = EvaluateCert(certRef, policyRef); | |
130 | ||
52b7d2ce A |
131 | end: |
132 | ||
133 | if (certRef) | |
134 | CFRelease(certRef); | |
135 | if (policyRef) | |
136 | CFRelease(policyRef); | |
137 | ||
138 | if (status != noErr && status != -1) { | |
139 | plog(LLV_ERROR, LOCATION, NULL, | |
140 | "error %d %s.\n", status, GetSecurityErrorString(status)); | |
141 | status = -1; | |
fce29cd9 A |
142 | } else if (certStatus) { |
143 | plog(LLV_ERROR, LOCATION, NULL, | |
144 | "certificate failed date verification: %d.\n", certStatus); | |
145 | status = -1; | |
146 | } | |
52b7d2ce A |
147 | return status; |
148 | ||
149 | } | |
150 | ||
151 | /* | |
152 | * Encrypt a hash via CSSM using the private key in the keychain | |
153 | * from an identity. | |
154 | */ | |
155 | vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash) | |
156 | { | |
157 | ||
158 | OSStatus status; | |
52b7d2ce | 159 | SecIdentityRef identityRef = NULL; |
d1e348cf A |
160 | SecKeyRef privateKeyRef = NULL; |
161 | vchar_t *sig = NULL; | |
162 | ||
163 | #if !TARGET_OS_EMBEDDED | |
164 | u_int32_t bytesEncrypted = 0; | |
165 | SecCertificateRef certificateRef = NULL; | |
52b7d2ce A |
166 | SecIdentitySearchRef idSearchRef = NULL; |
167 | SecKeychainRef keychainRef = NULL; | |
52b7d2ce A |
168 | const CSSM_KEY *cssmKey = NULL; |
169 | CSSM_CSP_HANDLE cspHandle = nil; | |
170 | CSSM_CC_HANDLE cssmContextHandle = nil; | |
171 | const CSSM_ACCESS_CREDENTIALS *credentials = NULL; | |
172 | //CSSM_SIZE bytesEncrypted = 0; //%%%%HWR fix this - need new headers on Leopard | |
52b7d2ce A |
173 | CSSM_DATA clearData; |
174 | CSSM_DATA cipherData; | |
175 | CSSM_DATA remData; | |
176 | CSSM_CONTEXT_ATTRIBUTE newAttr; | |
52b7d2ce A |
177 | |
178 | remData.Length = 0; | |
179 | remData.Data = 0; | |
180 | ||
d1e348cf | 181 | if (persistentCertRef) { |
52b7d2ce A |
182 | // get cert from keychain |
183 | status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef); | |
184 | if (status != noErr) | |
185 | goto end; | |
186 | ||
187 | // get keychain ref where cert is contained | |
188 | status = SecKeychainItemCopyKeychain((SecKeychainItemRef)certificateRef, &keychainRef); | |
189 | if (status != noErr) | |
190 | goto end; | |
191 | ||
192 | // get identity from the certificate | |
193 | status = SecIdentityCreateWithCertificate(keychainRef, certificateRef, &identityRef); | |
194 | if (status != noErr) | |
195 | goto end; | |
196 | ||
197 | } else { | |
d1e348cf | 198 | |
52b7d2ce A |
199 | // copy system keychain |
200 | status = CopySystemKeychain(&keychainRef); | |
201 | if (status != noErr) | |
202 | goto end; | |
203 | ||
204 | // serach for first identity in system keychain | |
205 | status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef); | |
206 | if (status != noErr) | |
207 | goto end; | |
208 | ||
209 | status = SecIdentitySearchCopyNext(idSearchRef, &identityRef); | |
210 | if (status != noErr) | |
211 | goto end; | |
212 | ||
213 | // get certificate from identity | |
214 | status = SecIdentityCopyCertificate(identityRef, &certificateRef); | |
215 | if (status != noErr) | |
216 | goto end; | |
217 | } | |
218 | ||
52b7d2ce A |
219 | // get private key from identity |
220 | status = SecIdentityCopyPrivateKey(identityRef, &privateKeyRef); | |
221 | if (status != noErr) | |
222 | goto end; | |
223 | ||
224 | // get CSSM_KEY pointer from key ref | |
225 | status = SecKeyGetCSSMKey(privateKeyRef, &cssmKey); | |
226 | if (status != noErr) | |
227 | goto end; | |
228 | ||
229 | // get CSSM CSP handle | |
230 | status = SecKeychainGetCSPHandle(keychainRef, &cspHandle); | |
231 | if (status != noErr) | |
232 | goto end; | |
233 | ||
234 | // create CSSM credentials to unlock private key for encryption - no UI to be used | |
235 | status = SecKeyGetCredentials(privateKeyRef, CSSM_ACL_AUTHORIZATION_ENCRYPT, | |
236 | kSecCredentialTypeNoUI, &credentials); | |
237 | if (status != noErr) | |
238 | goto end; | |
239 | ||
240 | // create asymmetric context for encryption | |
241 | status = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA, credentials, cssmKey, | |
242 | CSSM_PADDING_PKCS1, &cssmContextHandle); | |
243 | if (status != noErr) | |
244 | goto end; | |
245 | ||
246 | // add mode attribute to use private key for encryption | |
247 | newAttr.AttributeType = CSSM_ATTRIBUTE_MODE; | |
248 | newAttr.AttributeLength = sizeof(uint32); | |
249 | newAttr.Attribute.Data = (CSSM_DATA_PTR)CSSM_ALGMODE_PRIVATE_KEY; | |
250 | status = CSSM_UpdateContextAttributes(cssmContextHandle, 1, &newAttr); | |
251 | if(status != noErr) | |
252 | goto end; | |
253 | ||
254 | // and finally - encrypt data | |
255 | clearData.Length = hash->l; | |
256 | clearData.Data = (uint8 *)hash->v; | |
257 | cipherData.Length = 0; | |
258 | cipherData.Data = NULL; | |
259 | status = CSSM_EncryptData(cssmContextHandle, &clearData, 1, &cipherData, 1, &bytesEncrypted, | |
260 | &remData); | |
261 | if (status != noErr) | |
262 | goto end; | |
263 | ||
264 | if (remData.Length != 0) { // something didn't go right - should be zero | |
265 | status = -1; | |
266 | plog(LLV_ERROR, LOCATION, NULL, | |
267 | "unencrypted data remaining after encrypting hash.\n"); | |
268 | goto end; | |
269 | } | |
270 | ||
271 | // alloc buffer for result | |
272 | sig = vmalloc(0); | |
273 | if (sig == NULL) | |
274 | goto end; | |
275 | ||
276 | sig->l = cipherData.Length; | |
277 | sig->v = (caddr_t)cipherData.Data; | |
d1e348cf A |
278 | |
279 | #else | |
280 | ||
281 | CFDictionaryRef persistFind = NULL; | |
282 | const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef }; | |
283 | const void *values_persist[] = { kCFBooleanTrue, persistentCertRef }; | |
284 | ||
285 | #define SIG_BUF_SIZE 1024 | |
286 | ||
287 | /* find identity by persistent ref */ | |
288 | persistFind = CFDictionaryCreate(NULL, keys_persist, values_persist, | |
289 | (sizeof(keys_persist) / sizeof(*keys_persist)), NULL, NULL); | |
290 | if (persistFind == NULL) | |
291 | goto end; | |
292 | ||
293 | status = SecItemCopyMatching(persistFind, (CFTypeRef *)&identityRef); | |
294 | if (status != noErr) | |
295 | goto end; | |
296 | ||
297 | status = SecIdentityCopyPrivateKey(identityRef, &privateKeyRef); | |
298 | if (status != noErr) | |
299 | goto end; | |
300 | ||
301 | // alloc buffer for result | |
302 | sig = vmalloc(SIG_BUF_SIZE); | |
303 | if (sig == NULL) | |
304 | goto end; | |
305 | ||
306 | status = SecKeyRawSign(privateKeyRef, kSecPaddingPKCS1, hash->v, | |
307 | hash->l, sig->v, &sig->l); | |
308 | ||
309 | #endif | |
310 | ||
52b7d2ce A |
311 | |
312 | end: | |
52b7d2ce A |
313 | if (identityRef) |
314 | CFRelease(identityRef); | |
315 | if (privateKeyRef) | |
316 | CFRelease(privateKeyRef); | |
d1e348cf A |
317 | |
318 | #if !TARGET_OS_EMBEDDED | |
319 | if (certificateRef) | |
320 | CFRelease(certificateRef); | |
321 | if (keychainRef) | |
322 | CFRelease(keychainRef); | |
52b7d2ce A |
323 | if (idSearchRef) |
324 | CFRelease(idSearchRef); | |
325 | if (cssmContextHandle) | |
326 | CSSM_DeleteContext(cssmContextHandle); | |
d1e348cf A |
327 | #else |
328 | if (persistFind) | |
329 | CFRelease(persistFind); | |
330 | #endif | |
331 | ||
52b7d2ce A |
332 | if (status != noErr) { |
333 | if (sig) { | |
334 | vfree(sig); | |
335 | sig = NULL; | |
336 | } | |
337 | } | |
338 | ||
339 | if (status != noErr && status != -1) { | |
340 | plog(LLV_ERROR, LOCATION, NULL, | |
341 | "error %d %s.\n", status, GetSecurityErrorString(status)); | |
342 | status = -1; | |
343 | } | |
344 | return sig; | |
345 | ||
346 | } | |
347 | ||
348 | ||
349 | /* | |
350 | * Retrieve a cert from the keychain | |
351 | */ | |
fce29cd9 A |
352 | vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef, |
353 | cert_status_t *certStatus) | |
52b7d2ce A |
354 | { |
355 | ||
356 | OSStatus status; | |
52b7d2ce A |
357 | vchar_t *cert = NULL; |
358 | SecIdentityRef identityRef = NULL; | |
52b7d2ce A |
359 | SecCertificateRef certificateRef = NULL; |
360 | ||
d1e348cf A |
361 | #if !TARGET_OS_EMBEDDED |
362 | CSSM_DATA cssmData; | |
363 | SecIdentitySearchRef idSearchRef = NULL; | |
364 | SecKeychainRef keychainRef = NULL; | |
52b7d2ce A |
365 | |
366 | // get cert ref | |
367 | if (persistentCertRef) { | |
368 | status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef); | |
369 | if (status != noErr) | |
370 | goto end; | |
371 | } else { | |
372 | // copy system keychain | |
373 | status = CopySystemKeychain(&keychainRef); | |
374 | if (status != noErr) | |
375 | goto end; | |
376 | ||
377 | // find first identity in system keychain | |
378 | status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef); | |
379 | if (status != noErr) | |
380 | goto end; | |
381 | ||
382 | status = SecIdentitySearchCopyNext(idSearchRef, &identityRef); | |
383 | if (status != noErr) | |
384 | goto end; | |
385 | ||
386 | // get certificate from identity | |
387 | status = SecIdentityCopyCertificate(identityRef, &certificateRef); | |
388 | if (status != noErr) | |
389 | goto end; | |
390 | ||
391 | } | |
d1e348cf | 392 | |
52b7d2ce A |
393 | // get certificate data |
394 | cssmData.Length = 0; | |
395 | cssmData.Data = NULL; | |
396 | status = SecCertificateGetData(certificateRef, &cssmData); | |
397 | if (status != noErr) | |
398 | goto end; | |
399 | ||
400 | if (cssmData.Length == 0) | |
401 | goto end; | |
402 | ||
403 | cert = vmalloc(cssmData.Length); | |
404 | if (cert == NULL) | |
405 | goto end; | |
406 | ||
407 | // cssmData struct just points to the data | |
408 | // data must be copied to be returned | |
409 | memcpy(cert->v, cssmData.Data, cssmData.Length); | |
d1e348cf | 410 | |
fce29cd9 A |
411 | // verify expiry or missing fields |
412 | if (certStatus) { | |
413 | *certStatus = CERT_STATUS_OK; | |
414 | } | |
d1e348cf A |
415 | #else |
416 | ||
417 | CFDictionaryRef persistFind = NULL; | |
418 | const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef }; | |
419 | const void *values_persist[] = { kCFBooleanTrue, persistentCertRef }; | |
420 | size_t dataLen; | |
421 | CFDataRef certData = NULL; | |
fce29cd9 A |
422 | CFAbsoluteTime timeNow = 0; |
423 | CFAbsoluteTime notvalidbeforedate = 0; | |
424 | CFAbsoluteTime notvalidafterdate = 0; | |
425 | CFDateRef nowcfdatedata = NULL; | |
426 | CFDateRef notvalidbeforedatedata = NULL; | |
427 | CFDateRef notvalidafterdatedata = NULL; | |
428 | CFArrayRef certProparray = NULL; | |
429 | CFRange range; | |
430 | CFDictionaryRef *values = NULL; | |
431 | CFDictionaryRef propDict = NULL; | |
432 | const void *datevalue = NULL; | |
433 | const void *labelvalue = NULL; | |
434 | CFGregorianDate gregoriandate; | |
435 | int count; | |
436 | int i; | |
d1e348cf A |
437 | |
438 | /* find identity by persistent ref */ | |
439 | persistFind = CFDictionaryCreate(NULL, keys_persist, values_persist, | |
440 | (sizeof(keys_persist) / sizeof(*keys_persist)), NULL, NULL); | |
441 | if (persistFind == NULL) | |
442 | goto end; | |
443 | ||
444 | status = SecItemCopyMatching(persistFind, (CFTypeRef *)&identityRef); | |
445 | if (status != noErr) | |
446 | goto end; | |
447 | ||
448 | status = SecIdentityCopyCertificate(identityRef, &certificateRef); | |
449 | if (status != noErr) | |
450 | goto end; | |
451 | ||
452 | certData = SecCertificateCopyData(certificateRef); | |
453 | if (certData == NULL) | |
454 | goto end; | |
455 | ||
456 | dataLen = CFDataGetLength(certData); | |
457 | if (dataLen == 0) | |
458 | goto end; | |
459 | ||
460 | cert = vmalloc(dataLen); | |
461 | if (cert == NULL) | |
462 | goto end; | |
463 | ||
464 | CFDataGetBytes(certData, CFRangeMake(0, dataLen), cert->v); | |
465 | ||
fce29cd9 A |
466 | // verify expiry or missing fields |
467 | if (certStatus) { | |
468 | ||
469 | *certStatus = CERT_STATUS_OK; | |
470 | ||
471 | if ((certProparray = SecCertificateCopyProperties(certificateRef))){ | |
472 | if ((count = CFArrayGetCount( certProparray ))){ | |
473 | range.location = 0; | |
474 | range.length = count; | |
475 | if ( (values = CFAllocatorAllocate(NULL, count * sizeof(CFDictionaryRef), 0))){ | |
476 | CFArrayGetValues(certProparray, range, (const void **)values); | |
477 | for( i = 0; i < count; i++) | |
478 | { | |
479 | if ((propDict = values[i])){ | |
480 | if ( CFDictionaryContainsValue(propDict, kSecPropertyTypeDate) ){ | |
481 | if ( CFDictionaryGetValueIfPresent(propDict, kSecPropertyKeyValue, (const void**)&datevalue)){ | |
482 | /* get kSecPropertyKeyLabel */ | |
483 | if ( (datevalue) && (CFDictionaryGetValueIfPresent(propDict, kSecPropertyKeyLabel, (const void**)&labelvalue))){ | |
484 | if ( (labelvalue) && (CFStringCompare( (CFStringRef)labelvalue, CFSTR("Not Valid Before"), 0) == kCFCompareEqualTo)){ | |
485 | if ( notvalidbeforedate = CFDateGetAbsoluteTime(datevalue)) | |
486 | notvalidbeforedatedata = CFDateCreate(NULL, notvalidbeforedate); | |
487 | }else if ((labelvalue) && (CFStringCompare( (CFStringRef)labelvalue, CFSTR("Not Valid After"), 0 ) == kCFCompareEqualTo)){ | |
488 | if ( notvalidafterdate = CFDateGetAbsoluteTime(datevalue)) | |
489 | notvalidafterdatedata = CFDateCreate(NULL, notvalidafterdate); | |
490 | } | |
491 | } | |
492 | } | |
493 | } | |
494 | } | |
495 | ||
496 | } | |
497 | } | |
498 | } | |
499 | } | |
500 | ||
501 | if ( (timeNow = CFAbsoluteTimeGetCurrent()) && (nowcfdatedata = CFDateCreate( NULL, timeNow))){ | |
502 | if ( notvalidbeforedatedata ){ | |
503 | gregoriandate = CFAbsoluteTimeGetGregorianDate(notvalidbeforedate, NULL); | |
504 | plog(LLV_DEBUG, LOCATION, NULL, | |
505 | "cert not valid before yr %d, mon %d, days %d, hours %d, min %d\n", gregoriandate.year, gregoriandate.month, gregoriandate.day, gregoriandate.hour, gregoriandate.minute); | |
506 | gregoriandate = CFAbsoluteTimeGetGregorianDate(notvalidafterdate, NULL); | |
507 | plog(LLV_DEBUG, LOCATION, NULL, | |
508 | "cert not valid after yr %d, mon %d, days %d, hours %d, min %d\n", gregoriandate.year, gregoriandate.month, gregoriandate.day, gregoriandate.hour, gregoriandate.minute); | |
509 | if ( CFDateCompare( nowcfdatedata, notvalidbeforedatedata, NULL ) == kCFCompareLessThan){ | |
510 | plog(LLV_ERROR, LOCATION, NULL, | |
511 | "current time before valid time\n"); | |
512 | *certStatus = CERT_STATUS_PREMATURE; | |
513 | } | |
514 | else if (notvalidafterdatedata && (CFDateCompare( nowcfdatedata, notvalidafterdatedata, NULL ) == kCFCompareGreaterThan)){ | |
515 | plog(LLV_ERROR, LOCATION, NULL, | |
516 | "current time after valid time\n"); | |
517 | *certStatus = CERT_STATUS_EXPIRED; | |
518 | }else { | |
519 | plog(LLV_INFO, LOCATION, NULL, "certificate expiration date OK\n"); | |
520 | *certStatus = CERT_STATUS_OK; | |
521 | } | |
522 | ||
523 | } | |
524 | ||
525 | } | |
526 | } | |
527 | ||
d1e348cf | 528 | #endif |
52b7d2ce A |
529 | |
530 | end: | |
531 | if (certificateRef) | |
532 | CFRelease(certificateRef); | |
533 | if (identityRef) | |
534 | CFRelease(identityRef); | |
d1e348cf | 535 | #if !TARGET_OS_EMBEDDED |
52b7d2ce A |
536 | if (idSearchRef) |
537 | CFRelease(idSearchRef); | |
538 | if (keychainRef) | |
539 | CFRelease(keychainRef); | |
d1e348cf | 540 | #else |
fce29cd9 A |
541 | if (notvalidbeforedatedata) |
542 | CFRelease(notvalidbeforedatedata); | |
543 | if (notvalidafterdatedata) | |
544 | CFRelease(notvalidafterdatedata); | |
545 | if (certProparray) | |
546 | CFRelease(certProparray); | |
547 | if (values) | |
548 | CFAllocatorDeallocate(NULL, values); | |
549 | if (nowcfdatedata) | |
550 | CFRelease(nowcfdatedata); | |
d1e348cf A |
551 | if (persistFind) |
552 | CFRelease(persistFind); | |
553 | if (certData) | |
554 | CFRelease(certData); | |
555 | #endif | |
556 | ||
52b7d2ce A |
557 | if (status != noErr && status != -1) { |
558 | plog(LLV_ERROR, LOCATION, NULL, | |
559 | "error %d %s.\n", status, GetSecurityErrorString(status)); | |
560 | status = -1; | |
561 | } | |
562 | return cert; | |
563 | ||
564 | } | |
565 | ||
d1e348cf | 566 | #if !TARGET_OS_EMBEDDED |
52b7d2ce A |
567 | /* |
568 | * Find a policy ref by OID | |
569 | */ | |
570 | static OSStatus FindPolicy(const CSSM_OID *policyOID, SecPolicyRef *policyRef) | |
571 | { | |
572 | ||
573 | OSStatus status; | |
574 | SecPolicySearchRef searchRef = nil; | |
575 | ||
576 | status = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &searchRef); | |
577 | if (status != noErr) | |
578 | goto end; | |
579 | ||
580 | status = SecPolicySearchCopyNext(searchRef, policyRef); | |
581 | ||
582 | end: | |
583 | if (searchRef) | |
584 | CFRelease(searchRef); | |
585 | ||
586 | if (status != noErr) { | |
587 | plog(LLV_ERROR, LOCATION, NULL, | |
588 | "error %d %s.\n", status, GetSecurityErrorString(status)); | |
589 | status = -1; | |
590 | } | |
591 | return status; | |
592 | } | |
d1e348cf | 593 | #endif |
52b7d2ce A |
594 | |
595 | /* | |
596 | * Evaluate the trust of a cert using the policy provided | |
597 | */ | |
598 | static OSStatus EvaluateCert(SecCertificateRef cert, CFTypeRef policyRef) | |
599 | { | |
600 | OSStatus status; | |
601 | SecTrustRef trustRef = 0; | |
602 | SecTrustResultType evalResult; | |
fce29cd9 A |
603 | |
604 | #if TARGET_OS_EMBEDDED | |
605 | CFArrayRef errorStrings; | |
606 | #else | |
607 | CSSM_TP_APPLE_EVIDENCE_INFO *statusChain; | |
608 | CFArrayRef certChain; | |
609 | #endif | |
52b7d2ce A |
610 | |
611 | SecCertificateRef evalCertArray[1] = { cert }; | |
612 | ||
d1e348cf A |
613 | CFArrayRef cfCertRef = CFArrayCreate((CFAllocatorRef) NULL, (void*)evalCertArray, 1, |
614 | &kCFTypeArrayCallBacks); | |
52b7d2ce A |
615 | |
616 | if (!cfCertRef) { | |
617 | plog(LLV_ERROR, LOCATION, NULL, | |
618 | "unable to create CFArray.\n"); | |
619 | return -1; | |
620 | } | |
621 | ||
622 | status = SecTrustCreateWithCertificates(cfCertRef, policyRef, &trustRef); | |
623 | if (status != noErr) | |
624 | goto end; | |
fce29cd9 | 625 | |
52b7d2ce A |
626 | status = SecTrustEvaluate(trustRef, &evalResult); |
627 | if (status != noErr) | |
628 | goto end; | |
629 | ||
630 | if (evalResult != kSecTrustResultProceed && evalResult != kSecTrustResultUnspecified) { | |
fce29cd9 A |
631 | plog(LLV_ERROR, LOCATION, NULL, "Error evaluating certificate.\n"); |
632 | ||
633 | switch (evalResult) { | |
634 | case kSecTrustResultInvalid: | |
635 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultInvalid.\n"); | |
636 | break; | |
637 | case kSecTrustResultProceed: | |
638 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultProceed.\n"); | |
639 | break; | |
640 | case kSecTrustResultConfirm: | |
641 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultConfirm.\n"); | |
642 | break; | |
643 | case kSecTrustResultDeny: | |
644 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultDeny.\n"); | |
645 | break; | |
646 | case kSecTrustResultUnspecified: | |
647 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultUnspecified.\n"); | |
648 | break; | |
649 | case kSecTrustResultRecoverableTrustFailure: | |
650 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultRecoverableTrustFailure.\n"); | |
651 | break; | |
652 | case kSecTrustResultFatalTrustFailure: | |
653 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultFatalTrustFailure.\n"); | |
654 | break; | |
655 | case kSecTrustResultOtherError: | |
656 | plog(LLV_DEBUG, LOCATION, NULL, "eval result = kSecTrustResultOtherError.\n"); | |
657 | break; | |
658 | default: | |
659 | plog(LLV_DEBUG, LOCATION, NULL, "eval result unknown: value = %d.\n", (int)evalResult); | |
660 | break; | |
661 | } | |
662 | ||
663 | ||
664 | #if TARGET_OS_EMBEDDED | |
665 | errorStrings = SecTrustCopyProperties(trustRef); | |
666 | if (errorStrings) { | |
667 | ||
668 | CFDictionaryRef dict; | |
669 | CFStringRef val; | |
670 | const char *str; | |
671 | CFIndex count, maxcount = CFArrayGetCount(errorStrings); | |
672 | ||
673 | plog(LLV_ERROR, LOCATION, NULL, "---------------Returned error strings: ---------------.\n"); | |
674 | for (count = 0; count < maxcount; count++) { | |
675 | dict = CFArrayGetValueAtIndex(errorStrings, count); | |
676 | if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) { | |
677 | val = CFDictionaryGetValue(dict, kSecPropertyKeyType); | |
678 | if (val && (CFGetTypeID(val) == CFStringGetTypeID())) { | |
679 | str = CFStringGetCStringPtr(val, kCFStringEncodingMacRoman); | |
680 | if (str) | |
681 | plog(LLV_ERROR, LOCATION, NULL, "type = %s.\n", str); | |
682 | } | |
683 | val = CFDictionaryGetValue(dict, kSecPropertyKeyValue); | |
684 | if (val && (CFGetTypeID(val) == CFStringGetTypeID())) { | |
685 | str = CFStringGetCStringPtr(val, kCFStringEncodingMacRoman); | |
686 | if (str) | |
687 | plog(LLV_ERROR, LOCATION, NULL, "value = %s.\n", str); | |
688 | } | |
689 | } | |
690 | } | |
691 | plog(LLV_ERROR, LOCATION, NULL, "-----------------------------------------------------.\n"); | |
692 | CFRelease(errorStrings); | |
693 | } | |
694 | ||
695 | #else | |
696 | SecTrustGetResult(trustRef, &evalResult, &certChain, &statusChain); | |
697 | plog(LLV_ERROR, LOCATION, NULL, "Cert status bits = 0x%x.\n", statusChain->StatusBits); | |
698 | plog(LLV_ERROR, LOCATION, NULL, "Cert status NumStatusCodes = 0x%x.\n", statusChain->NumStatusCodes); | |
699 | { | |
700 | int i; | |
701 | for (i = 0; i < statusChain->NumStatusCodes; i++) | |
702 | plog(LLV_ERROR, LOCATION, NULL, "Cert status code i = 0x%x %d.\n", *(statusChain->StatusCodes + i), *(statusChain->StatusCodes + i)); | |
703 | } | |
704 | plog(LLV_ERROR, LOCATION, NULL, "Cert status Index = %d.\n", statusChain->Index); | |
705 | CFRelease(certChain); | |
706 | #endif | |
707 | ||
52b7d2ce A |
708 | status = -1; |
709 | } | |
710 | ||
711 | ||
712 | end: | |
713 | if (cfCertRef) | |
714 | CFRelease(cfCertRef); | |
715 | if (trustRef) | |
716 | CFRelease(trustRef); | |
717 | ||
718 | if (status != noErr && status != -1) { | |
719 | plog(LLV_ERROR, LOCATION, NULL, | |
720 | "error %d %s.\n", status, GetSecurityErrorString(status)); | |
721 | status = -1; | |
722 | } | |
723 | return status; | |
724 | } | |
725 | ||
d1e348cf | 726 | #if !TARGET_OS_EMBEDDED |
52b7d2ce A |
727 | /* |
728 | * Copy the system keychain | |
729 | */ | |
730 | static OSStatus CopySystemKeychain(SecKeychainRef *keychainRef) | |
731 | { | |
732 | ||
733 | OSStatus status; | |
734 | ||
735 | status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); | |
736 | if (status != noErr) | |
737 | goto end; | |
738 | ||
739 | status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, keychainRef); | |
740 | ||
741 | end: | |
742 | ||
743 | if (status != noErr) { | |
744 | plog(LLV_ERROR, LOCATION, NULL, | |
745 | "error %d %s.\n", status, GetSecurityErrorString(status)); | |
746 | status = -1; | |
747 | } | |
748 | return status; | |
749 | ||
750 | } | |
d1e348cf | 751 | #endif |
52b7d2ce A |
752 | |
753 | /* | |
754 | * Return string representation of Security-related OSStatus. | |
755 | */ | |
756 | const char * | |
757 | GetSecurityErrorString(OSStatus err) | |
758 | { | |
759 | switch(err) { | |
760 | case noErr: | |
761 | return "noErr"; | |
762 | case memFullErr: | |
763 | return "memFullErr"; | |
764 | case paramErr: | |
765 | return "paramErr"; | |
766 | case unimpErr: | |
767 | return "unimpErr"; | |
768 | ||
769 | /* SecBase.h: */ | |
770 | case errSecNotAvailable: | |
771 | return "errSecNotAvailable"; | |
d1e348cf | 772 | #if !TARGET_OS_EMBEDDED |
52b7d2ce A |
773 | case errSecReadOnly: |
774 | return "errSecReadOnly"; | |
775 | case errSecAuthFailed: | |
776 | return "errSecAuthFailed"; | |
777 | case errSecNoSuchKeychain: | |
778 | return "errSecNoSuchKeychain"; | |
779 | case errSecInvalidKeychain: | |
780 | return "errSecInvalidKeychain"; | |
781 | case errSecDuplicateKeychain: | |
782 | return "errSecDuplicateKeychain"; | |
783 | case errSecDuplicateCallback: | |
784 | return "errSecDuplicateCallback"; | |
785 | case errSecInvalidCallback: | |
786 | return "errSecInvalidCallback"; | |
52b7d2ce A |
787 | case errSecBufferTooSmall: |
788 | return "errSecBufferTooSmall"; | |
789 | case errSecDataTooLarge: | |
790 | return "errSecDataTooLarge"; | |
791 | case errSecNoSuchAttr: | |
792 | return "errSecNoSuchAttr"; | |
793 | case errSecInvalidItemRef: | |
794 | return "errSecInvalidItemRef"; | |
795 | case errSecInvalidSearchRef: | |
796 | return "errSecInvalidSearchRef"; | |
797 | case errSecNoSuchClass: | |
798 | return "errSecNoSuchClass"; | |
799 | case errSecNoDefaultKeychain: | |
800 | return "errSecNoDefaultKeychain"; | |
801 | case errSecInteractionNotAllowed: | |
802 | return "errSecInteractionNotAllowed"; | |
803 | case errSecReadOnlyAttr: | |
804 | return "errSecReadOnlyAttr"; | |
805 | case errSecWrongSecVersion: | |
806 | return "errSecWrongSecVersion"; | |
807 | case errSecKeySizeNotAllowed: | |
808 | return "errSecKeySizeNotAllowed"; | |
809 | case errSecNoStorageModule: | |
810 | return "errSecNoStorageModule"; | |
811 | case errSecNoCertificateModule: | |
812 | return "errSecNoCertificateModule"; | |
813 | case errSecNoPolicyModule: | |
814 | return "errSecNoPolicyModule"; | |
815 | case errSecInteractionRequired: | |
816 | return "errSecInteractionRequired"; | |
817 | case errSecDataNotAvailable: | |
818 | return "errSecDataNotAvailable"; | |
819 | case errSecDataNotModifiable: | |
820 | return "errSecDataNotModifiable"; | |
821 | case errSecCreateChainFailed: | |
822 | return "errSecCreateChainFailed"; | |
823 | case errSecACLNotSimple: | |
824 | return "errSecACLNotSimple"; | |
825 | case errSecPolicyNotFound: | |
826 | return "errSecPolicyNotFound"; | |
827 | case errSecInvalidTrustSetting: | |
828 | return "errSecInvalidTrustSetting"; | |
829 | case errSecNoAccessForItem: | |
830 | return "errSecNoAccessForItem"; | |
831 | case errSecInvalidOwnerEdit: | |
832 | return "errSecInvalidOwnerEdit"; | |
d1e348cf A |
833 | #endif |
834 | case errSecDuplicateItem: | |
835 | return "errSecDuplicateItem"; | |
836 | case errSecItemNotFound: | |
837 | return "errSecItemNotFound"; | |
52b7d2ce A |
838 | default: |
839 | return "<unknown>"; | |
840 | } | |
841 | } | |
842 |