]> git.saurik.com Git - apple/network_cmds.git/blob - racoon.tproj/crypto_cssm.c
acf5e5a3da3ca09a9a79281b31ea9351e5d4066b
[apple/network_cmds.git] / racoon.tproj / crypto_cssm.c
1
2 /*
3 * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 /*
27 * Racoon module for verifying and signing certificates through Security
28 * Framework and CSSM
29 */
30
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>
48 #include "plog.h"
49 #include "debug.h"
50 #include "misc.h"
51
52 #include "crypto_cssm.h"
53
54
55
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);
60
61
62 /*
63 * Verify cert using security framework
64 */
65 int crypto_cssm_check_x509cert(vchar_t *cert)
66 {
67 OSStatus status;
68 SecCertificateRef certRef = 0;
69 CSSM_DATA certData;
70 CSSM_OID ourPolicyOID = CSSMOID_APPLE_TP_IP_SEC;
71 SecPolicyRef policyRef = 0;
72
73 // create cert ref
74 certData.Length = cert->l;
75 certData.Data = cert->v;
76 status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
77 &certRef);
78 if (status != noErr)
79 goto end;
80
81 // get our policy object
82 status = FindPolicy(&ourPolicyOID, &policyRef);
83 if (status != noErr)
84 goto end;
85
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()
89
90 // evaluate cert
91 status = EvaluateCert(certRef, policyRef);
92
93
94 end:
95
96 if (certRef)
97 CFRelease(certRef);
98 if (policyRef)
99 CFRelease(policyRef);
100
101 if (status != noErr && status != -1) {
102 plog(LLV_ERROR, LOCATION, NULL,
103 "error %d %s.\n", status, GetSecurityErrorString(status));
104 status = -1;
105 }
106 return status;
107
108 }
109
110 /*
111 * Encrypt a hash via CSSM using the private key in the keychain
112 * from an identity.
113 */
114 vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash)
115 {
116
117 OSStatus status;
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;
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 = 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(cipherData.Length);
229 if (sig == NULL)
230 goto end;
231
232 sig->v = cipherData.Data;
233
234 end:
235 if (certificateRef)
236 CFRelease(certificateRef);
237 if (keychainRef)
238 CFRelease(keychainRef);
239 if (identityRef)
240 CFRelease(identityRef);
241 if (privateKeyRef)
242 CFRelease(privateKeyRef);
243 if (idSearchRef)
244 CFRelease(idSearchRef);
245 if (cssmContextHandle)
246 CSSM_DeleteContext(cssmContextHandle);
247 if (status != noErr) {
248 if (sig) {
249 vfree(sig);
250 sig = NULL;
251 }
252 }
253
254 if (status != noErr && status != -1) {
255 plog(LLV_ERROR, LOCATION, NULL,
256 "error %d %s.\n", status, GetSecurityErrorString(status));
257 status = -1;
258 }
259 return sig;
260
261 }
262
263
264 /*
265 * Retrieve a cert from the keychain
266 */
267 vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef)
268 {
269
270 OSStatus status;
271 CSSM_DATA cssmData;
272 vchar_t *cert = NULL;
273 SecIdentityRef identityRef = NULL;
274 SecIdentitySearchRef idSearchRef = NULL;
275 SecKeychainRef keychainRef = NULL;
276 SecCertificateRef certificateRef = NULL;
277
278
279 // get cert ref
280 if (persistentCertRef) {
281 status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef);
282 if (status != noErr)
283 goto end;
284 } else {
285 // copy system keychain
286 status = CopySystemKeychain(&keychainRef);
287 if (status != noErr)
288 goto end;
289
290 // find first identity in system keychain
291 status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef);
292 if (status != noErr)
293 goto end;
294
295 status = SecIdentitySearchCopyNext(idSearchRef, &identityRef);
296 if (status != noErr)
297 goto end;
298
299 // get certificate from identity
300 status = SecIdentityCopyCertificate(identityRef, &certificateRef);
301 if (status != noErr)
302 goto end;
303
304 }
305
306 // get certificate data
307 cssmData.Length = 0;
308 cssmData.Data = NULL;
309 status = SecCertificateGetData(certificateRef, &cssmData);
310 if (status != noErr)
311 goto end;
312
313 if (cssmData.Length == 0)
314 goto end;
315
316 cert = vmalloc(cssmData.Length);
317 if (cert == NULL)
318 goto end;
319
320 // cssmData struct just points to the data
321 // data must be copied to be returned
322 memcpy(cert->v, cssmData.Data, cssmData.Length);
323
324 end:
325 if (certificateRef)
326 CFRelease(certificateRef);
327 if (identityRef)
328 CFRelease(identityRef);
329 if (idSearchRef)
330 CFRelease(idSearchRef);
331 if (keychainRef)
332 CFRelease(keychainRef);
333
334 if (status != noErr && status != -1) {
335 plog(LLV_ERROR, LOCATION, NULL,
336 "error %d %s.\n", status, GetSecurityErrorString(status));
337 status = -1;
338 }
339 return cert;
340
341 }
342
343
344 /*
345 * Find a policy ref by OID
346 */
347 static OSStatus FindPolicy(const CSSM_OID *policyOID, SecPolicyRef *policyRef)
348 {
349
350 OSStatus status;
351 SecPolicySearchRef searchRef = nil;
352
353 status = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &searchRef);
354 if (status != noErr)
355 goto end;
356
357 status = SecPolicySearchCopyNext(searchRef, policyRef);
358
359 end:
360 if (searchRef)
361 CFRelease(searchRef);
362
363 if (status != noErr) {
364 plog(LLV_ERROR, LOCATION, NULL,
365 "error %d %s.\n", status, GetSecurityErrorString(status));
366 status = -1;
367 }
368 return status;
369 }
370
371
372 /*
373 * Evaluate the trust of a cert using the policy provided
374 */
375 static OSStatus EvaluateCert(SecCertificateRef cert, CFTypeRef policyRef)
376 {
377 OSStatus status;
378 SecTrustRef trustRef = 0;
379 SecTrustResultType evalResult;
380
381 SecCertificateRef evalCertArray[1] = { cert };
382
383 CFArrayRef cfCertRef = CFArrayCreate((CFAllocatorRef) NULL, (void*)evalCertArray, 1,
384 &kCFTypeArrayCallBacks);
385
386 if (!cfCertRef) {
387 plog(LLV_ERROR, LOCATION, NULL,
388 "unable to create CFArray.\n");
389 return -1;
390 }
391
392 status = SecTrustCreateWithCertificates(cfCertRef, policyRef, &trustRef);
393 if (status != noErr)
394 goto end;
395
396 status = SecTrustEvaluate(trustRef, &evalResult);
397 if (status != noErr)
398 goto end;
399
400 if (evalResult != kSecTrustResultProceed && evalResult != kSecTrustResultUnspecified) {
401 plog(LLV_ERROR, LOCATION, NULL,
402 "error evaluating certificate.\n");
403 status = -1;
404 }
405
406
407 end:
408 if (cfCertRef)
409 CFRelease(cfCertRef);
410 if (trustRef)
411 CFRelease(trustRef);
412
413 if (status != noErr && status != -1) {
414 plog(LLV_ERROR, LOCATION, NULL,
415 "error %d %s.\n", status, GetSecurityErrorString(status));
416 status = -1;
417 }
418 return status;
419 }
420
421
422 /*
423 * Copy the system keychain
424 */
425 static OSStatus CopySystemKeychain(SecKeychainRef *keychainRef)
426 {
427
428 OSStatus status;
429
430 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
431 if (status != noErr)
432 goto end;
433
434 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, keychainRef);
435
436 end:
437
438 if (status != noErr) {
439 plog(LLV_ERROR, LOCATION, NULL,
440 "error %d %s.\n", status, GetSecurityErrorString(status));
441 status = -1;
442 }
443 return status;
444
445 }
446
447
448 /*
449 * Return string representation of Security-related OSStatus.
450 */
451 const char *
452 GetSecurityErrorString(OSStatus err)
453 {
454 switch(err) {
455 case noErr:
456 return "noErr";
457 case memFullErr:
458 return "memFullErr";
459 case paramErr:
460 return "paramErr";
461 case unimpErr:
462 return "unimpErr";
463
464 /* SecBase.h: */
465 case errSecNotAvailable:
466 return "errSecNotAvailable";
467 case errSecReadOnly:
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";
531 default:
532 return "<unknown>";
533 }
534 }
535