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
= 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 uint32 bytesEncrypted
= 0;
128 CSSM_DATA cipherData
;
130 CSSM_CONTEXT_ATTRIBUTE newAttr
;
136 if (persistentCertRef
) {
137 // get cert from keychain
138 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
142 // get keychain ref where cert is contained
143 status
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)certificateRef
, &keychainRef
);
147 // get identity from the certificate
148 status
= SecIdentityCreateWithCertificate(keychainRef
, certificateRef
, &identityRef
);
153 // copy system keychain
154 status
= CopySystemKeychain(&keychainRef
);
158 // serach for first identity in system keychain
159 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
163 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
167 // get certificate from identity
168 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
174 // get private key from identity
175 status
= SecIdentityCopyPrivateKey(identityRef
, &privateKeyRef
);
179 // get CSSM_KEY pointer from key ref
180 status
= SecKeyGetCSSMKey(privateKeyRef
, &cssmKey
);
184 // get CSSM CSP handle
185 status
= SecKeychainGetCSPHandle(keychainRef
, &cspHandle
);
189 // create CSSM credentials to unlock private key for encryption - no UI to be used
190 status
= SecKeyGetCredentials(privateKeyRef
, CSSM_ACL_AUTHORIZATION_ENCRYPT
,
191 kSecCredentialTypeNoUI
, &credentials
);
195 // create asymmetric context for encryption
196 status
= CSSM_CSP_CreateAsymmetricContext(cspHandle
, CSSM_ALGID_RSA
, credentials
, cssmKey
,
197 CSSM_PADDING_PKCS1
, &cssmContextHandle
);
201 // add mode attribute to use private key for encryption
202 newAttr
.AttributeType
= CSSM_ATTRIBUTE_MODE
;
203 newAttr
.AttributeLength
= sizeof(uint32
);
204 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)CSSM_ALGMODE_PRIVATE_KEY
;
205 status
= CSSM_UpdateContextAttributes(cssmContextHandle
, 1, &newAttr
);
209 // and finally - encrypt data
210 clearData
.Length
= hash
->l
;
211 clearData
.Data
= hash
->v
;
212 cipherData
.Length
= 0;
213 cipherData
.Data
= NULL
;
214 status
= CSSM_EncryptData(cssmContextHandle
, &clearData
, 1, &cipherData
, 1, &bytesEncrypted
,
219 if (remData
.Length
!= 0) { // something didn't go right - should be zero
221 plog(LLV_ERROR
, LOCATION
, NULL
,
222 "unencrypted data remaining after encrypting hash.\n");
226 // alloc buffer for result
227 sig
= vmalloc(cipherData
.Length
);
231 sig
->v
= cipherData
.Data
;
235 CFRelease(certificateRef
);
237 CFRelease(keychainRef
);
239 CFRelease(identityRef
);
241 CFRelease(privateKeyRef
);
243 CFRelease(idSearchRef
);
244 if (cssmContextHandle
)
245 CSSM_DeleteContext(cssmContextHandle
);
246 if (status
!= noErr
) {
253 if (status
!= noErr
&& status
!= -1) {
254 plog(LLV_ERROR
, LOCATION
, NULL
,
255 "error %d %s.\n", status
, GetSecurityErrorString(status
));
264 * Retrieve a cert from the keychain
266 vchar_t
* crypto_cssm_get_x509cert(CFDataRef persistentCertRef
)
271 vchar_t
*cert
= NULL
;
272 SecIdentityRef identityRef
= NULL
;
273 SecIdentitySearchRef idSearchRef
= NULL
;
274 SecKeychainRef keychainRef
= NULL
;
275 SecCertificateRef certificateRef
= NULL
;
279 if (persistentCertRef
) {
280 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
284 // copy system keychain
285 status
= CopySystemKeychain(&keychainRef
);
289 // find first identity in system keychain
290 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
294 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
298 // get certificate from identity
299 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
305 // get certificate data
307 cssmData
.Data
= NULL
;
308 status
= SecCertificateGetData(certificateRef
, &cssmData
);
312 if (cssmData
.Length
== 0)
315 cert
= vmalloc(cssmData
.Length
);
319 // cssmData struct just points to the data
320 // data must be copied to be returned
321 memcpy(cert
->v
, cssmData
.Data
, cssmData
.Length
);
325 CFRelease(certificateRef
);
327 CFRelease(identityRef
);
329 CFRelease(idSearchRef
);
331 CFRelease(keychainRef
);
333 if (status
!= noErr
&& status
!= -1) {
334 plog(LLV_ERROR
, LOCATION
, NULL
,
335 "error %d %s.\n", status
, GetSecurityErrorString(status
));
344 * Find a policy ref by OID
346 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
)
350 SecPolicySearchRef searchRef
= nil
;
352 status
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policyOID
, NULL
, &searchRef
);
356 status
= SecPolicySearchCopyNext(searchRef
, policyRef
);
360 CFRelease(searchRef
);
362 if (status
!= noErr
) {
363 plog(LLV_ERROR
, LOCATION
, NULL
,
364 "error %d %s.\n", status
, GetSecurityErrorString(status
));
372 * Evaluate the trust of a cert using the policy provided
374 static OSStatus
EvaluateCert(SecCertificateRef cert
, CFTypeRef policyRef
)
377 SecTrustRef trustRef
= 0;
378 SecTrustResultType evalResult
;
380 SecCertificateRef evalCertArray
[1] = { cert
};
382 CFArrayRef cfCertRef
= CFArrayCreate((CFAllocatorRef
) NULL
, (void*)evalCertArray
, 1,
383 &kCFTypeArrayCallBacks
);
386 plog(LLV_ERROR
, LOCATION
, NULL
,
387 "unable to create CFArray.\n");
391 status
= SecTrustCreateWithCertificates(cfCertRef
, policyRef
, &trustRef
);
395 status
= SecTrustEvaluate(trustRef
, &evalResult
);
399 if (evalResult
!= kSecTrustResultProceed
&& evalResult
!= kSecTrustResultUnspecified
) {
400 plog(LLV_ERROR
, LOCATION
, NULL
,
401 "error evaluating certificate.\n");
408 CFRelease(cfCertRef
);
412 if (status
!= noErr
&& status
!= -1) {
413 plog(LLV_ERROR
, LOCATION
, NULL
,
414 "error %d %s.\n", status
, GetSecurityErrorString(status
));
422 * Copy the system keychain
424 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
)
429 status
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
433 status
= SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem
, keychainRef
);
437 if (status
!= noErr
) {
438 plog(LLV_ERROR
, LOCATION
, NULL
,
439 "error %d %s.\n", status
, GetSecurityErrorString(status
));
448 * Return string representation of Security-related OSStatus.
451 GetSecurityErrorString(OSStatus err
)
464 case errSecNotAvailable
:
465 return "errSecNotAvailable";
467 return "errSecReadOnly";
468 case errSecAuthFailed
:
469 return "errSecAuthFailed";
470 case errSecNoSuchKeychain
:
471 return "errSecNoSuchKeychain";
472 case errSecInvalidKeychain
:
473 return "errSecInvalidKeychain";
474 case errSecDuplicateKeychain
:
475 return "errSecDuplicateKeychain";
476 case errSecDuplicateCallback
:
477 return "errSecDuplicateCallback";
478 case errSecInvalidCallback
:
479 return "errSecInvalidCallback";
480 case errSecDuplicateItem
:
481 return "errSecDuplicateItem";
482 case errSecItemNotFound
:
483 return "errSecItemNotFound";
484 case errSecBufferTooSmall
:
485 return "errSecBufferTooSmall";
486 case errSecDataTooLarge
:
487 return "errSecDataTooLarge";
488 case errSecNoSuchAttr
:
489 return "errSecNoSuchAttr";
490 case errSecInvalidItemRef
:
491 return "errSecInvalidItemRef";
492 case errSecInvalidSearchRef
:
493 return "errSecInvalidSearchRef";
494 case errSecNoSuchClass
:
495 return "errSecNoSuchClass";
496 case errSecNoDefaultKeychain
:
497 return "errSecNoDefaultKeychain";
498 case errSecInteractionNotAllowed
:
499 return "errSecInteractionNotAllowed";
500 case errSecReadOnlyAttr
:
501 return "errSecReadOnlyAttr";
502 case errSecWrongSecVersion
:
503 return "errSecWrongSecVersion";
504 case errSecKeySizeNotAllowed
:
505 return "errSecKeySizeNotAllowed";
506 case errSecNoStorageModule
:
507 return "errSecNoStorageModule";
508 case errSecNoCertificateModule
:
509 return "errSecNoCertificateModule";
510 case errSecNoPolicyModule
:
511 return "errSecNoPolicyModule";
512 case errSecInteractionRequired
:
513 return "errSecInteractionRequired";
514 case errSecDataNotAvailable
:
515 return "errSecDataNotAvailable";
516 case errSecDataNotModifiable
:
517 return "errSecDataNotModifiable";
518 case errSecCreateChainFailed
:
519 return "errSecCreateChainFailed";
520 case errSecACLNotSimple
:
521 return "errSecACLNotSimple";
522 case errSecPolicyNotFound
:
523 return "errSecPolicyNotFound";
524 case errSecInvalidTrustSetting
:
525 return "errSecInvalidTrustSetting";
526 case errSecNoAccessForItem
:
527 return "errSecNoAccessForItem";
528 case errSecInvalidOwnerEdit
:
529 return "errSecInvalidOwnerEdit";