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/SecBase.h>
31 #include <Security/SecCertificate.h>
32 #include <Security/SecPolicy.h>
33 #include <Security/SecIdentity.h>
34 #include <Security/SecIdentityPriv.h>
35 #include <Security/SecIdentitySearch.h>
36 #include <Security/SecKeychain.h>
37 #include <Security/SecKeychainItem.h>
38 #include <Security/SecKeychainItemPriv.h>
39 #include <Security/SecKey.h>
40 #include <Security/SecKeyPriv.h>
41 #include <Security/SecTrust.h>
42 #include <Security/oidsalg.h>
43 #include <Security/cssmapi.h>
44 #include <Security/SecPolicySearch.h>
45 #include <CoreFoundation/CoreFoundation.h>
46 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
51 #include "crypto_cssm.h"
55 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
);
56 static OSStatus
EvaluateCert(SecCertificateRef cert
, CFTypeRef policyRef
);
57 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
);
58 static const char *GetSecurityErrorString(OSStatus err
);
62 * Verify cert using security framework
64 int crypto_cssm_check_x509cert(vchar_t
*cert
)
67 SecCertificateRef certRef
= 0;
69 CSSM_OID ourPolicyOID
= CSSMOID_APPLE_TP_IP_SEC
;
70 SecPolicyRef policyRef
= 0;
73 certData
.Length
= cert
->l
;
74 certData
.Data
= (uint8
*)cert
->v
;
75 status
= SecCertificateCreateFromData(&certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
,
80 // get our policy object
81 status
= FindPolicy(&ourPolicyOID
, &policyRef
);
85 // setup policy options ???
86 // no options used at present - verification of subjectAltName fields, etc.
87 // are done elsewhere in racoon in oakley_check_certid()
90 status
= EvaluateCert(certRef
, policyRef
);
100 if (status
!= noErr
&& status
!= -1) {
101 plog(LLV_ERROR
, LOCATION
, NULL
,
102 "error %d %s.\n", status
, GetSecurityErrorString(status
));
110 * Encrypt a hash via CSSM using the private key in the keychain
113 vchar_t
* crypto_cssm_getsign(CFDataRef persistentCertRef
, vchar_t
* hash
)
117 SecCertificateRef certificateRef
= NULL
;
118 SecIdentityRef identityRef
= NULL
;
119 SecIdentitySearchRef idSearchRef
= NULL
;
120 SecKeychainRef keychainRef
= NULL
;
121 SecKeyRef privateKeyRef
= NULL
;
122 const CSSM_KEY
*cssmKey
= NULL
;
123 CSSM_CSP_HANDLE cspHandle
= nil
;
124 CSSM_CC_HANDLE cssmContextHandle
= nil
;
125 const CSSM_ACCESS_CREDENTIALS
*credentials
= NULL
;
126 //CSSM_SIZE bytesEncrypted = 0; //%%%%HWR fix this - need new headers on Leopard
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
= (uint8
*)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
232 sig
->l
= cipherData
.Length
;
233 sig
->v
= (caddr_t
)cipherData
.Data
;
237 CFRelease(certificateRef
);
239 CFRelease(keychainRef
);
241 CFRelease(identityRef
);
243 CFRelease(privateKeyRef
);
245 CFRelease(idSearchRef
);
246 if (cssmContextHandle
)
247 CSSM_DeleteContext(cssmContextHandle
);
248 if (status
!= noErr
) {
255 if (status
!= noErr
&& status
!= -1) {
256 plog(LLV_ERROR
, LOCATION
, NULL
,
257 "error %d %s.\n", status
, GetSecurityErrorString(status
));
266 * Retrieve a cert from the keychain
268 vchar_t
* crypto_cssm_get_x509cert(CFDataRef persistentCertRef
)
273 vchar_t
*cert
= NULL
;
274 SecIdentityRef identityRef
= NULL
;
275 SecIdentitySearchRef idSearchRef
= NULL
;
276 SecKeychainRef keychainRef
= NULL
;
277 SecCertificateRef certificateRef
= NULL
;
281 if (persistentCertRef
) {
282 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
286 // copy system keychain
287 status
= CopySystemKeychain(&keychainRef
);
291 // find first identity in system keychain
292 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
296 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
300 // get certificate from identity
301 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
307 // get certificate data
309 cssmData
.Data
= NULL
;
310 status
= SecCertificateGetData(certificateRef
, &cssmData
);
314 if (cssmData
.Length
== 0)
317 cert
= vmalloc(cssmData
.Length
);
321 // cssmData struct just points to the data
322 // data must be copied to be returned
323 memcpy(cert
->v
, cssmData
.Data
, cssmData
.Length
);
327 CFRelease(certificateRef
);
329 CFRelease(identityRef
);
331 CFRelease(idSearchRef
);
333 CFRelease(keychainRef
);
335 if (status
!= noErr
&& status
!= -1) {
336 plog(LLV_ERROR
, LOCATION
, NULL
,
337 "error %d %s.\n", status
, GetSecurityErrorString(status
));
346 * Find a policy ref by OID
348 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
)
352 SecPolicySearchRef searchRef
= nil
;
354 status
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policyOID
, NULL
, &searchRef
);
358 status
= SecPolicySearchCopyNext(searchRef
, policyRef
);
362 CFRelease(searchRef
);
364 if (status
!= noErr
) {
365 plog(LLV_ERROR
, LOCATION
, NULL
,
366 "error %d %s.\n", status
, GetSecurityErrorString(status
));
374 * Evaluate the trust of a cert using the policy provided
376 static OSStatus
EvaluateCert(SecCertificateRef cert
, CFTypeRef policyRef
)
379 SecTrustRef trustRef
= 0;
380 SecTrustResultType evalResult
;
382 SecCertificateRef evalCertArray
[1] = { cert
};
384 CFArrayRef cfCertRef
= CFArrayCreate((CFAllocatorRef
) NULL
, (void*)evalCertArray
, 1,
385 &kCFTypeArrayCallBacks
);
388 plog(LLV_ERROR
, LOCATION
, NULL
,
389 "unable to create CFArray.\n");
393 status
= SecTrustCreateWithCertificates(cfCertRef
, policyRef
, &trustRef
);
397 status
= SecTrustEvaluate(trustRef
, &evalResult
);
401 if (evalResult
!= kSecTrustResultProceed
&& evalResult
!= kSecTrustResultUnspecified
) {
402 plog(LLV_ERROR
, LOCATION
, NULL
,
403 "error evaluating certificate.\n");
410 CFRelease(cfCertRef
);
414 if (status
!= noErr
&& status
!= -1) {
415 plog(LLV_ERROR
, LOCATION
, NULL
,
416 "error %d %s.\n", status
, GetSecurityErrorString(status
));
424 * Copy the system keychain
426 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
)
431 status
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
435 status
= SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem
, keychainRef
);
439 if (status
!= noErr
) {
440 plog(LLV_ERROR
, LOCATION
, NULL
,
441 "error %d %s.\n", status
, GetSecurityErrorString(status
));
450 * Return string representation of Security-related OSStatus.
453 GetSecurityErrorString(OSStatus err
)
466 case errSecNotAvailable
:
467 return "errSecNotAvailable";
469 return "errSecReadOnly";
470 case errSecAuthFailed
:
471 return "errSecAuthFailed";
472 case errSecNoSuchKeychain
:
473 return "errSecNoSuchKeychain";
474 case errSecInvalidKeychain
:
475 return "errSecInvalidKeychain";
476 case errSecDuplicateKeychain
:
477 return "errSecDuplicateKeychain";
478 case errSecDuplicateCallback
:
479 return "errSecDuplicateCallback";
480 case errSecInvalidCallback
:
481 return "errSecInvalidCallback";
482 case errSecDuplicateItem
:
483 return "errSecDuplicateItem";
484 case errSecItemNotFound
:
485 return "errSecItemNotFound";
486 case errSecBufferTooSmall
:
487 return "errSecBufferTooSmall";
488 case errSecDataTooLarge
:
489 return "errSecDataTooLarge";
490 case errSecNoSuchAttr
:
491 return "errSecNoSuchAttr";
492 case errSecInvalidItemRef
:
493 return "errSecInvalidItemRef";
494 case errSecInvalidSearchRef
:
495 return "errSecInvalidSearchRef";
496 case errSecNoSuchClass
:
497 return "errSecNoSuchClass";
498 case errSecNoDefaultKeychain
:
499 return "errSecNoDefaultKeychain";
500 case errSecInteractionNotAllowed
:
501 return "errSecInteractionNotAllowed";
502 case errSecReadOnlyAttr
:
503 return "errSecReadOnlyAttr";
504 case errSecWrongSecVersion
:
505 return "errSecWrongSecVersion";
506 case errSecKeySizeNotAllowed
:
507 return "errSecKeySizeNotAllowed";
508 case errSecNoStorageModule
:
509 return "errSecNoStorageModule";
510 case errSecNoCertificateModule
:
511 return "errSecNoCertificateModule";
512 case errSecNoPolicyModule
:
513 return "errSecNoPolicyModule";
514 case errSecInteractionRequired
:
515 return "errSecInteractionRequired";
516 case errSecDataNotAvailable
:
517 return "errSecDataNotAvailable";
518 case errSecDataNotModifiable
:
519 return "errSecDataNotModifiable";
520 case errSecCreateChainFailed
:
521 return "errSecCreateChainFailed";
522 case errSecACLNotSimple
:
523 return "errSecACLNotSimple";
524 case errSecPolicyNotFound
:
525 return "errSecPolicyNotFound";
526 case errSecInvalidTrustSetting
:
527 return "errSecInvalidTrustSetting";
528 case errSecNoAccessForItem
:
529 return "errSecNoAccessForItem";
530 case errSecInvalidOwnerEdit
:
531 return "errSecInvalidOwnerEdit";