]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/crypto_cssm.c
ipsec-34.0.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / crypto_cssm.c
1
2 /*
3 * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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.
12 *
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
19 * under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 /*
26 * Racoon module for verifying and signing certificates through Security
27 * Framework and CSSM
28 */
29
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>
47 #include "plog.h"
48 #include "debug.h"
49 #include "misc.h"
50
51 #include "crypto_cssm.h"
52
53
54
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);
59
60
61 /*
62 * Verify cert using security framework
63 */
64 int crypto_cssm_check_x509cert(vchar_t *cert)
65 {
66 OSStatus status;
67 SecCertificateRef certRef = 0;
68 CSSM_DATA certData;
69 CSSM_OID ourPolicyOID = CSSMOID_APPLE_TP_IP_SEC;
70 SecPolicyRef policyRef = 0;
71
72 // create cert ref
73 certData.Length = cert->l;
74 certData.Data = (uint8 *)cert->v;
75 status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
76 &certRef);
77 if (status != noErr)
78 goto end;
79
80 // get our policy object
81 status = FindPolicy(&ourPolicyOID, &policyRef);
82 if (status != noErr)
83 goto end;
84
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()
88
89 // evaluate cert
90 status = EvaluateCert(certRef, policyRef);
91
92
93 end:
94
95 if (certRef)
96 CFRelease(certRef);
97 if (policyRef)
98 CFRelease(policyRef);
99
100 if (status != noErr && status != -1) {
101 plog(LLV_ERROR, LOCATION, NULL,
102 "error %d %s.\n", status, GetSecurityErrorString(status));
103 status = -1;
104 }
105 return status;
106
107 }
108
109 /*
110 * Encrypt a hash via CSSM using the private key in the keychain
111 * from an identity.
112 */
113 vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash)
114 {
115
116 OSStatus status;
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;
128 CSSM_DATA clearData;
129 CSSM_DATA cipherData;
130 CSSM_DATA remData;
131 CSSM_CONTEXT_ATTRIBUTE newAttr;
132 vchar_t *sig = NULL;
133
134 remData.Length = 0;
135 remData.Data = 0;
136
137 if (persistentCertRef) {
138 // get cert from keychain
139 status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef);
140 if (status != noErr)
141 goto end;
142
143 // get keychain ref where cert is contained
144 status = SecKeychainItemCopyKeychain((SecKeychainItemRef)certificateRef, &keychainRef);
145 if (status != noErr)
146 goto end;
147
148 // get identity from the certificate
149 status = SecIdentityCreateWithCertificate(keychainRef, certificateRef, &identityRef);
150 if (status != noErr)
151 goto end;
152
153 } else {
154 // copy system keychain
155 status = CopySystemKeychain(&keychainRef);
156 if (status != noErr)
157 goto end;
158
159 // serach for first identity in system keychain
160 status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef);
161 if (status != noErr)
162 goto end;
163
164 status = SecIdentitySearchCopyNext(idSearchRef, &identityRef);
165 if (status != noErr)
166 goto end;
167
168 // get certificate from identity
169 status = SecIdentityCopyCertificate(identityRef, &certificateRef);
170 if (status != noErr)
171 goto end;
172 }
173
174
175 // get private key from identity
176 status = SecIdentityCopyPrivateKey(identityRef, &privateKeyRef);
177 if (status != noErr)
178 goto end;
179
180 // get CSSM_KEY pointer from key ref
181 status = SecKeyGetCSSMKey(privateKeyRef, &cssmKey);
182 if (status != noErr)
183 goto end;
184
185 // get CSSM CSP handle
186 status = SecKeychainGetCSPHandle(keychainRef, &cspHandle);
187 if (status != noErr)
188 goto end;
189
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);
193 if (status != noErr)
194 goto end;
195
196 // create asymmetric context for encryption
197 status = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA, credentials, cssmKey,
198 CSSM_PADDING_PKCS1, &cssmContextHandle);
199 if (status != noErr)
200 goto end;
201
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);
207 if(status != noErr)
208 goto end;
209
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,
216 &remData);
217 if (status != noErr)
218 goto end;
219
220 if (remData.Length != 0) { // something didn't go right - should be zero
221 status = -1;
222 plog(LLV_ERROR, LOCATION, NULL,
223 "unencrypted data remaining after encrypting hash.\n");
224 goto end;
225 }
226
227 // alloc buffer for result
228 sig = vmalloc(0);
229 if (sig == NULL)
230 goto end;
231
232 sig->l = cipherData.Length;
233 sig->v = (caddr_t)cipherData.Data;
234
235 end:
236 if (certificateRef)
237 CFRelease(certificateRef);
238 if (keychainRef)
239 CFRelease(keychainRef);
240 if (identityRef)
241 CFRelease(identityRef);
242 if (privateKeyRef)
243 CFRelease(privateKeyRef);
244 if (idSearchRef)
245 CFRelease(idSearchRef);
246 if (cssmContextHandle)
247 CSSM_DeleteContext(cssmContextHandle);
248 if (status != noErr) {
249 if (sig) {
250 vfree(sig);
251 sig = NULL;
252 }
253 }
254
255 if (status != noErr && status != -1) {
256 plog(LLV_ERROR, LOCATION, NULL,
257 "error %d %s.\n", status, GetSecurityErrorString(status));
258 status = -1;
259 }
260 return sig;
261
262 }
263
264
265 /*
266 * Retrieve a cert from the keychain
267 */
268 vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef)
269 {
270
271 OSStatus status;
272 CSSM_DATA cssmData;
273 vchar_t *cert = NULL;
274 SecIdentityRef identityRef = NULL;
275 SecIdentitySearchRef idSearchRef = NULL;
276 SecKeychainRef keychainRef = NULL;
277 SecCertificateRef certificateRef = NULL;
278
279
280 // get cert ref
281 if (persistentCertRef) {
282 status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef);
283 if (status != noErr)
284 goto end;
285 } else {
286 // copy system keychain
287 status = CopySystemKeychain(&keychainRef);
288 if (status != noErr)
289 goto end;
290
291 // find first identity in system keychain
292 status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef);
293 if (status != noErr)
294 goto end;
295
296 status = SecIdentitySearchCopyNext(idSearchRef, &identityRef);
297 if (status != noErr)
298 goto end;
299
300 // get certificate from identity
301 status = SecIdentityCopyCertificate(identityRef, &certificateRef);
302 if (status != noErr)
303 goto end;
304
305 }
306
307 // get certificate data
308 cssmData.Length = 0;
309 cssmData.Data = NULL;
310 status = SecCertificateGetData(certificateRef, &cssmData);
311 if (status != noErr)
312 goto end;
313
314 if (cssmData.Length == 0)
315 goto end;
316
317 cert = vmalloc(cssmData.Length);
318 if (cert == NULL)
319 goto end;
320
321 // cssmData struct just points to the data
322 // data must be copied to be returned
323 memcpy(cert->v, cssmData.Data, cssmData.Length);
324
325 end:
326 if (certificateRef)
327 CFRelease(certificateRef);
328 if (identityRef)
329 CFRelease(identityRef);
330 if (idSearchRef)
331 CFRelease(idSearchRef);
332 if (keychainRef)
333 CFRelease(keychainRef);
334
335 if (status != noErr && status != -1) {
336 plog(LLV_ERROR, LOCATION, NULL,
337 "error %d %s.\n", status, GetSecurityErrorString(status));
338 status = -1;
339 }
340 return cert;
341
342 }
343
344
345 /*
346 * Find a policy ref by OID
347 */
348 static OSStatus FindPolicy(const CSSM_OID *policyOID, SecPolicyRef *policyRef)
349 {
350
351 OSStatus status;
352 SecPolicySearchRef searchRef = nil;
353
354 status = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &searchRef);
355 if (status != noErr)
356 goto end;
357
358 status = SecPolicySearchCopyNext(searchRef, policyRef);
359
360 end:
361 if (searchRef)
362 CFRelease(searchRef);
363
364 if (status != noErr) {
365 plog(LLV_ERROR, LOCATION, NULL,
366 "error %d %s.\n", status, GetSecurityErrorString(status));
367 status = -1;
368 }
369 return status;
370 }
371
372
373 /*
374 * Evaluate the trust of a cert using the policy provided
375 */
376 static OSStatus EvaluateCert(SecCertificateRef cert, CFTypeRef policyRef)
377 {
378 OSStatus status;
379 SecTrustRef trustRef = 0;
380 SecTrustResultType evalResult;
381
382 SecCertificateRef evalCertArray[1] = { cert };
383
384 CFArrayRef cfCertRef = CFArrayCreate((CFAllocatorRef) NULL, (void*)evalCertArray, 1,
385 &kCFTypeArrayCallBacks);
386
387 if (!cfCertRef) {
388 plog(LLV_ERROR, LOCATION, NULL,
389 "unable to create CFArray.\n");
390 return -1;
391 }
392
393 status = SecTrustCreateWithCertificates(cfCertRef, policyRef, &trustRef);
394 if (status != noErr)
395 goto end;
396
397 status = SecTrustEvaluate(trustRef, &evalResult);
398 if (status != noErr)
399 goto end;
400
401 if (evalResult != kSecTrustResultProceed && evalResult != kSecTrustResultUnspecified) {
402 plog(LLV_ERROR, LOCATION, NULL,
403 "error evaluating certificate.\n");
404 status = -1;
405 }
406
407
408 end:
409 if (cfCertRef)
410 CFRelease(cfCertRef);
411 if (trustRef)
412 CFRelease(trustRef);
413
414 if (status != noErr && status != -1) {
415 plog(LLV_ERROR, LOCATION, NULL,
416 "error %d %s.\n", status, GetSecurityErrorString(status));
417 status = -1;
418 }
419 return status;
420 }
421
422
423 /*
424 * Copy the system keychain
425 */
426 static OSStatus CopySystemKeychain(SecKeychainRef *keychainRef)
427 {
428
429 OSStatus status;
430
431 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
432 if (status != noErr)
433 goto end;
434
435 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, keychainRef);
436
437 end:
438
439 if (status != noErr) {
440 plog(LLV_ERROR, LOCATION, NULL,
441 "error %d %s.\n", status, GetSecurityErrorString(status));
442 status = -1;
443 }
444 return status;
445
446 }
447
448
449 /*
450 * Return string representation of Security-related OSStatus.
451 */
452 const char *
453 GetSecurityErrorString(OSStatus err)
454 {
455 switch(err) {
456 case noErr:
457 return "noErr";
458 case memFullErr:
459 return "memFullErr";
460 case paramErr:
461 return "paramErr";
462 case unimpErr:
463 return "unimpErr";
464
465 /* SecBase.h: */
466 case errSecNotAvailable:
467 return "errSecNotAvailable";
468 case errSecReadOnly:
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";
532 default:
533 return "<unknown>";
534 }
535 }
536