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