]> git.saurik.com Git - apple/security.git/blob - Keychain/srCdsaUtils.cpp
Security-176.tar.gz
[apple/security.git] / Keychain / srCdsaUtils.cpp
1 /*
2 File: srCdsaUtils.cpp
3
4 Description: common CDSA access utilities
5
6 Author: dmitch
7
8 Copyright: © Copyright 2001 Apple Computer, Inc. All rights reserved.
9
10 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
11 Computer, Inc. ("Apple") in consideration of your agreement to
12 the following terms, and your use, installation, modification
13 or redistribution of this Apple software constitutes acceptance
14 of these terms. If you do not agree with these terms, please
15 do not use, install, modify or redistribute this Apple software.
16
17 In consideration of your agreement to abide by the following
18 terms, and subject to these terms, Apple grants you a personal,
19 non-exclusive license, under Apple's copyrights in this
20 original Apple software (the "Apple Software"), to use,
21 reproduce, modify and redistribute the Apple Software, with
22 or without modifications, in source and/or binary forms;
23 provided that if you redistribute the Apple Software in
24 its entirety and without modifications, you must retain
25 this notice and the following text and disclaimers in all
26 such redistributions of the Apple Software. Neither the
27 name, trademarks, service marks or logos of Apple Computer,
28 Inc. may be used to endorse or promote products derived from the
29 Apple Software without specific prior written permission from
30 Apple. Except as expressly stated in this notice, no other
31 rights or licenses, express or implied, are granted by Apple
32 herein, including but not limited to any patent rights that
33 may be infringed by your derivative works or by other works
34 in which the Apple Software may be incorporated.
35
36 The Apple Software is provided by Apple on an "AS IS" basis.
37 APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
38 WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
39 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
40 REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE
41 OR IN COMBINATION WITH YOUR PRODUCTS.
42
43 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
44 INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
48 AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
49 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING
50 NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE
51 HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 */
53
54 #include "srCdsaUtils.h"
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <Security/SecCertificate.h>
58 #include <Security/cssmapple.h> /* for cssmPerror() */
59 #include <Security/oidsalg.h> /* for cssmPerror() */
60 #include <strings.h>
61
62 static CSSM_VERSION vers = {2, 0};
63 static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
64
65 /*
66 * Standard app-level memory functions required by CDSA.
67 */
68 void * srAppMalloc (uint32 size, void *allocRef) {
69 return( malloc(size) );
70 }
71
72 void srAppFree (void *mem_ptr, void *allocRef) {
73 free(mem_ptr);
74 return;
75 }
76
77 void * srAppRealloc (void *ptr, uint32 size, void *allocRef) {
78 return( realloc( ptr, size ) );
79 }
80
81 void * srAppCalloc (uint32 num, uint32 size, void *allocRef) {
82 return( calloc( num, size ) );
83 }
84
85 static CSSM_API_MEMORY_FUNCS memFuncs = {
86 srAppMalloc,
87 srAppFree,
88 srAppRealloc,
89 srAppCalloc,
90 NULL
91 };
92
93 CSSM_BOOL srCompareCssmData(const CSSM_DATA *d1,
94 const CSSM_DATA *d2)
95 {
96 if(d1->Length != d2->Length) {
97 return CSSM_FALSE;
98 }
99 if(memcmp(d1->Data, d2->Data, d1->Length)) {
100 return CSSM_FALSE;
101 }
102 return CSSM_TRUE;
103 }
104
105 /*
106 * Init CSSM; returns CSSM_FALSE on error. Reusable.
107 */
108 static CSSM_BOOL cssmInitd = CSSM_FALSE;
109
110 CSSM_BOOL srCssmStartup()
111 {
112 CSSM_RETURN crtn;
113 CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
114
115 if(cssmInitd) {
116 return CSSM_TRUE;
117 }
118 crtn = CSSM_Init (&vers,
119 CSSM_PRIVILEGE_SCOPE_NONE,
120 &testGuid,
121 CSSM_KEY_HIERARCHY_NONE,
122 &pvcPolicy,
123 NULL /* reserved */);
124 if(crtn != CSSM_OK)
125 {
126 srPrintError("CSSM_Init", crtn);
127 return CSSM_FALSE;
128 }
129 else {
130 cssmInitd = CSSM_TRUE;
131 return CSSM_TRUE;
132 }
133 }
134
135 /*
136 * Attach to CSP. Returns zero on error.
137 */
138 CSSM_CSP_HANDLE srCspStartup(
139 CSSM_BOOL bareCsp) // true ==> CSP, false ==> CSP/DL
140 {
141 CSSM_CSP_HANDLE cspHand;
142 CSSM_RETURN crtn;
143 const CSSM_GUID *guid;
144
145 /* common CSSM init */
146 if(srCssmStartup() == CSSM_FALSE) {
147 return 0;
148 }
149 if(bareCsp) {
150 guid = &gGuidAppleCSP;
151 }
152 else {
153 guid = &gGuidAppleCSPDL;
154 }
155 crtn = CSSM_ModuleLoad(guid,
156 CSSM_KEY_HIERARCHY_NONE,
157 NULL, // eventHandler
158 NULL); // AppNotifyCallbackCtx
159 if(crtn) {
160 srPrintError("CSSM_ModuleLoad()", crtn);
161 return 0;
162 }
163 crtn = CSSM_ModuleAttach (guid,
164 &vers,
165 &memFuncs, // memFuncs
166 0, // SubserviceID
167 CSSM_SERVICE_CSP,
168 0, // AttachFlags
169 CSSM_KEY_HIERARCHY_NONE,
170 NULL, // FunctionTable
171 0, // NumFuncTable
172 NULL, // reserved
173 &cspHand);
174 if(crtn) {
175 srPrintError("CSSM_ModuleAttach()", crtn);
176 return 0;
177 }
178 return cspHand;
179 }
180
181 /* Attach to DL side of CSPDL */
182 CSSM_DL_HANDLE srDlStartup()
183 {
184 CSSM_DL_HANDLE dlHand = 0;
185 CSSM_RETURN crtn;
186
187 if(srCssmStartup() == CSSM_FALSE) {
188 return 0;
189 }
190 crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
191 CSSM_KEY_HIERARCHY_NONE,
192 NULL, // eventHandler
193 NULL); // AppNotifyCallbackCtx
194 if(crtn) {
195 srPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
196 return 0;
197 }
198 crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
199 &vers,
200 &memFuncs, // memFuncs
201 0, // SubserviceID
202 CSSM_SERVICE_DL,
203 0, // AttachFlags
204 CSSM_KEY_HIERARCHY_NONE,
205 NULL, // FunctionTable
206 0, // NumFuncTable
207 NULL, // reserved
208 &dlHand);
209 if(crtn) {
210 srPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
211 return 0;
212 }
213 return dlHand;
214 }
215
216 CSSM_CL_HANDLE srClStartup()
217 {
218 CSSM_CL_HANDLE clHand;
219 CSSM_RETURN crtn;
220
221 if(srCssmStartup() == CSSM_FALSE) {
222 return 0;
223 }
224 crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
225 CSSM_KEY_HIERARCHY_NONE,
226 NULL, // eventHandler
227 NULL); // AppNotifyCallbackCtx
228 if(crtn) {
229 srPrintError("CSSM_ModuleLoad(AppleCL)", crtn);
230 return 0;
231 }
232 crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
233 &vers,
234 &memFuncs, // memFuncs
235 0, // SubserviceID
236 CSSM_SERVICE_CL, // SubserviceFlags - Where is this used?
237 0, // AttachFlags
238 CSSM_KEY_HIERARCHY_NONE,
239 NULL, // FunctionTable
240 0, // NumFuncTable
241 NULL, // reserved
242 &clHand);
243 if(crtn) {
244 srPrintError("CSSM_ModuleAttach(AppleCL)", crtn);
245 return 0;
246 }
247 else {
248 return clHand;
249 }
250 }
251
252 CSSM_TP_HANDLE srTpStartup()
253 {
254 CSSM_TP_HANDLE tpHand;
255 CSSM_RETURN crtn;
256
257 if(srCssmStartup() == CSSM_FALSE) {
258 return 0;
259 }
260 crtn = CSSM_ModuleLoad(&gGuidAppleX509TP,
261 CSSM_KEY_HIERARCHY_NONE,
262 NULL, // eventHandler
263 NULL); // AppNotifyCallbackCtx
264 if(crtn) {
265 srPrintError("CSSM_ModuleLoad(AppleTP)", crtn);
266 return 0;
267 }
268 crtn = CSSM_ModuleAttach (&gGuidAppleX509TP,
269 &vers,
270 &memFuncs, // memFuncs
271 0, // SubserviceID
272 CSSM_SERVICE_TP, // SubserviceFlags
273 0, // AttachFlags
274 CSSM_KEY_HIERARCHY_NONE,
275 NULL, // FunctionTable
276 0, // NumFuncTable
277 NULL, // reserved
278 &tpHand);
279 if(crtn) {
280 srPrintError("CSSM_ModuleAttach(AppleTP)", crtn);
281 return 0;
282 }
283 else {
284 return tpHand;
285 }
286 }
287
288 /*
289 * Given a context specified via a CSSM_CC_HANDLE, add a new
290 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
291 * AttributeLength, and an untyped pointer.
292 */
293 CSSM_RETURN srAddContextAttribute(CSSM_CC_HANDLE CCHandle,
294 uint32 AttributeType,
295 uint32 AttributeLength,
296 const void *AttributePtr)
297 {
298 CSSM_CONTEXT_ATTRIBUTE newAttr;
299 CSSM_RETURN crtn;
300
301 newAttr.AttributeType = AttributeType;
302 newAttr.AttributeLength = AttributeLength;
303 newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr;
304 crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
305 if(crtn) {
306 srPrintError("CSSM_UpdateContextAttributes", crtn);
307 }
308 return crtn;
309 }
310
311
312 /*
313 * Derive symmetric key.
314 * Note in the X CSP, we never return an IV.
315 */
316 CSSM_RETURN srCspDeriveKey(CSSM_CSP_HANDLE cspHand,
317 uint32 keyAlg, // CSSM_ALGID_RC5, etc.
318 const char *keyLabel,
319 unsigned keyLabelLen,
320 uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
321 uint32 keySizeInBits,
322 CSSM_DATA_PTR password, // in PKCS-5 lingo
323 CSSM_DATA_PTR salt, // ditto
324 uint32 iterationCnt, // ditto
325 CSSM_KEY_PTR key)
326 {
327 CSSM_RETURN crtn;
328 CSSM_CC_HANDLE ccHand;
329 uint32 keyAttr;
330 CSSM_DATA dummyLabel;
331 CSSM_PKCS5_PBKDF2_PARAMS pbeParams;
332 CSSM_DATA pbeData;
333 CSSM_ACCESS_CREDENTIALS creds;
334
335 memset(key, 0, sizeof(CSSM_KEY));
336 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
337 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
338 CSSM_ALGID_PKCS5_PBKDF2,
339 keyAlg,
340 keySizeInBits,
341 &creds,
342 NULL, // BaseKey
343 iterationCnt,
344 salt,
345 NULL, // seed
346 &ccHand);
347 if(crtn) {
348 srPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
349 return crtn;
350 }
351 keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF |
352 CSSM_KEYATTR_SENSITIVE;
353 dummyLabel.Length = keyLabelLen;
354 dummyLabel.Data = (uint8 *)keyLabel;
355
356 /* passing in password is pretty strange....*/
357 pbeParams.Passphrase = *password;
358 pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
359 pbeData.Data = (uint8 *)&pbeParams;
360 pbeData.Length = sizeof(pbeParams);
361 crtn = CSSM_DeriveKey(ccHand,
362 &pbeData,
363 keyUsage,
364 keyAttr,
365 &dummyLabel,
366 NULL, // cred and acl
367 key);
368 if(crtn) {
369 srPrintError("CSSM_DeriveKey", crtn);
370 return crtn;
371 }
372 crtn = CSSM_DeleteContext(ccHand);
373 if(crtn) {
374 srPrintError("CSSM_DeleteContext", crtn);
375 }
376 return crtn;
377 }
378
379 /*
380 * Generate key pair of arbitrary algorithm.
381 */
382
383 /* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
384 #define DO_DSA_GEN_PARAMS 0
385
386 CSSM_RETURN srCspGenKeyPair(CSSM_CSP_HANDLE cspHand,
387 CSSM_DL_DB_HANDLE *dlDbHand, // optional
388 uint32 algorithm,
389 const char *keyLabel,
390 unsigned keyLabelLen,
391 uint32 keySize, // in bits
392 CSSM_KEY_PTR pubKey, // mallocd by caller
393 CSSM_KEYUSE pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
394 CSSM_KEYATTR_FLAGS pubAttrs, // CSSM_KEYATTR_EXTRACTABLE, etc.
395 CSSM_KEY_PTR privKey, // mallocd by caller
396 CSSM_KEYUSE privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc.
397 CSSM_KEYATTR_FLAGS privAttrs) // CSSM_KEYATTR_EXTRACTABLE, etc.
398 {
399 CSSM_RETURN crtn;
400 CSSM_RETURN ocrtn;
401 CSSM_CC_HANDLE ccHand;
402 CSSM_DATA keyLabelData;
403
404 keyLabelData.Data = (uint8 *)keyLabel,
405 keyLabelData.Length = keyLabelLen;
406 memset(pubKey, 0, sizeof(CSSM_KEY));
407 memset(privKey, 0, sizeof(CSSM_KEY));
408
409 crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
410 algorithm,
411 keySize,
412 NULL, // Seed
413 NULL, // Salt
414 NULL, // StartDate
415 NULL, // EndDate
416 NULL, // Params
417 &ccHand);
418 if(crtn) {
419 srPrintError("CSSM_CSP_CreateKeyGenContext", crtn);
420 return crtn;
421 }
422
423 /* post-context-create algorithm-specific stuff */
424 switch(algorithm) {
425 #if DO_DSA_GEN_PARAMS
426 case CSSM_ALGID_DSA:
427 /*
428 * extra step - generate params - this just adds some
429 * info to the context
430 */
431 {
432 CSSM_DATA dummy = {0, NULL};
433 crtn = CSSM_GenerateAlgorithmParams(ccHand,
434 keySize, &dummy);
435 if(crtn) {
436 srPrintError("CSSM_GenerateAlgorithmParams", crtn);
437 CSSM_DeleteContext(ccHand);
438 return crtn;
439 }
440 srAppFree(dummy.Data, NULL);
441 }
442 break;
443 #endif /* DO_DSA_GEN_PARAMS */
444 default:
445 break;
446 }
447
448 /* optionally specify DL/DB storage location */
449 if(dlDbHand) {
450 crtn = srAddContextAttribute(ccHand,
451 CSSM_ATTRIBUTE_DL_DB_HANDLE,
452 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
453 dlDbHand);
454 if(crtn) {
455 CSSM_DeleteContext(ccHand);
456 return crtn;
457 }
458 }
459 ocrtn = CSSM_GenerateKeyPair(ccHand,
460 pubKeyUsage,
461 pubAttrs,
462 &keyLabelData,
463 pubKey,
464 privKeyUsage,
465 privAttrs,
466 &keyLabelData, // same labels
467 NULL, // CredAndAclEntry
468 privKey);
469 if(ocrtn) {
470 srPrintError("CSSM_GenerateKeyPair", ocrtn);
471 }
472 crtn = CSSM_DeleteContext(ccHand);
473 if(crtn) {
474 srPrintError("CSSM_DeleteContext", crtn);
475 if(ocrtn == CSSM_OK) {
476 /* error on CSSM_GenerateKeyPair takes precedence */
477 ocrtn = crtn;
478 }
479 }
480 return ocrtn;
481 }
482
483
484 /*
485 * Add a certificate to an open Keychain.
486 */
487 CSSM_RETURN srAddCertToKC(
488 SecKeychainRef keychain,
489 const CSSM_DATA *cert,
490 CSSM_CERT_TYPE certType,
491 CSSM_CERT_ENCODING certEncoding,
492 const char *printName, // C string
493 const CSSM_DATA *keyLabel) // ??
494 {
495 SecCertificateRef certificate;
496
497 OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate);
498 if (!rslt)
499 {
500 rslt = SecCertificateAddToKeychain(certificate, keychain);
501 CFRelease(certificate);
502 }
503
504 return rslt;
505 }
506
507 /*
508 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
509 * unsigned.
510 */
511 unsigned srDER_ToInt(const CSSM_DATA *DER_Data)
512 {
513 uint32 rtn = 0;
514 unsigned i = 0;
515
516 while(i < DER_Data->Length) {
517 rtn |= DER_Data->Data[i];
518 if(++i == DER_Data->Length) {
519 break;
520 }
521 rtn <<= 8;
522 }
523 return rtn;
524 }
525
526 /*
527 * Log CSSM error.
528 */
529 void srPrintError(char *op, CSSM_RETURN err)
530 {
531 cssmPerror(op, err);
532 }
533
534 /*
535 * Convert a CFString into a C string as safely as we can. Caller must
536 * free the result.
537 */
538 char *srCfStrToCString(
539 CFStringRef cfStr)
540 {
541 CFIndex len = CFStringGetLength(cfStr) + 1;
542 char *cstr = (char *)malloc(len);
543 if(cstr == NULL) {
544 return NULL;
545 }
546 if(!CFStringGetCString(cfStr, cstr, len, kCFStringEncodingASCII)) {
547 printf("***CFStringGetCString error\n");
548 free(cstr);
549 return NULL;
550 }
551 return cstr;
552 }
553