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>
36 #include <TargetConditionals.h>
37 #if TARGET_OS_EMBEDDED
38 #include <Security/SecItem.h>
40 #include <Security/SecBase.h>
41 #include <Security/SecIdentityPriv.h>
42 #include <Security/SecIdentitySearch.h>
43 #include <Security/SecKeychain.h>
44 #include <Security/SecKeychainItem.h>
45 #include <Security/SecKeychainItemPriv.h>
47 #include <Security/SecKeyPriv.h>
48 #include <Security/oidsalg.h>
49 #include <Security/cssmapi.h>
50 #include <Security/SecPolicySearch.h>
53 #include <CoreFoundation/CoreFoundation.h>
54 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
60 #include "crypto_cssm.h"
63 static OSStatus
EvaluateCert(SecCertificateRef cert
, CFTypeRef policyRef
);
64 static const char *GetSecurityErrorString(OSStatus err
);
65 #if !TARGET_OS_EMBEDDED
66 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
);
67 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
);
71 * Verify cert using security framework
73 int crypto_cssm_check_x509cert(vchar_t
*cert
, CFStringRef hostname
)
76 SecCertificateRef certRef
= NULL
;
77 SecPolicyRef policyRef
= NULL
;
79 #if !TARGET_OS_EMBEDDED
81 CSSM_OID ourPolicyOID
= CSSMOID_APPLE_TP_IP_SEC
;
84 certData
.Length
= cert
->l
;
85 certData
.Data
= (uint8
*)cert
->v
;
86 status
= SecCertificateCreateFromData(&certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
,
91 // get our policy object
92 status
= FindPolicy(&ourPolicyOID
, &policyRef
);
95 // no options used at present - verification of subjectAltName fields, etc.
96 // are done elsewhere in racoon in oakley_check_certid()
99 CFDataRef cert_data
= CFDataCreateWithBytesNoCopy(NULL
, cert
->v
, cert
->l
, kCFAllocatorNull
);
101 certRef
= SecCertificateCreateWithData(NULL
, cert_data
);
102 CFRelease(cert_data
);
105 if (certRef
== NULL
) {
106 plog(LLV_ERROR
, LOCATION
, NULL
,
107 "unable to create a certRef.\n");
113 policyRef
= SecPolicyCreateSSL(FALSE
, hostname
);
114 if (policyRef
== NULL
) {
115 plog(LLV_ERROR
, LOCATION
, NULL
,
116 "unable to create a SSL policyRef.\n");
122 policyRef
= SecPolicyCreateBasicX509();
123 if (policyRef
== NULL
) {
124 plog(LLV_ERROR
, LOCATION
, NULL
,
125 "unable to create a Basic X509 policyRef.\n");
134 status
= EvaluateCert(certRef
, policyRef
);
141 CFRelease(policyRef
);
143 if (status
!= noErr
&& status
!= -1) {
144 plog(LLV_ERROR
, LOCATION
, NULL
,
145 "error %d %s.\n", status
, GetSecurityErrorString(status
));
153 * Encrypt a hash via CSSM using the private key in the keychain
156 vchar_t
* crypto_cssm_getsign(CFDataRef persistentCertRef
, vchar_t
* hash
)
160 SecIdentityRef identityRef
= NULL
;
161 SecKeyRef privateKeyRef
= NULL
;
164 #if !TARGET_OS_EMBEDDED
165 u_int32_t bytesEncrypted
= 0;
166 SecCertificateRef certificateRef
= NULL
;
167 SecIdentitySearchRef idSearchRef
= NULL
;
168 SecKeychainRef keychainRef
= NULL
;
169 const CSSM_KEY
*cssmKey
= NULL
;
170 CSSM_CSP_HANDLE cspHandle
= nil
;
171 CSSM_CC_HANDLE cssmContextHandle
= nil
;
172 const CSSM_ACCESS_CREDENTIALS
*credentials
= NULL
;
173 //CSSM_SIZE bytesEncrypted = 0; //%%%%HWR fix this - need new headers on Leopard
175 CSSM_DATA cipherData
;
177 CSSM_CONTEXT_ATTRIBUTE newAttr
;
182 if (persistentCertRef
) {
183 // get cert from keychain
184 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
188 // get keychain ref where cert is contained
189 status
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)certificateRef
, &keychainRef
);
193 // get identity from the certificate
194 status
= SecIdentityCreateWithCertificate(keychainRef
, certificateRef
, &identityRef
);
200 // copy system keychain
201 status
= CopySystemKeychain(&keychainRef
);
205 // serach for first identity in system keychain
206 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
210 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
214 // get certificate from identity
215 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
220 // get private key from identity
221 status
= SecIdentityCopyPrivateKey(identityRef
, &privateKeyRef
);
225 // get CSSM_KEY pointer from key ref
226 status
= SecKeyGetCSSMKey(privateKeyRef
, &cssmKey
);
230 // get CSSM CSP handle
231 status
= SecKeychainGetCSPHandle(keychainRef
, &cspHandle
);
235 // create CSSM credentials to unlock private key for encryption - no UI to be used
236 status
= SecKeyGetCredentials(privateKeyRef
, CSSM_ACL_AUTHORIZATION_ENCRYPT
,
237 kSecCredentialTypeNoUI
, &credentials
);
241 // create asymmetric context for encryption
242 status
= CSSM_CSP_CreateAsymmetricContext(cspHandle
, CSSM_ALGID_RSA
, credentials
, cssmKey
,
243 CSSM_PADDING_PKCS1
, &cssmContextHandle
);
247 // add mode attribute to use private key for encryption
248 newAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
249 newAttr
.AttributeLength
= sizeof(uint32
);
250 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)CSSM_ALGMODE_PRIVATE_KEY
;
251 status
= CSSM_UpdateContextAttributes(cssmContextHandle
, 1, &newAttr
);
255 // and finally - encrypt data
256 clearData
.Length
= hash
->l
;
257 clearData
.Data
= (uint8
*)hash
->v
;
258 cipherData
.Length
= 0;
259 cipherData
.Data
= NULL
;
260 status
= CSSM_EncryptData(cssmContextHandle
, &clearData
, 1, &cipherData
, 1, &bytesEncrypted
,
265 if (remData
.Length
!= 0) { // something didn't go right - should be zero
267 plog(LLV_ERROR
, LOCATION
, NULL
,
268 "unencrypted data remaining after encrypting hash.\n");
272 // alloc buffer for result
277 sig
->l
= cipherData
.Length
;
278 sig
->v
= (caddr_t
)cipherData
.Data
;
282 CFDictionaryRef persistFind
= NULL
;
283 const void *keys_persist
[] = { kSecReturnRef
, kSecValuePersistentRef
};
284 const void *values_persist
[] = { kCFBooleanTrue
, persistentCertRef
};
286 #define SIG_BUF_SIZE 1024
288 /* find identity by persistent ref */
289 persistFind
= CFDictionaryCreate(NULL
, keys_persist
, values_persist
,
290 (sizeof(keys_persist
) / sizeof(*keys_persist
)), NULL
, NULL
);
291 if (persistFind
== NULL
)
294 status
= SecItemCopyMatching(persistFind
, (CFTypeRef
*)&identityRef
);
298 status
= SecIdentityCopyPrivateKey(identityRef
, &privateKeyRef
);
302 // alloc buffer for result
303 sig
= vmalloc(SIG_BUF_SIZE
);
307 status
= SecKeyRawSign(privateKeyRef
, kSecPaddingPKCS1
, hash
->v
,
308 hash
->l
, sig
->v
, &sig
->l
);
315 CFRelease(identityRef
);
317 CFRelease(privateKeyRef
);
319 #if !TARGET_OS_EMBEDDED
321 CFRelease(certificateRef
);
323 CFRelease(keychainRef
);
325 CFRelease(idSearchRef
);
326 if (cssmContextHandle
)
327 CSSM_DeleteContext(cssmContextHandle
);
330 CFRelease(persistFind
);
333 if (status
!= noErr
) {
340 if (status
!= noErr
&& status
!= -1) {
341 plog(LLV_ERROR
, LOCATION
, NULL
,
342 "error %d %s.\n", status
, GetSecurityErrorString(status
));
351 * Retrieve a cert from the keychain
353 vchar_t
* crypto_cssm_get_x509cert(CFDataRef persistentCertRef
)
357 vchar_t
*cert
= NULL
;
358 SecIdentityRef identityRef
= NULL
;
359 SecCertificateRef certificateRef
= NULL
;
361 #if !TARGET_OS_EMBEDDED
363 SecIdentitySearchRef idSearchRef
= NULL
;
364 SecKeychainRef keychainRef
= NULL
;
367 if (persistentCertRef
) {
368 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
372 // copy system keychain
373 status
= CopySystemKeychain(&keychainRef
);
377 // find first identity in system keychain
378 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
382 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
386 // get certificate from identity
387 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
393 // get certificate data
395 cssmData
.Data
= NULL
;
396 status
= SecCertificateGetData(certificateRef
, &cssmData
);
400 if (cssmData
.Length
== 0)
403 cert
= vmalloc(cssmData
.Length
);
407 // cssmData struct just points to the data
408 // data must be copied to be returned
409 memcpy(cert
->v
, cssmData
.Data
, cssmData
.Length
);
413 CFDictionaryRef persistFind
= NULL
;
414 const void *keys_persist
[] = { kSecReturnRef
, kSecValuePersistentRef
};
415 const void *values_persist
[] = { kCFBooleanTrue
, persistentCertRef
};
417 CFDataRef certData
= NULL
;
419 /* find identity by persistent ref */
420 persistFind
= CFDictionaryCreate(NULL
, keys_persist
, values_persist
,
421 (sizeof(keys_persist
) / sizeof(*keys_persist
)), NULL
, NULL
);
422 if (persistFind
== NULL
)
425 status
= SecItemCopyMatching(persistFind
, (CFTypeRef
*)&identityRef
);
429 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
433 certData
= SecCertificateCopyData(certificateRef
);
434 if (certData
== NULL
)
437 dataLen
= CFDataGetLength(certData
);
441 cert
= vmalloc(dataLen
);
445 CFDataGetBytes(certData
, CFRangeMake(0, dataLen
), cert
->v
);
451 CFRelease(certificateRef
);
453 CFRelease(identityRef
);
454 #if !TARGET_OS_EMBEDDED
456 CFRelease(idSearchRef
);
458 CFRelease(keychainRef
);
461 CFRelease(persistFind
);
466 if (status
!= noErr
&& status
!= -1) {
467 plog(LLV_ERROR
, LOCATION
, NULL
,
468 "error %d %s.\n", status
, GetSecurityErrorString(status
));
475 #if !TARGET_OS_EMBEDDED
477 * Find a policy ref by OID
479 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
)
483 SecPolicySearchRef searchRef
= nil
;
485 status
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policyOID
, NULL
, &searchRef
);
489 status
= SecPolicySearchCopyNext(searchRef
, policyRef
);
493 CFRelease(searchRef
);
495 if (status
!= noErr
) {
496 plog(LLV_ERROR
, LOCATION
, NULL
,
497 "error %d %s.\n", status
, GetSecurityErrorString(status
));
505 * Evaluate the trust of a cert using the policy provided
507 static OSStatus
EvaluateCert(SecCertificateRef cert
, CFTypeRef policyRef
)
510 SecTrustRef trustRef
= 0;
511 SecTrustResultType evalResult
;
513 SecCertificateRef evalCertArray
[1] = { cert
};
515 CFArrayRef cfCertRef
= CFArrayCreate((CFAllocatorRef
) NULL
, (void*)evalCertArray
, 1,
516 &kCFTypeArrayCallBacks
);
519 plog(LLV_ERROR
, LOCATION
, NULL
,
520 "unable to create CFArray.\n");
524 status
= SecTrustCreateWithCertificates(cfCertRef
, policyRef
, &trustRef
);
528 status
= SecTrustEvaluate(trustRef
, &evalResult
);
532 if (evalResult
!= kSecTrustResultProceed
&& evalResult
!= kSecTrustResultUnspecified
) {
533 plog(LLV_ERROR
, LOCATION
, NULL
,
534 "error evaluating certificate.\n");
541 CFRelease(cfCertRef
);
545 if (status
!= noErr
&& status
!= -1) {
546 plog(LLV_ERROR
, LOCATION
, NULL
,
547 "error %d %s.\n", status
, GetSecurityErrorString(status
));
553 #if !TARGET_OS_EMBEDDED
555 * Copy the system keychain
557 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
)
562 status
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
566 status
= SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem
, keychainRef
);
570 if (status
!= noErr
) {
571 plog(LLV_ERROR
, LOCATION
, NULL
,
572 "error %d %s.\n", status
, GetSecurityErrorString(status
));
581 * Return string representation of Security-related OSStatus.
584 GetSecurityErrorString(OSStatus err
)
597 case errSecNotAvailable
:
598 return "errSecNotAvailable";
599 #if !TARGET_OS_EMBEDDED
601 return "errSecReadOnly";
602 case errSecAuthFailed
:
603 return "errSecAuthFailed";
604 case errSecNoSuchKeychain
:
605 return "errSecNoSuchKeychain";
606 case errSecInvalidKeychain
:
607 return "errSecInvalidKeychain";
608 case errSecDuplicateKeychain
:
609 return "errSecDuplicateKeychain";
610 case errSecDuplicateCallback
:
611 return "errSecDuplicateCallback";
612 case errSecInvalidCallback
:
613 return "errSecInvalidCallback";
614 case errSecBufferTooSmall
:
615 return "errSecBufferTooSmall";
616 case errSecDataTooLarge
:
617 return "errSecDataTooLarge";
618 case errSecNoSuchAttr
:
619 return "errSecNoSuchAttr";
620 case errSecInvalidItemRef
:
621 return "errSecInvalidItemRef";
622 case errSecInvalidSearchRef
:
623 return "errSecInvalidSearchRef";
624 case errSecNoSuchClass
:
625 return "errSecNoSuchClass";
626 case errSecNoDefaultKeychain
:
627 return "errSecNoDefaultKeychain";
628 case errSecInteractionNotAllowed
:
629 return "errSecInteractionNotAllowed";
630 case errSecReadOnlyAttr
:
631 return "errSecReadOnlyAttr";
632 case errSecWrongSecVersion
:
633 return "errSecWrongSecVersion";
634 case errSecKeySizeNotAllowed
:
635 return "errSecKeySizeNotAllowed";
636 case errSecNoStorageModule
:
637 return "errSecNoStorageModule";
638 case errSecNoCertificateModule
:
639 return "errSecNoCertificateModule";
640 case errSecNoPolicyModule
:
641 return "errSecNoPolicyModule";
642 case errSecInteractionRequired
:
643 return "errSecInteractionRequired";
644 case errSecDataNotAvailable
:
645 return "errSecDataNotAvailable";
646 case errSecDataNotModifiable
:
647 return "errSecDataNotModifiable";
648 case errSecCreateChainFailed
:
649 return "errSecCreateChainFailed";
650 case errSecACLNotSimple
:
651 return "errSecACLNotSimple";
652 case errSecPolicyNotFound
:
653 return "errSecPolicyNotFound";
654 case errSecInvalidTrustSetting
:
655 return "errSecInvalidTrustSetting";
656 case errSecNoAccessForItem
:
657 return "errSecNoAccessForItem";
658 case errSecInvalidOwnerEdit
:
659 return "errSecInvalidOwnerEdit";
661 case errSecDuplicateItem
:
662 return "errSecDuplicateItem";
663 case errSecItemNotFound
:
664 return "errSecItemNotFound";