]> git.saurik.com Git - apple/network_cmds.git/blob - racoon.tproj/crypto_cssm.c
aa6f83bd9aeaa1ce3f49ed25cf9d6c906c8b23a3
[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 * 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 = 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 uint32 bytesEncrypted = 0;
127 CSSM_DATA clearData;
128 CSSM_DATA cipherData;
129 CSSM_DATA remData;
130 CSSM_CONTEXT_ATTRIBUTE newAttr;
131 vchar_t *sig = NULL;
132
133 remData.Length = 0;
134 remData.Data = 0;
135
136 if (persistentCertRef) {
137 // get cert from keychain
138 status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef);
139 if (status != noErr)
140 goto end;
141
142 // get keychain ref where cert is contained
143 status = SecKeychainItemCopyKeychain((SecKeychainItemRef)certificateRef, &keychainRef);
144 if (status != noErr)
145 goto end;
146
147 // get identity from the certificate
148 status = SecIdentityCreateWithCertificate(keychainRef, certificateRef, &identityRef);
149 if (status != noErr)
150 goto end;
151
152 } else {
153 // copy system keychain
154 status = CopySystemKeychain(&keychainRef);
155 if (status != noErr)
156 goto end;
157
158 // serach for first identity in system keychain
159 status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef);
160 if (status != noErr)
161 goto end;
162
163 status = SecIdentitySearchCopyNext(idSearchRef, &identityRef);
164 if (status != noErr)
165 goto end;
166
167 // get certificate from identity
168 status = SecIdentityCopyCertificate(identityRef, &certificateRef);
169 if (status != noErr)
170 goto end;
171 }
172
173
174 // get private key from identity
175 status = SecIdentityCopyPrivateKey(identityRef, &privateKeyRef);
176 if (status != noErr)
177 goto end;
178
179 // get CSSM_KEY pointer from key ref
180 status = SecKeyGetCSSMKey(privateKeyRef, &cssmKey);
181 if (status != noErr)
182 goto end;
183
184 // get CSSM CSP handle
185 status = SecKeychainGetCSPHandle(keychainRef, &cspHandle);
186 if (status != noErr)
187 goto end;
188
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);
192 if (status != noErr)
193 goto end;
194
195 // create asymmetric context for encryption
196 status = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA, credentials, cssmKey,
197 CSSM_PADDING_PKCS1, &cssmContextHandle);
198 if (status != noErr)
199 goto end;
200
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);
206 if(status != noErr)
207 goto end;
208
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,
215 &remData);
216 if (status != noErr)
217 goto end;
218
219 if (remData.Length != 0) { // something didn't go right - should be zero
220 status = -1;
221 plog(LLV_ERROR, LOCATION, NULL,
222 "unencrypted data remaining after encrypting hash.\n");
223 goto end;
224 }
225
226 // alloc buffer for result
227 sig = vmalloc(cipherData.Length);
228 if (sig == NULL)
229 goto end;
230
231 sig->v = cipherData.Data;
232
233 end:
234 if (certificateRef)
235 CFRelease(certificateRef);
236 if (keychainRef)
237 CFRelease(keychainRef);
238 if (identityRef)
239 CFRelease(identityRef);
240 if (privateKeyRef)
241 CFRelease(privateKeyRef);
242 if (idSearchRef)
243 CFRelease(idSearchRef);
244 if (cssmContextHandle)
245 CSSM_DeleteContext(cssmContextHandle);
246 if (status != noErr) {
247 if (sig) {
248 vfree(sig);
249 sig = NULL;
250 }
251 }
252
253 if (status != noErr && status != -1) {
254 plog(LLV_ERROR, LOCATION, NULL,
255 "error %d %s.\n", status, GetSecurityErrorString(status));
256 status = -1;
257 }
258 return sig;
259
260 }
261
262
263 /*
264 * Retrieve a cert from the keychain
265 */
266 vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef)
267 {
268
269 OSStatus status;
270 CSSM_DATA cssmData;
271 vchar_t *cert = NULL;
272 SecIdentityRef identityRef = NULL;
273 SecIdentitySearchRef idSearchRef = NULL;
274 SecKeychainRef keychainRef = NULL;
275 SecCertificateRef certificateRef = NULL;
276
277
278 // get cert ref
279 if (persistentCertRef) {
280 status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef);
281 if (status != noErr)
282 goto end;
283 } else {
284 // copy system keychain
285 status = CopySystemKeychain(&keychainRef);
286 if (status != noErr)
287 goto end;
288
289 // find first identity in system keychain
290 status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef);
291 if (status != noErr)
292 goto end;
293
294 status = SecIdentitySearchCopyNext(idSearchRef, &identityRef);
295 if (status != noErr)
296 goto end;
297
298 // get certificate from identity
299 status = SecIdentityCopyCertificate(identityRef, &certificateRef);
300 if (status != noErr)
301 goto end;
302
303 }
304
305 // get certificate data
306 cssmData.Length = 0;
307 cssmData.Data = NULL;
308 status = SecCertificateGetData(certificateRef, &cssmData);
309 if (status != noErr)
310 goto end;
311
312 if (cssmData.Length == 0)
313 goto end;
314
315 cert = vmalloc(cssmData.Length);
316 if (cert == NULL)
317 goto end;
318
319 // cssmData struct just points to the data
320 // data must be copied to be returned
321 memcpy(cert->v, cssmData.Data, cssmData.Length);
322
323 end:
324 if (certificateRef)
325 CFRelease(certificateRef);
326 if (identityRef)
327 CFRelease(identityRef);
328 if (idSearchRef)
329 CFRelease(idSearchRef);
330 if (keychainRef)
331 CFRelease(keychainRef);
332
333 if (status != noErr && status != -1) {
334 plog(LLV_ERROR, LOCATION, NULL,
335 "error %d %s.\n", status, GetSecurityErrorString(status));
336 status = -1;
337 }
338 return cert;
339
340 }
341
342
343 /*
344 * Find a policy ref by OID
345 */
346 static OSStatus FindPolicy(const CSSM_OID *policyOID, SecPolicyRef *policyRef)
347 {
348
349 OSStatus status;
350 SecPolicySearchRef searchRef = nil;
351
352 status = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &searchRef);
353 if (status != noErr)
354 goto end;
355
356 status = SecPolicySearchCopyNext(searchRef, policyRef);
357
358 end:
359 if (searchRef)
360 CFRelease(searchRef);
361
362 if (status != noErr) {
363 plog(LLV_ERROR, LOCATION, NULL,
364 "error %d %s.\n", status, GetSecurityErrorString(status));
365 status = -1;
366 }
367 return status;
368 }
369
370
371 /*
372 * Evaluate the trust of a cert using the policy provided
373 */
374 static OSStatus EvaluateCert(SecCertificateRef cert, CFTypeRef policyRef)
375 {
376 OSStatus status;
377 SecTrustRef trustRef = 0;
378 SecTrustResultType evalResult;
379
380 SecCertificateRef evalCertArray[1] = { cert };
381
382 CFArrayRef cfCertRef = CFArrayCreate((CFAllocatorRef) NULL, (void*)evalCertArray, 1,
383 &kCFTypeArrayCallBacks);
384
385 if (!cfCertRef) {
386 plog(LLV_ERROR, LOCATION, NULL,
387 "unable to create CFArray.\n");
388 return -1;
389 }
390
391 status = SecTrustCreateWithCertificates(cfCertRef, policyRef, &trustRef);
392 if (status != noErr)
393 goto end;
394
395 status = SecTrustEvaluate(trustRef, &evalResult);
396 if (status != noErr)
397 goto end;
398
399 if (evalResult != kSecTrustResultProceed && evalResult != kSecTrustResultUnspecified) {
400 plog(LLV_ERROR, LOCATION, NULL,
401 "error evaluating certificate.\n");
402 status = -1;
403 }
404
405
406 end:
407 if (cfCertRef)
408 CFRelease(cfCertRef);
409 if (trustRef)
410 CFRelease(trustRef);
411
412 if (status != noErr && status != -1) {
413 plog(LLV_ERROR, LOCATION, NULL,
414 "error %d %s.\n", status, GetSecurityErrorString(status));
415 status = -1;
416 }
417 return status;
418 }
419
420
421 /*
422 * Copy the system keychain
423 */
424 static OSStatus CopySystemKeychain(SecKeychainRef *keychainRef)
425 {
426
427 OSStatus status;
428
429 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
430 if (status != noErr)
431 goto end;
432
433 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, keychainRef);
434
435 end:
436
437 if (status != noErr) {
438 plog(LLV_ERROR, LOCATION, NULL,
439 "error %d %s.\n", status, GetSecurityErrorString(status));
440 status = -1;
441 }
442 return status;
443
444 }
445
446
447 /*
448 * Return string representation of Security-related OSStatus.
449 */
450 const char *
451 GetSecurityErrorString(OSStatus err)
452 {
453 switch(err) {
454 case noErr:
455 return "noErr";
456 case memFullErr:
457 return "memFullErr";
458 case paramErr:
459 return "paramErr";
460 case unimpErr:
461 return "unimpErr";
462
463 /* SecBase.h: */
464 case errSecNotAvailable:
465 return "errSecNotAvailable";
466 case errSecReadOnly:
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";
530 default:
531 return "<unknown>";
532 }
533 }
534