3 * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
27 * Racoon module for verifying and signing certificates through Security
31 #include <Security/SecBase.h>
32 #include <Security/SecCertificate.h>
33 #include <Security/SecPolicy.h>
34 #include <Security/SecIdentity.h>
35 #include <Security/SecIdentityPriv.h>
36 #include <Security/SecIdentitySearch.h>
37 #include <Security/SecKeychain.h>
38 #include <Security/SecKeychainItem.h>
39 #include <Security/SecKeychainItemPriv.h>
40 #include <Security/SecKey.h>
41 #include <Security/SecKeyPriv.h>
42 #include <Security/SecTrust.h>
43 #include <Security/oidsalg.h>
44 #include <Security/cssmapi.h>
45 #include <Security/SecPolicySearch.h>
46 #include <CoreFoundation/CoreFoundation.h>
47 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
52 #include "crypto_cssm.h"
56 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
);
57 static OSStatus
EvaluateCert(SecCertificateRef cert
, CFTypeRef policyRef
);
58 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
);
59 static const char *GetSecurityErrorString(OSStatus err
);
63 * Verify cert using security framework
65 int crypto_cssm_check_x509cert(vchar_t
*cert
)
68 SecCertificateRef certRef
= 0;
70 CSSM_OID ourPolicyOID
= CSSMOID_APPLE_TP_IP_SEC
;
71 SecPolicyRef policyRef
= 0;
74 certData
.Length
= cert
->l
;
75 certData
.Data
= cert
->v
;
76 status
= SecCertificateCreateFromData(&certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
,
81 // get our policy object
82 status
= FindPolicy(&ourPolicyOID
, &policyRef
);
86 // setup policy options ???
87 // no options used at present - verification of subjectAltName fields, etc.
88 // are done elsewhere in racoon in oakley_check_certid()
91 status
= EvaluateCert(certRef
, policyRef
);
101 if (status
!= noErr
&& status
!= -1) {
102 plog(LLV_ERROR
, LOCATION
, NULL
,
103 "error %d %s.\n", status
, GetSecurityErrorString(status
));
111 * Encrypt a hash via CSSM using the private key in the keychain
114 vchar_t
* crypto_cssm_getsign(CFDataRef persistentCertRef
, vchar_t
* hash
)
118 SecCertificateRef certificateRef
= NULL
;
119 SecIdentityRef identityRef
= NULL
;
120 SecIdentitySearchRef idSearchRef
= NULL
;
121 SecKeychainRef keychainRef
= NULL
;
122 SecKeyRef privateKeyRef
= NULL
;
123 const CSSM_KEY
*cssmKey
= NULL
;
124 CSSM_CSP_HANDLE cspHandle
= nil
;
125 CSSM_CC_HANDLE cssmContextHandle
= nil
;
126 const CSSM_ACCESS_CREDENTIALS
*credentials
= NULL
;
127 uint32 bytesEncrypted
= 0;
129 CSSM_DATA cipherData
;
131 CSSM_CONTEXT_ATTRIBUTE newAttr
;
137 if (persistentCertRef
) {
138 // get cert from keychain
139 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
143 // get keychain ref where cert is contained
144 status
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)certificateRef
, &keychainRef
);
148 // get identity from the certificate
149 status
= SecIdentityCreateWithCertificate(keychainRef
, certificateRef
, &identityRef
);
154 // copy system keychain
155 status
= CopySystemKeychain(&keychainRef
);
159 // serach for first identity in system keychain
160 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
164 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
168 // get certificate from identity
169 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
175 // get private key from identity
176 status
= SecIdentityCopyPrivateKey(identityRef
, &privateKeyRef
);
180 // get CSSM_KEY pointer from key ref
181 status
= SecKeyGetCSSMKey(privateKeyRef
, &cssmKey
);
185 // get CSSM CSP handle
186 status
= SecKeychainGetCSPHandle(keychainRef
, &cspHandle
);
190 // create CSSM credentials to unlock private key for encryption - no UI to be used
191 status
= SecKeyGetCredentials(privateKeyRef
, CSSM_ACL_AUTHORIZATION_ENCRYPT
,
192 kSecCredentialTypeNoUI
, &credentials
);
196 // create asymmetric context for encryption
197 status
= CSSM_CSP_CreateAsymmetricContext(cspHandle
, CSSM_ALGID_RSA
, credentials
, cssmKey
,
198 CSSM_PADDING_PKCS1
, &cssmContextHandle
);
202 // add mode attribute to use private key for encryption
203 newAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
204 newAttr
.AttributeLength
= sizeof(uint32
);
205 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)CSSM_ALGMODE_PRIVATE_KEY
;
206 status
= CSSM_UpdateContextAttributes(cssmContextHandle
, 1, &newAttr
);
210 // and finally - encrypt data
211 clearData
.Length
= hash
->l
;
212 clearData
.Data
= hash
->v
;
213 cipherData
.Length
= 0;
214 cipherData
.Data
= NULL
;
215 status
= CSSM_EncryptData(cssmContextHandle
, &clearData
, 1, &cipherData
, 1, &bytesEncrypted
,
220 if (remData
.Length
!= 0) { // something didn't go right - should be zero
222 plog(LLV_ERROR
, LOCATION
, NULL
,
223 "unencrypted data remaining after encrypting hash.\n");
227 // alloc buffer for result
228 sig
= vmalloc(cipherData
.Length
);
232 sig
->v
= cipherData
.Data
;
236 CFRelease(certificateRef
);
238 CFRelease(keychainRef
);
240 CFRelease(identityRef
);
242 CFRelease(privateKeyRef
);
244 CFRelease(idSearchRef
);
245 if (cssmContextHandle
)
246 CSSM_DeleteContext(cssmContextHandle
);
247 if (status
!= noErr
) {
254 if (status
!= noErr
&& status
!= -1) {
255 plog(LLV_ERROR
, LOCATION
, NULL
,
256 "error %d %s.\n", status
, GetSecurityErrorString(status
));
265 * Retrieve a cert from the keychain
267 vchar_t
* crypto_cssm_get_x509cert(CFDataRef persistentCertRef
)
272 vchar_t
*cert
= NULL
;
273 SecIdentityRef identityRef
= NULL
;
274 SecIdentitySearchRef idSearchRef
= NULL
;
275 SecKeychainRef keychainRef
= NULL
;
276 SecCertificateRef certificateRef
= NULL
;
280 if (persistentCertRef
) {
281 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
285 // copy system keychain
286 status
= CopySystemKeychain(&keychainRef
);
290 // find first identity in system keychain
291 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
295 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
299 // get certificate from identity
300 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
306 // get certificate data
308 cssmData
.Data
= NULL
;
309 status
= SecCertificateGetData(certificateRef
, &cssmData
);
313 if (cssmData
.Length
== 0)
316 cert
= vmalloc(cssmData
.Length
);
320 // cssmData struct just points to the data
321 // data must be copied to be returned
322 memcpy(cert
->v
, cssmData
.Data
, cssmData
.Length
);
326 CFRelease(certificateRef
);
328 CFRelease(identityRef
);
330 CFRelease(idSearchRef
);
332 CFRelease(keychainRef
);
334 if (status
!= noErr
&& status
!= -1) {
335 plog(LLV_ERROR
, LOCATION
, NULL
,
336 "error %d %s.\n", status
, GetSecurityErrorString(status
));
345 * Find a policy ref by OID
347 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
)
351 SecPolicySearchRef searchRef
= nil
;
353 status
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policyOID
, NULL
, &searchRef
);
357 status
= SecPolicySearchCopyNext(searchRef
, policyRef
);
361 CFRelease(searchRef
);
363 if (status
!= noErr
) {
364 plog(LLV_ERROR
, LOCATION
, NULL
,
365 "error %d %s.\n", status
, GetSecurityErrorString(status
));
373 * Evaluate the trust of a cert using the policy provided
375 static OSStatus
EvaluateCert(SecCertificateRef cert
, CFTypeRef policyRef
)
378 SecTrustRef trustRef
= 0;
379 SecTrustResultType evalResult
;
381 SecCertificateRef evalCertArray
[1] = { cert
};
383 CFArrayRef cfCertRef
= CFArrayCreate((CFAllocatorRef
) NULL
, (void*)evalCertArray
, 1,
384 &kCFTypeArrayCallBacks
);
387 plog(LLV_ERROR
, LOCATION
, NULL
,
388 "unable to create CFArray.\n");
392 status
= SecTrustCreateWithCertificates(cfCertRef
, policyRef
, &trustRef
);
396 status
= SecTrustEvaluate(trustRef
, &evalResult
);
400 if (evalResult
!= kSecTrustResultProceed
&& evalResult
!= kSecTrustResultUnspecified
) {
401 plog(LLV_ERROR
, LOCATION
, NULL
,
402 "error evaluating certificate.\n");
409 CFRelease(cfCertRef
);
413 if (status
!= noErr
&& status
!= -1) {
414 plog(LLV_ERROR
, LOCATION
, NULL
,
415 "error %d %s.\n", status
, GetSecurityErrorString(status
));
423 * Copy the system keychain
425 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
)
430 status
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
434 status
= SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem
, keychainRef
);
438 if (status
!= noErr
) {
439 plog(LLV_ERROR
, LOCATION
, NULL
,
440 "error %d %s.\n", status
, GetSecurityErrorString(status
));
449 * Return string representation of Security-related OSStatus.
452 GetSecurityErrorString(OSStatus err
)
465 case errSecNotAvailable
:
466 return "errSecNotAvailable";
468 return "errSecReadOnly";
469 case errSecAuthFailed
:
470 return "errSecAuthFailed";
471 case errSecNoSuchKeychain
:
472 return "errSecNoSuchKeychain";
473 case errSecInvalidKeychain
:
474 return "errSecInvalidKeychain";
475 case errSecDuplicateKeychain
:
476 return "errSecDuplicateKeychain";
477 case errSecDuplicateCallback
:
478 return "errSecDuplicateCallback";
479 case errSecInvalidCallback
:
480 return "errSecInvalidCallback";
481 case errSecDuplicateItem
:
482 return "errSecDuplicateItem";
483 case errSecItemNotFound
:
484 return "errSecItemNotFound";
485 case errSecBufferTooSmall
:
486 return "errSecBufferTooSmall";
487 case errSecDataTooLarge
:
488 return "errSecDataTooLarge";
489 case errSecNoSuchAttr
:
490 return "errSecNoSuchAttr";
491 case errSecInvalidItemRef
:
492 return "errSecInvalidItemRef";
493 case errSecInvalidSearchRef
:
494 return "errSecInvalidSearchRef";
495 case errSecNoSuchClass
:
496 return "errSecNoSuchClass";
497 case errSecNoDefaultKeychain
:
498 return "errSecNoDefaultKeychain";
499 case errSecInteractionNotAllowed
:
500 return "errSecInteractionNotAllowed";
501 case errSecReadOnlyAttr
:
502 return "errSecReadOnlyAttr";
503 case errSecWrongSecVersion
:
504 return "errSecWrongSecVersion";
505 case errSecKeySizeNotAllowed
:
506 return "errSecKeySizeNotAllowed";
507 case errSecNoStorageModule
:
508 return "errSecNoStorageModule";
509 case errSecNoCertificateModule
:
510 return "errSecNoCertificateModule";
511 case errSecNoPolicyModule
:
512 return "errSecNoPolicyModule";
513 case errSecInteractionRequired
:
514 return "errSecInteractionRequired";
515 case errSecDataNotAvailable
:
516 return "errSecDataNotAvailable";
517 case errSecDataNotModifiable
:
518 return "errSecDataNotModifiable";
519 case errSecCreateChainFailed
:
520 return "errSecCreateChainFailed";
521 case errSecACLNotSimple
:
522 return "errSecACLNotSimple";
523 case errSecPolicyNotFound
:
524 return "errSecPolicyNotFound";
525 case errSecInvalidTrustSetting
:
526 return "errSecInvalidTrustSetting";
527 case errSecNoAccessForItem
:
528 return "errSecNoAccessForItem";
529 case errSecInvalidOwnerEdit
:
530 return "errSecInvalidOwnerEdit";