3 * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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.
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
21 * @APPLE_LICENSE_HEADER_END@
26 * Racoon module for verifying and signing certificates through Security
30 #include <Security/SecCertificate.h>
31 #include <Security/SecPolicy.h>
32 #include <Security/SecTrust.h>
33 #include <Security/SecKey.h>
34 #include <Security/SecIdentity.h>
35 #include <Security/SecItem.h>
36 #include <TargetConditionals.h>
37 #include <Security/SecItemPriv.h>
38 #if TARGET_OS_EMBEDDED
39 #include <Security/SecTrustPriv.h>
40 #include <Security/SecPolicyPriv.h>
41 #include <Security/SecCertificatePriv.h>
43 #include <Security/SecBase.h>
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>
49 #include <Security/SecCertificateOIDs.h>
50 #include <Security/SecKeyPriv.h>
51 #include <Security/oidsalg.h>
52 #include <Security/cssmapi.h>
53 #include <Security/SecPolicySearch.h>
55 #include <CoreFoundation/CoreFoundation.h>
56 #if !TARGET_OS_EMBEDDED
57 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
66 #include "crypto_cssm.h"
69 static OSStatus
EvaluateCert(SecCertificateRef evalCertArray
[], CFIndex evalCertArrayNumValues
, CFTypeRef policyRef
, SecKeyRef
*publicKeyRef
);
71 #if !TARGET_OS_EMBEDDED
75 crypto_cssm_x509cert_get_SecPolicyRef (CFStringRef hostname
)
77 SecPolicyRef policyRef
= NULL
;
78 CFDictionaryRef properties
= NULL
;
79 const void *key
[] = { kSecPolicyName
};
80 const void *value
[] = { hostname
};
83 properties
= CFDictionaryCreate(NULL
, key
, value
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
84 if (properties
== NULL
) {
86 "unable to create dictionary for policy properties.\n");
89 policyRef
= SecPolicyCreateWithProperties(kSecPolicyAppleIPsec
, properties
);
91 CFRelease(properties
);
96 crypto_cssm_x509cert_CreateSecCertificateRef (vchar_t
*cert
)
98 SecCertificateRef certRef
= NULL
;
100 CFDataRef cert_data
= CFDataCreateWithBytesNoCopy(NULL
, (uint8_t*)cert
->v
, cert
->l
, kCFAllocatorNull
);
102 certRef
= SecCertificateCreateWithData(NULL
, cert_data
);
103 CFRelease(cert_data
);
106 if (certRef
== NULL
) {
108 "unable to get a certifcate reference.\n");
113 /* HACK!!! - temporary until this prototype gets moved */
114 extern CFDataRef
SecCertificateCopySubjectSequence( SecCertificateRef certificate
);
117 crypto_cssm_CopySubjectSequence(SecCertificateRef certRef
)
119 CFDataRef subject
= NULL
;
121 subject
= SecCertificateCopySubjectSequence(certRef
);
128 crypto_cssm_check_x509cert_dates (SecCertificateRef certificateRef
)
130 cert_status_t certStatus
= CERT_STATUS_OK
;
131 #if TARGET_OS_EMBEDDED
132 CFAbsoluteTime timeNow
= 0;
133 CFAbsoluteTime notvalidbeforedate
= 0;
134 CFAbsoluteTime notvalidafterdate
= 0;
135 CFDateRef nowcfdatedata
= NULL
;
136 CFDateRef notvalidbeforedatedata
= NULL
;
137 CFDateRef notvalidafterdatedata
= NULL
;
138 CFArrayRef certProparray
= NULL
;
139 CFDictionaryRef propDict
= NULL
;
140 const void *datevalue
= NULL
;
141 const void *labelvalue
= NULL
;
142 CFGregorianDate gregoriandate
;
146 if ((certProparray
= SecCertificateCopyProperties(certificateRef
))){
147 if ((count
= CFArrayGetCount( certProparray
))){
148 for( i
= 0; i
< count
; i
++) {
149 if ((propDict
= CFArrayGetValueAtIndex(certProparray
, i
))) {
150 if ( CFDictionaryGetValueIfPresent(propDict
, kSecPropertyKeyValue
, (const void**)&datevalue
)){
151 /* get kSecPropertyKeyLabel */
152 if ( (datevalue
) && (CFDictionaryGetValueIfPresent(propDict
, kSecPropertyKeyLabel
, (const void**)&labelvalue
))){
153 if ( (labelvalue
) && (CFStringCompare( (CFStringRef
)labelvalue
, CFSTR("Not Valid Before"), 0) == kCFCompareEqualTo
)){
154 if ( (notvalidbeforedate
= CFDateGetAbsoluteTime(datevalue
))) {
155 if (notvalidbeforedatedata
) {
156 CFRelease(notvalidbeforedatedata
);
158 notvalidbeforedatedata
= CFDateCreate(NULL
, notvalidbeforedate
);
160 }else if ((labelvalue
) && (CFStringCompare( (CFStringRef
)labelvalue
, CFSTR("Not Valid After"), 0 ) == kCFCompareEqualTo
)){
161 if ( (notvalidafterdate
= CFDateGetAbsoluteTime(datevalue
))) {
162 if (notvalidafterdatedata
) {
163 CFRelease(notvalidafterdatedata
);
165 notvalidafterdatedata
= CFDateCreate(NULL
, notvalidafterdate
);
175 if ( (timeNow
= CFAbsoluteTimeGetCurrent()) && (nowcfdatedata
= CFDateCreate( NULL
, timeNow
))){
176 if ( notvalidbeforedatedata
){
177 gregoriandate
= CFAbsoluteTimeGetGregorianDate(notvalidbeforedate
, NULL
);
178 plog(ASL_LEVEL_DEBUG
,
179 "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
);
180 gregoriandate
= CFAbsoluteTimeGetGregorianDate(notvalidafterdate
, NULL
);
181 plog(ASL_LEVEL_DEBUG
,
182 "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
);
183 if ( CFDateCompare( nowcfdatedata
, notvalidbeforedatedata
, NULL
) == kCFCompareLessThan
){
185 "current time before valid time\n");
186 certStatus
= CERT_STATUS_PREMATURE
;
187 } else if (notvalidafterdatedata
&& (CFDateCompare( nowcfdatedata
, notvalidafterdatedata
, NULL
) == kCFCompareGreaterThan
)){
189 "current time after valid time\n");
190 certStatus
= CERT_STATUS_EXPIRED
;
192 plog(ASL_LEVEL_INFO
, "Certificate expiration date is OK\n");
193 certStatus
= CERT_STATUS_OK
;
198 if (notvalidbeforedatedata
)
199 CFRelease(notvalidbeforedatedata
);
200 if (notvalidafterdatedata
)
201 CFRelease(notvalidafterdatedata
);
203 CFRelease(certProparray
);
205 CFRelease(nowcfdatedata
);
211 * Verify cert using security framework
213 int crypto_cssm_check_x509cert (cert_t
*hostcert
, cert_t
*certchain
, CFStringRef hostname
, SecKeyRef
*publicKeyRef
)
216 cert_status_t certStatus
= 0;
218 CFIndex certArrayRefNumValues
= 0;
221 SecCertificateRef
*certArrayRef
= NULL
;
222 SecPolicyRef policyRef
= crypto_cssm_x509cert_get_SecPolicyRef(hostname
);
224 if (!hostcert
|| !certchain
) {
228 // find the total number of certs
229 for (p
= certchain
; p
; p
= p
->chain
, n
++);
231 plog(ASL_LEVEL_DEBUG
,
232 "%s: checking chain of %d certificates.\n", __FUNCTION__
, (int)n
);
235 certArraySiz
= n
* sizeof(CFTypeRef
);
236 certArrayRef
= CFAllocatorAllocate(NULL
, certArraySiz
, 0);
240 bzero(certArrayRef
, certArraySiz
);
241 if ((certArrayRef
[certArrayRefNumValues
] = crypto_cssm_x509cert_CreateSecCertificateRef(&hostcert
->cert
))) {
242 /* don't overwrite any pending status */
243 if (!hostcert
->status
) {
244 hostcert
->status
= crypto_cssm_check_x509cert_dates(certArrayRef
[certArrayRefNumValues
]);
245 if (hostcert
->status
) {
247 "host certificate failed date verification: %d.\n", hostcert
->status
);
248 certStatus
= hostcert
->status
;
251 certArrayRefNumValues
++;
253 for (p
= certchain
; p
&& certArrayRefNumValues
< n
; p
= p
->chain
) {
255 if ((certArrayRef
[certArrayRefNumValues
] = crypto_cssm_x509cert_CreateSecCertificateRef(&p
->cert
))) {
256 /* don't overwrite any pending status */
258 p
->status
= crypto_cssm_check_x509cert_dates(certArrayRef
[certArrayRefNumValues
]);
261 "other certificate in chain failed date verification: %d.\n", p
->status
);
263 certStatus
= p
->status
;
267 certArrayRefNumValues
++;
273 status
= EvaluateCert(certArrayRef
, certArrayRefNumValues
, policyRef
, publicKeyRef
);
275 while (certArrayRefNumValues
) {
276 CFRelease(certArrayRef
[--certArrayRefNumValues
]);
278 CFAllocatorDeallocate(NULL
, certArrayRef
);
281 CFRelease(policyRef
);
283 if (status
!= noErr
&& status
!= -1) {
285 "error %d %s.\n", (int)status
, GetSecurityErrorString(status
));
287 } else if (certStatus
== CERT_STATUS_PREMATURE
|| certStatus
== CERT_STATUS_EXPIRED
) {
295 int crypto_cssm_verify_x509sign(SecKeyRef publicKeyRef
, vchar_t
*hash
, vchar_t
*signature
, Boolean useSHA1
)
297 return SecKeyRawVerify(publicKeyRef
, useSHA1
? kSecPaddingPKCS1SHA1
: kSecPaddingPKCS1
, (uint8_t*)hash
->v
, hash
->l
, (uint8_t*)signature
->v
, signature
->l
);
301 * Encrypt a hash via CSSM using the private key in the keychain
304 vchar_t
* crypto_cssm_getsign(CFDataRef persistentCertRef
, vchar_t
* hash
)
307 OSStatus status
= -1;
308 SecIdentityRef identityRef
= NULL
;
309 SecKeyRef privateKeyRef
= NULL
;
313 CFDictionaryRef persistFind
= NULL
;
314 const void *keys_persist
[] = { kSecReturnRef
, kSecValuePersistentRef
, kSecClass
,
315 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
316 kSecUseSystemKeychain
,
319 const void *values_persist
[] = { kCFBooleanTrue
, persistentCertRef
, kSecClassIdentity
,
320 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
325 #define SIG_BUF_SIZE 1024
327 /* find identity by persistent ref */
328 persistFind
= CFDictionaryCreate(NULL
, keys_persist
, values_persist
,
329 (sizeof(keys_persist
) / sizeof(*keys_persist
)), NULL
, NULL
);
330 if (persistFind
== NULL
)
333 status
= SecItemCopyMatching(persistFind
, (CFTypeRef
*)&identityRef
);
337 status
= SecIdentityCopyPrivateKey(identityRef
, &privateKeyRef
);
341 // alloc buffer for result
342 sig
= vmalloc(SIG_BUF_SIZE
);
346 status
= SecKeyRawSign(privateKeyRef
, kSecPaddingPKCS1
, (uint8_t*)hash
->v
,
347 hash
->l
, (uint8_t*)sig
->v
, &sig
->l
);
352 CFRelease(identityRef
);
354 CFRelease(privateKeyRef
);
357 CFRelease(persistFind
);
359 if (status
!= noErr
) {
366 if (status
!= noErr
&& status
!= -1) {
368 "error %d %s.\n", (int)status
, GetSecurityErrorString(status
));
377 * Retrieve a cert from the keychain
379 vchar_t
* crypto_cssm_get_x509cert(CFDataRef persistentCertRef
,
380 cert_status_t
*certStatus
)
383 OSStatus status
= -1;
384 vchar_t
*cert
= NULL
;
385 SecCertificateRef certificateRef
= NULL
;
386 CFDictionaryRef persistFind
= NULL
;
388 CFDataRef certData
= NULL
;
389 SecIdentityRef identityRef
= NULL
;
390 const void *keys_persist
[] = { kSecReturnRef
, kSecValuePersistentRef
, kSecClass
,
391 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
392 kSecUseSystemKeychain
,
395 const void *values_persist
[] = { kCFBooleanTrue
, persistentCertRef
, kSecClassIdentity
,
396 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
401 /* find identity by persistent ref */
402 persistFind
= CFDictionaryCreate(NULL
, keys_persist
, values_persist
,
403 (sizeof(keys_persist
) / sizeof(*keys_persist
)), &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
404 if (persistFind
== NULL
)
407 status
= SecItemCopyMatching(persistFind
, (CFTypeRef
*)&identityRef
);
411 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
415 certData
= SecCertificateCopyData(certificateRef
);
416 if (certData
== NULL
)
419 dataLen
= CFDataGetLength(certData
);
423 cert
= vmalloc(dataLen
);
427 CFDataGetBytes(certData
, CFRangeMake(0, dataLen
), (uint8_t*)cert
->v
);
429 // verify expiry or missing fields
431 *certStatus
= crypto_cssm_check_x509cert_dates(certificateRef
);
436 CFRelease(identityRef
);
438 CFRelease(certificateRef
);
440 CFRelease(persistFind
);
444 if (status
!= noErr
&& status
!= -1) {
446 "error %d %s.\n", (int)status
, GetSecurityErrorString(status
));
454 * Evaluate the trust of a cert using the policy provided
456 static OSStatus
EvaluateCert(SecCertificateRef evalCertArray
[], CFIndex evalCertArrayNumValues
, CFTypeRef policyRef
, SecKeyRef
*publicKeyRef
)
459 SecTrustRef trustRef
= 0;
460 SecTrustResultType evalResult
;
462 CFArrayRef errorStrings
;
464 CFArrayRef cfCertRef
= CFArrayCreate((CFAllocatorRef
) NULL
, (void*)evalCertArray
, evalCertArrayNumValues
,
465 &kCFTypeArrayCallBacks
);
469 "unable to create CFArray.\n");
473 status
= SecTrustCreateWithCertificates(cfCertRef
, policyRef
, &trustRef
);
477 status
= SecTrustEvaluate(trustRef
, &evalResult
);
481 if (evalResult
!= kSecTrustResultProceed
&& evalResult
!= kSecTrustResultUnspecified
) {
482 plog(ASL_LEVEL_ERR
, "Error evaluating certificate.\n");
484 switch (evalResult
) {
485 case kSecTrustResultInvalid
:
486 plog(ASL_LEVEL_DEBUG
, "eval result = kSecTrustResultInvalid.\n");
488 case kSecTrustResultProceed
:
489 plog(ASL_LEVEL_DEBUG
, "eval result = kSecTrustResultProceed.\n");
491 case kSecTrustResultDeny
:
492 plog(ASL_LEVEL_DEBUG
, "eval result = kSecTrustResultDeny.\n");
494 case kSecTrustResultUnspecified
:
495 plog(ASL_LEVEL_DEBUG
, "eval result = kSecTrustResultUnspecified.\n");
497 case kSecTrustResultRecoverableTrustFailure
:
498 plog(ASL_LEVEL_DEBUG
, "eval result = kSecTrustResultRecoverableTrustFailure.\n");
500 case kSecTrustResultFatalTrustFailure
:
501 plog(ASL_LEVEL_DEBUG
, "eval result = kSecTrustResultFatalTrustFailure.\n");
503 case kSecTrustResultOtherError
:
504 plog(ASL_LEVEL_DEBUG
, "eval result = kSecTrustResultOtherError.\n");
507 plog(ASL_LEVEL_DEBUG
, "eval result unknown: value = %d.\n", (int)evalResult
);
511 errorStrings
= SecTrustCopyProperties(trustRef
);
514 CFDictionaryRef dict
;
517 CFIndex count
, maxcount
= CFArrayGetCount(errorStrings
);
519 plog(ASL_LEVEL_ERR
, "---------------Returned error strings: ---------------.\n");
520 for (count
= 0; count
< maxcount
; count
++) {
521 dict
= CFArrayGetValueAtIndex(errorStrings
, count
);
522 if (dict
&& (CFGetTypeID(dict
) == CFDictionaryGetTypeID())) {
523 val
= CFDictionaryGetValue(dict
, kSecPropertyKeyType
);
524 if (val
&& (CFGetTypeID(val
) == CFStringGetTypeID())) {
525 str
= CFStringGetCStringPtr(val
, kCFStringEncodingMacRoman
);
527 plog(ASL_LEVEL_ERR
, "type = %s.\n", str
);
529 val
= CFDictionaryGetValue(dict
, kSecPropertyKeyValue
);
530 if (val
&& (CFGetTypeID(val
) == CFStringGetTypeID())) {
531 str
= CFStringGetCStringPtr(val
, kCFStringEncodingMacRoman
);
533 plog(ASL_LEVEL_ERR
, "value = %s.\n", str
);
537 plog(ASL_LEVEL_ERR
, "-----------------------------------------------------.\n");
538 CFRelease(errorStrings
);
545 /* get and return the public key */
546 *publicKeyRef
= SecTrustCopyPublicKey(trustRef
);
550 CFRelease(cfCertRef
);
554 if (status
!= noErr
&& status
!= -1) {
556 "error %d %s.\n", (int)status
, GetSecurityErrorString(status
));
563 * Return string representation of Security-related OSStatus.
566 GetSecurityErrorString(OSStatus err
)
573 case errSecNotAvailable
:
574 return "errSecNotAvailable";
576 #if !TARGET_OS_EMBEDDED
586 return "errSecReadOnly";
587 case errSecAuthFailed
:
588 return "errSecAuthFailed";
589 case errSecNoSuchKeychain
:
590 return "errSecNoSuchKeychain";
591 case errSecInvalidKeychain
:
592 return "errSecInvalidKeychain";
593 case errSecDuplicateKeychain
:
594 return "errSecDuplicateKeychain";
595 case errSecDuplicateCallback
:
596 return "errSecDuplicateCallback";
597 case errSecInvalidCallback
:
598 return "errSecInvalidCallback";
599 case errSecBufferTooSmall
:
600 return "errSecBufferTooSmall";
601 case errSecDataTooLarge
:
602 return "errSecDataTooLarge";
603 case errSecNoSuchAttr
:
604 return "errSecNoSuchAttr";
605 case errSecInvalidItemRef
:
606 return "errSecInvalidItemRef";
607 case errSecInvalidSearchRef
:
608 return "errSecInvalidSearchRef";
609 case errSecNoSuchClass
:
610 return "errSecNoSuchClass";
611 case errSecNoDefaultKeychain
:
612 return "errSecNoDefaultKeychain";
613 case errSecInteractionNotAllowed
:
614 return "errSecInteractionNotAllowed";
615 case errSecReadOnlyAttr
:
616 return "errSecReadOnlyAttr";
617 case errSecWrongSecVersion
:
618 return "errSecWrongSecVersion";
619 case errSecKeySizeNotAllowed
:
620 return "errSecKeySizeNotAllowed";
621 case errSecNoStorageModule
:
622 return "errSecNoStorageModule";
623 case errSecNoCertificateModule
:
624 return "errSecNoCertificateModule";
625 case errSecNoPolicyModule
:
626 return "errSecNoPolicyModule";
627 case errSecInteractionRequired
:
628 return "errSecInteractionRequired";
629 case errSecDataNotAvailable
:
630 return "errSecDataNotAvailable";
631 case errSecDataNotModifiable
:
632 return "errSecDataNotModifiable";
633 case errSecCreateChainFailed
:
634 return "errSecCreateChainFailed";
635 case errSecACLNotSimple
:
636 return "errSecACLNotSimple";
637 case errSecPolicyNotFound
:
638 return "errSecPolicyNotFound";
639 case errSecInvalidTrustSetting
:
640 return "errSecInvalidTrustSetting";
641 case errSecNoAccessForItem
:
642 return "errSecNoAccessForItem";
643 case errSecInvalidOwnerEdit
:
644 return "errSecInvalidOwnerEdit";
646 case errSecDuplicateItem
:
647 return "errSecDuplicateItem";
648 case errSecItemNotFound
:
649 return "errSecItemNotFound";