]> git.saurik.com Git - apple/security.git/blob - SecurityTool/macOS/srCdsaUtils.cpp
Security-59306.101.1.tar.gz
[apple/security.git] / SecurityTool / macOS / srCdsaUtils.cpp
1 /*
2 * Copyright (c) 2001,2003-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * srCdsaUtils.cpp -- common CDSA access utilities
24 */
25
26 #include "srCdsaUtils.h"
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <Security/SecCertificate.h>
30 #include <Security/cssmapple.h> /* for cssmPerror() */
31 #include <Security/oidsalg.h> /* for cssmPerror() */
32 #include <strings.h>
33
34 static CSSM_VERSION vers = {2, 0};
35 static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
36
37 /*
38 * Standard app-level memory functions required by CDSA.
39 */
40 void * srAppMalloc (CSSM_SIZE size, void *allocRef) {
41 return( malloc(size) );
42 }
43
44 void srAppFree (void *mem_ptr, void *allocRef) {
45 free(mem_ptr);
46 return;
47 }
48
49 void * srAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
50 return( realloc( ptr, size ) );
51 }
52
53 void * srAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
54 return( calloc( num, size ) );
55 }
56
57 static CSSM_API_MEMORY_FUNCS memFuncs = {
58 srAppMalloc,
59 srAppFree,
60 srAppRealloc,
61 srAppCalloc,
62 NULL
63 };
64
65 CSSM_BOOL srCompareCssmData(const CSSM_DATA *d1,
66 const CSSM_DATA *d2)
67 {
68 if(d1->Length != d2->Length) {
69 return CSSM_FALSE;
70 }
71 if(memcmp(d1->Data, d2->Data, d1->Length)) {
72 return CSSM_FALSE;
73 }
74 return CSSM_TRUE;
75 }
76
77 /*
78 * Init CSSM; returns CSSM_FALSE on error. Reusable.
79 */
80 static CSSM_BOOL cssmInitd = CSSM_FALSE;
81
82 CSSM_BOOL srCssmStartup()
83 {
84 CSSM_RETURN crtn;
85 CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
86
87 if(cssmInitd) {
88 return CSSM_TRUE;
89 }
90 crtn = CSSM_Init (&vers,
91 CSSM_PRIVILEGE_SCOPE_NONE,
92 &testGuid,
93 CSSM_KEY_HIERARCHY_NONE,
94 &pvcPolicy,
95 NULL /* reserved */);
96 if(crtn != CSSM_OK)
97 {
98 srPrintError("CSSM_Init", crtn);
99 return CSSM_FALSE;
100 }
101 else {
102 cssmInitd = CSSM_TRUE;
103 return CSSM_TRUE;
104 }
105 }
106
107 /*
108 * Attach to CSP. Returns zero on error.
109 */
110 CSSM_CSP_HANDLE srCspStartup(
111 CSSM_BOOL bareCsp) // true ==> CSP, false ==> CSP/DL
112 {
113 CSSM_CSP_HANDLE cspHand;
114 CSSM_RETURN crtn;
115 const CSSM_GUID *guid;
116
117 /* common CSSM init */
118 if(srCssmStartup() == CSSM_FALSE) {
119 return 0;
120 }
121 if(bareCsp) {
122 guid = &gGuidAppleCSP;
123 }
124 else {
125 guid = &gGuidAppleCSPDL;
126 }
127 crtn = CSSM_ModuleLoad(guid,
128 CSSM_KEY_HIERARCHY_NONE,
129 NULL, // eventHandler
130 NULL); // AppNotifyCallbackCtx
131 if(crtn) {
132 srPrintError("CSSM_ModuleLoad()", crtn);
133 return 0;
134 }
135 crtn = CSSM_ModuleAttach (guid,
136 &vers,
137 &memFuncs, // memFuncs
138 0, // SubserviceID
139 CSSM_SERVICE_CSP,
140 0, // AttachFlags
141 CSSM_KEY_HIERARCHY_NONE,
142 NULL, // FunctionTable
143 0, // NumFuncTable
144 NULL, // reserved
145 &cspHand);
146 if(crtn) {
147 srPrintError("CSSM_ModuleAttach()", crtn);
148 return 0;
149 }
150 return cspHand;
151 }
152
153 /* Attach to DL side of CSPDL */
154 CSSM_DL_HANDLE srDlStartup()
155 {
156 CSSM_DL_HANDLE dlHand = 0;
157 CSSM_RETURN crtn;
158
159 if(srCssmStartup() == CSSM_FALSE) {
160 return 0;
161 }
162 crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
163 CSSM_KEY_HIERARCHY_NONE,
164 NULL, // eventHandler
165 NULL); // AppNotifyCallbackCtx
166 if(crtn) {
167 srPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
168 return 0;
169 }
170 crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
171 &vers,
172 &memFuncs, // memFuncs
173 0, // SubserviceID
174 CSSM_SERVICE_DL,
175 0, // AttachFlags
176 CSSM_KEY_HIERARCHY_NONE,
177 NULL, // FunctionTable
178 0, // NumFuncTable
179 NULL, // reserved
180 &dlHand);
181 if(crtn) {
182 srPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
183 return 0;
184 }
185 return dlHand;
186 }
187
188 CSSM_CL_HANDLE srClStartup()
189 {
190 CSSM_CL_HANDLE clHand;
191 CSSM_RETURN crtn;
192
193 if(srCssmStartup() == CSSM_FALSE) {
194 return 0;
195 }
196 crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
197 CSSM_KEY_HIERARCHY_NONE,
198 NULL, // eventHandler
199 NULL); // AppNotifyCallbackCtx
200 if(crtn) {
201 srPrintError("CSSM_ModuleLoad(AppleCL)", crtn);
202 return 0;
203 }
204 crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
205 &vers,
206 &memFuncs, // memFuncs
207 0, // SubserviceID
208 CSSM_SERVICE_CL, // SubserviceFlags - Where is this used?
209 0, // AttachFlags
210 CSSM_KEY_HIERARCHY_NONE,
211 NULL, // FunctionTable
212 0, // NumFuncTable
213 NULL, // reserved
214 &clHand);
215 if(crtn) {
216 srPrintError("CSSM_ModuleAttach(AppleCL)", crtn);
217 return 0;
218 }
219 else {
220 return clHand;
221 }
222 }
223
224 CSSM_TP_HANDLE srTpStartup()
225 {
226 CSSM_TP_HANDLE tpHand;
227 CSSM_RETURN crtn;
228
229 if(srCssmStartup() == CSSM_FALSE) {
230 return 0;
231 }
232 crtn = CSSM_ModuleLoad(&gGuidAppleX509TP,
233 CSSM_KEY_HIERARCHY_NONE,
234 NULL, // eventHandler
235 NULL); // AppNotifyCallbackCtx
236 if(crtn) {
237 srPrintError("CSSM_ModuleLoad(AppleTP)", crtn);
238 return 0;
239 }
240 crtn = CSSM_ModuleAttach (&gGuidAppleX509TP,
241 &vers,
242 &memFuncs, // memFuncs
243 0, // SubserviceID
244 CSSM_SERVICE_TP, // SubserviceFlags
245 0, // AttachFlags
246 CSSM_KEY_HIERARCHY_NONE,
247 NULL, // FunctionTable
248 0, // NumFuncTable
249 NULL, // reserved
250 &tpHand);
251 if(crtn) {
252 srPrintError("CSSM_ModuleAttach(AppleTP)", crtn);
253 return 0;
254 }
255 else {
256 return tpHand;
257 }
258 }
259
260 /*
261 * Given a context specified via a CSSM_CC_HANDLE, add a new
262 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
263 * AttributeLength, and an untyped pointer.
264 */
265 static CSSM_RETURN srAddContextAttribute(CSSM_CC_HANDLE CCHandle,
266 uint32 AttributeType,
267 uint32 AttributeLength,
268 const void *AttributePtr)
269 {
270 CSSM_CONTEXT_ATTRIBUTE newAttr;
271 CSSM_RETURN crtn;
272
273 newAttr.AttributeType = AttributeType;
274 newAttr.AttributeLength = AttributeLength;
275 newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr;
276 crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
277 if(crtn) {
278 srPrintError("CSSM_UpdateContextAttributes", crtn);
279 }
280 return crtn;
281 }
282
283
284 /*
285 * Derive symmetric key.
286 * Note in the X CSP, we never return an IV.
287 */
288 CSSM_RETURN srCspDeriveKey(CSSM_CSP_HANDLE cspHand,
289 uint32 keyAlg, // CSSM_ALGID_RC5, etc.
290 const char *keyLabel,
291 unsigned keyLabelLen,
292 uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
293 uint32 keySizeInBits,
294 CSSM_DATA_PTR password, // in PKCS-5 lingo
295 CSSM_DATA_PTR salt, // ditto
296 uint32 iterationCnt, // ditto
297 CSSM_KEY_PTR key)
298 {
299 CSSM_RETURN crtn;
300 CSSM_CC_HANDLE ccHand;
301 uint32 keyAttr;
302 CSSM_DATA dummyLabel;
303 CSSM_PKCS5_PBKDF2_PARAMS pbeParams;
304 CSSM_DATA pbeData;
305 CSSM_ACCESS_CREDENTIALS creds;
306
307 memset(key, 0, sizeof(CSSM_KEY));
308 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
309 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
310 CSSM_ALGID_PKCS5_PBKDF2,
311 keyAlg,
312 keySizeInBits,
313 &creds,
314 NULL, // BaseKey
315 iterationCnt,
316 salt,
317 NULL, // seed
318 &ccHand);
319 if(crtn) {
320 srPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
321 return crtn;
322 }
323 keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF |
324 CSSM_KEYATTR_SENSITIVE;
325 dummyLabel.Length = keyLabelLen;
326 dummyLabel.Data = (uint8 *)keyLabel;
327
328 /* passing in password is pretty strange....*/
329 pbeParams.Passphrase = *password;
330 pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
331 pbeData.Data = (uint8 *)&pbeParams;
332 pbeData.Length = sizeof(pbeParams);
333 crtn = CSSM_DeriveKey(ccHand,
334 &pbeData,
335 keyUsage,
336 keyAttr,
337 &dummyLabel,
338 NULL, // cred and acl
339 key);
340 if(crtn) {
341 srPrintError("CSSM_DeriveKey", crtn);
342 return crtn;
343 }
344 crtn = CSSM_DeleteContext(ccHand);
345 if(crtn) {
346 srPrintError("CSSM_DeleteContext", crtn);
347 }
348 return crtn;
349 }
350
351 /*
352 * Generate key pair of arbitrary algorithm.
353 */
354
355 /* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
356 #define DO_DSA_GEN_PARAMS 0
357
358 CSSM_RETURN srCspGenKeyPair(CSSM_CSP_HANDLE cspHand,
359 CSSM_DL_DB_HANDLE *dlDbHand, // optional
360 uint32 algorithm,
361 const char *keyLabel,
362 unsigned keyLabelLen,
363 uint32 keySize, // in bits
364 CSSM_KEY_PTR pubKey, // mallocd by caller
365 CSSM_KEYUSE pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
366 CSSM_KEYATTR_FLAGS pubAttrs, // CSSM_KEYATTR_EXTRACTABLE, etc.
367 CSSM_KEY_PTR privKey, // mallocd by caller
368 CSSM_KEYUSE privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc.
369 CSSM_KEYATTR_FLAGS privAttrs) // CSSM_KEYATTR_EXTRACTABLE, etc.
370 {
371 CSSM_RETURN crtn;
372 CSSM_RETURN ocrtn;
373 CSSM_CC_HANDLE ccHand;
374 CSSM_DATA keyLabelData;
375
376 keyLabelData.Data = (uint8 *)keyLabel;
377 keyLabelData.Length = keyLabelLen;
378 memset(pubKey, 0, sizeof(CSSM_KEY));
379 memset(privKey, 0, sizeof(CSSM_KEY));
380
381 crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
382 algorithm,
383 keySize,
384 NULL, // Seed
385 NULL, // Salt
386 NULL, // StartDate
387 NULL, // EndDate
388 NULL, // Params
389 &ccHand);
390 if(crtn) {
391 srPrintError("CSSM_CSP_CreateKeyGenContext", crtn);
392 return crtn;
393 }
394
395 /* post-context-create algorithm-specific stuff */
396 switch(algorithm) {
397 #if DO_DSA_GEN_PARAMS
398 case CSSM_ALGID_DSA:
399 /*
400 * extra step - generate params - this just adds some
401 * info to the context
402 */
403 {
404 CSSM_DATA dummy = {0, NULL};
405 crtn = CSSM_GenerateAlgorithmParams(ccHand,
406 keySize, &dummy);
407 if(crtn) {
408 srPrintError("CSSM_GenerateAlgorithmParams", crtn);
409 CSSM_DeleteContext(ccHand);
410 return crtn;
411 }
412 srAppFree(dummy.Data, NULL);
413 }
414 break;
415 #endif /* DO_DSA_GEN_PARAMS */
416 default:
417 break;
418 }
419
420 /* optionally specify DL/DB storage location */
421 if(dlDbHand) {
422 crtn = srAddContextAttribute(ccHand,
423 CSSM_ATTRIBUTE_DL_DB_HANDLE,
424 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
425 dlDbHand);
426 if(crtn) {
427 CSSM_DeleteContext(ccHand);
428 return crtn;
429 }
430 }
431 ocrtn = CSSM_GenerateKeyPair(ccHand,
432 pubKeyUsage,
433 pubAttrs,
434 &keyLabelData,
435 pubKey,
436 privKeyUsage,
437 privAttrs,
438 &keyLabelData, // same labels
439 NULL, // CredAndAclEntry
440 privKey);
441 if(ocrtn) {
442 srPrintError("CSSM_GenerateKeyPair", ocrtn);
443 }
444 crtn = CSSM_DeleteContext(ccHand);
445 if(crtn) {
446 srPrintError("CSSM_DeleteContext", crtn);
447 if(ocrtn == CSSM_OK) {
448 /* error on CSSM_GenerateKeyPair takes precedence */
449 ocrtn = crtn;
450 }
451 }
452 return ocrtn;
453 }
454
455
456 /*
457 * Add a certificate to an open Keychain.
458 */
459 CSSM_RETURN srAddCertToKC(
460 SecKeychainRef keychain,
461 const CSSM_DATA *cert,
462 CSSM_CERT_TYPE certType,
463 CSSM_CERT_ENCODING certEncoding,
464 const char *printName, // C string
465 const CSSM_DATA *keyLabel) // ??
466 {
467 SecCertificateRef certificate;
468
469 OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate);
470 if (!rslt)
471 {
472 rslt = SecCertificateAddToKeychain(certificate, keychain);
473 CFRelease(certificate);
474 }
475
476 return rslt;
477 }
478
479 /*
480 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
481 * unsigned.
482 */
483 unsigned srDER_ToInt(const CSSM_DATA *DER_Data)
484 {
485 uint32 rtn = 0;
486 unsigned i = 0;
487
488 while(i < DER_Data->Length) {
489 rtn |= DER_Data->Data[i];
490 if(++i == DER_Data->Length) {
491 break;
492 }
493 rtn <<= 8;
494 }
495 return rtn;
496 }
497
498 /*
499 * Log CSSM error.
500 */
501 void srPrintError(const char *op, CSSM_RETURN err)
502 {
503 cssmPerror(op, err);
504 }
505
506 /*
507 * Convert a CFString into a C string as safely as we can. Caller must
508 * free the result.
509 */
510 char *srCfStrToCString(
511 CFStringRef cfStr)
512 {
513 CFIndex len = CFStringGetLength(cfStr) + 1;
514 char *cstr = (char *)malloc(len);
515 if(cstr == NULL) {
516 return NULL;
517 }
518 if(!CFStringGetCString(cfStr, cstr, len, kCFStringEncodingASCII)) {
519 printf("***CFStringGetCString error\n");
520 free(cstr);
521 return NULL;
522 }
523 return cstr;
524 }
525