]> git.saurik.com Git - apple/security.git/blob - libsecurity_pkcs12/lib/pkcs12Utils.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_pkcs12 / lib / pkcs12Utils.cpp
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, 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
24 /*
25 * pkcs12Utils.cpp
26 */
27
28 #include "pkcs12Utils.h"
29 #include <string.h>
30 #include "pkcs7Templates.h"
31 #include "pkcs12Templates.h"
32 #include "pkcs12Crypto.h"
33 #include "pkcs12Debug.h"
34 #include <security_asn1/nssUtils.h>
35 #include <Security/secasn1t.h>
36 #include <security_utilities/devrandom.h>
37 #include <security_utilities/errors.h>
38 #include <security_cdsa_utils/cuCdsaUtils.h>
39 #include <Security/oidsattr.h>
40 #include <Security/oidsalg.h>
41 #include <Security/cssmapple.h>
42 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
43
44 /* malloc a NULL-ed array of pointers of size num+1 */
45 void **p12NssNullArray(
46 uint32 num,
47 SecNssCoder &coder)
48 {
49 unsigned len = (num + 1) * sizeof(void *);
50 void **p = (void **)coder.malloc(len);
51 memset(p, 0, len);
52 return p;
53 }
54
55 /* CSSM_DATA --> uint32. Returns true if OK. */
56 bool p12DataToInt(
57 const CSSM_DATA &cdata,
58 uint32 &u)
59 {
60 if((cdata.Length == 0) || (cdata.Data == NULL)) {
61 /* default/not present */
62 u = 0;
63 return true;
64 }
65 uint32 len = cdata.Length;
66 if(len > sizeof(uint32)) {
67 return false;
68 }
69
70 uint32 rtn = 0;
71 uint8 *cp = cdata.Data;
72 for(uint32 i=0; i<len; i++) {
73 rtn = (rtn << 8) | *cp++;
74 }
75 u = rtn;
76 return true;
77 }
78
79 /* uint32 --> CSSM_DATA */
80 void p12IntToData(
81 uint32 num,
82 CSSM_DATA &cdata,
83 SecNssCoder &coder)
84 {
85 uint32 len = 0;
86
87 if(num < 0x100) {
88 len = 1;
89 }
90 else if(num < 0x10000) {
91 len = 2;
92 }
93 else if(num < 0x1000000) {
94 len = 3;
95 }
96 else {
97 len = 4;
98 }
99 coder.allocItem(cdata, len);
100 uint8 *cp = &cdata.Data[len - 1];
101 for(unsigned i=0; i<len; i++) {
102 *cp-- = num & 0xff;
103 num >>= 8;
104 }
105 }
106
107 /* CFDataRef <--> CSSM_DATA */
108 CFDataRef p12CssmDataToCf(
109 const CSSM_DATA &c)
110 {
111 return CFDataCreate(NULL, c.Data, c.Length);
112 }
113
114 void p12CfDataToCssm(
115 CFDataRef cf,
116 CSSM_DATA &c,
117 SecNssCoder &coder)
118 {
119 coder.allocCopyItem(CFDataGetBytePtr(cf),
120 CFDataGetLength(cf), c);
121 }
122
123 /*
124 * Attempt to convert a CFStringRef, which represents a SafeBag's
125 * FriendlyName, to a UTF8-encoded CSSM_DATA. The CSSM_DATA and its
126 * referent are allocated in the specified SecNssCoder's memory.
127 * No guarantee that this conversion works. If it doesn't we return
128 * NULL and caller must be prepared to deal with that.
129 */
130 CSSM_DATA_PTR p12StringToUtf8(
131 CFStringRef cfStr,
132 SecNssCoder &coder)
133 {
134 if(cfStr == NULL) {
135 return NULL;
136 }
137 CFIndex strLen = CFStringGetLength(cfStr);
138 if(strLen == 0) {
139 return NULL;
140 }
141 CSSM_DATA_PTR rtn = coder.mallocn<CSSM_DATA>();
142 coder.allocItem(*rtn, strLen + 1);
143 if(!CFStringGetCString(cfStr, (char *)rtn->Data,strLen + 1,
144 kCFStringEncodingUTF8)) {
145 /* not convertible from native Unicode to UTF8 */
146 return NULL;
147 }
148 return rtn;
149 }
150
151 /*
152 * Enum to string mappper.
153 * Maybe DEBUG only.
154 */
155 /*
156 * Each type of attribute has a name/value pair in a table of these:
157 */
158 typedef struct {
159 unsigned value;
160 const char *name;
161 } p12NameValuePair;
162
163 /* declare one entry in a table of p12NameValuePair */
164 #define NVP(attr) {attr, #attr}
165
166 /* the NULL entry which terminates all p12NameValuePair tables */
167 #define NVP_END {0, NULL}
168
169 static const p12NameValuePair p7CITypeNames[] =
170 {
171 NVP(CT_None),
172 NVP(CT_Data),
173 NVP(CT_SignedData),
174 NVP(CT_EnvData),
175 NVP(CT_SignedEnvData),
176 NVP(CT_DigestData),
177 NVP(CT_EncryptedData),
178 NVP_END
179 };
180
181 static const p12NameValuePair p12BagTypeNames[] =
182 {
183 NVP(BT_None),
184 NVP(BT_KeyBag),
185 NVP(BT_ShroudedKeyBag),
186 NVP(BT_CertBag),
187 NVP(BT_CrlBag),
188 NVP(BT_SecretBag),
189 NVP(BT_SafeContentsBag),
190 NVP_END
191 };
192
193 static const char *typeToStr(
194 unsigned type,
195 const p12NameValuePair *table)
196 {
197 while(table->name) {
198 if(table->value == type) {
199 return table->name;
200 }
201 table++;
202 }
203 return "Unknown";
204 }
205
206 const char *p12BagTypeStr(
207 NSS_P12_SB_Type type)
208 {
209 return typeToStr(type, p12BagTypeNames);
210 }
211
212 const char *p7ContentInfoTypeStr(
213 NSS_P7_CI_Type type)
214 {
215 return typeToStr(type, p7CITypeNames);
216 }
217
218 /*
219 * OIDS for P12 and PKCS5 v1.5 (PBES1) encrypt and decrypt map to the following
220 * attributes.
221 */
222 typedef struct {
223 const CSSM_OID *oid;
224 CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES
225 CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE
226 CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5
227 uint32 keySizeInBits;
228 uint32 blockSizeInBytes; // for IV, optional
229 CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc.
230 CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc.
231 PKCS_Which pkcs; // PW_PKCS12 (for this module) or PW_PKCS5_v1_5
232 } PKCSOidInfo;
233
234 static const PKCSOidInfo pkcsOidInfos[] = {
235 /* PKCS12 first, the ones this module uses */
236 {
237 &CSSMOID_PKCS12_pbeWithSHAAnd128BitRC4,
238 CSSM_ALGID_RC4,
239 CSSM_ALGID_RC4,
240 CSSM_ALGID_SHA1,
241 128,
242 0, // RC4 is a stream cipher
243 CSSM_PADDING_NONE,
244 CSSM_ALGMODE_NONE,
245 PW_PKCS12
246 },
247 {
248 &CSSMOID_PKCS12_pbeWithSHAAnd40BitRC4,
249 CSSM_ALGID_RC4,
250 CSSM_ALGID_RC4,
251 CSSM_ALGID_SHA1,
252 40,
253 0, // RC4 is a stream cipher
254 CSSM_PADDING_NONE,
255 CSSM_ALGMODE_NONE,
256 PW_PKCS12
257 },
258 {
259 &CSSMOID_PKCS12_pbeWithSHAAnd3Key3DESCBC,
260 CSSM_ALGID_3DES_3KEY,
261 CSSM_ALGID_3DES_3KEY_EDE,
262 CSSM_ALGID_SHA1,
263 64 * 3,
264 8,
265 CSSM_PADDING_PKCS7,
266 CSSM_ALGMODE_CBCPadIV8,
267 PW_PKCS12
268 },
269 {
270 &CSSMOID_PKCS12_pbeWithSHAAnd2Key3DESCBC,
271 CSSM_ALGID_3DES_2KEY,
272 CSSM_ALGID_3DES_2KEY_EDE,
273 CSSM_ALGID_SHA1,
274 64 * 2,
275 8,
276 CSSM_PADDING_PKCS7,
277 CSSM_ALGMODE_CBCPadIV8,
278 PW_PKCS12
279 },
280 {
281 &CSSMOID_PKCS12_pbeWithSHAAnd128BitRC2CBC,
282 CSSM_ALGID_RC2,
283 CSSM_ALGID_RC2,
284 CSSM_ALGID_SHA1,
285 128,
286 8,
287 CSSM_PADDING_PKCS7,
288 CSSM_ALGMODE_CBCPadIV8,
289 PW_PKCS12
290 },
291 {
292 &CSSMOID_PKCS12_pbewithSHAAnd40BitRC2CBC,
293 CSSM_ALGID_RC2,
294 CSSM_ALGID_RC2,
295 CSSM_ALGID_SHA1,
296 40,
297 8,
298 CSSM_PADDING_PKCS7,
299 CSSM_ALGMODE_CBCPadIV8,
300 PW_PKCS12
301 },
302
303 /* PKCS5 v1.5, used for SecImportExport module */
304 {
305 &CSSMOID_PKCS5_pbeWithMD2AndDES,
306 CSSM_ALGID_DES,
307 CSSM_ALGID_DES,
308 CSSM_ALGID_MD2,
309 64,
310 8,
311 CSSM_PADDING_PKCS7,
312 CSSM_ALGMODE_CBCPadIV8,
313 PW_PKCS5_v1_5
314 },
315 {
316 &CSSMOID_PKCS5_pbeWithMD2AndRC2,
317 CSSM_ALGID_RC2,
318 CSSM_ALGID_RC2,
319 CSSM_ALGID_MD2,
320 64,
321 8,
322 CSSM_PADDING_PKCS7,
323 CSSM_ALGMODE_CBCPadIV8,
324 PW_PKCS5_v1_5
325 },
326 {
327 &CSSMOID_PKCS5_pbeWithMD5AndDES,
328 CSSM_ALGID_DES,
329 CSSM_ALGID_DES,
330 CSSM_ALGID_MD5,
331 64,
332 8,
333 CSSM_PADDING_PKCS7,
334 CSSM_ALGMODE_CBCPadIV8,
335 PW_PKCS5_v1_5
336 },
337 {
338 &CSSMOID_PKCS5_pbeWithMD5AndRC2,
339 CSSM_ALGID_RC2,
340 CSSM_ALGID_RC2,
341 CSSM_ALGID_MD5,
342 64,
343 8,
344 CSSM_PADDING_PKCS7,
345 CSSM_ALGMODE_CBCPadIV8,
346 PW_PKCS5_v1_5
347 },
348 {
349 &CSSMOID_PKCS5_pbeWithSHA1AndDES,
350 CSSM_ALGID_DES,
351 CSSM_ALGID_DES,
352 CSSM_ALGID_SHA1,
353 64,
354 8,
355 CSSM_PADDING_PKCS7,
356 CSSM_ALGMODE_CBCPadIV8,
357 PW_PKCS5_v1_5
358 },
359 {
360 &CSSMOID_PKCS5_pbeWithSHA1AndRC2,
361 CSSM_ALGID_RC2,
362 CSSM_ALGID_RC2,
363 CSSM_ALGID_SHA1,
364 64,
365 8,
366 CSSM_PADDING_PKCS7,
367 CSSM_ALGMODE_CBCPadIV8,
368 PW_PKCS5_v1_5
369 },
370
371 /* finally one for PKCS5 v2.0, which has its own means of
372 * cooking up all the parameters */
373 {
374 &CSSMOID_PKCS5_PBES2,
375 CSSM_ALGID_NONE,
376 CSSM_ALGID_NONE,
377 CSSM_ALGID_NONE,
378 0, 0, 0, 0,
379 PW_PKCS5_v2
380 }
381 };
382
383 #define NUM_PKCS_OID_INFOS (sizeof(pkcsOidInfos) / sizeof(pkcsOidInfos[1]))
384
385 /* map an OID to the components */
386 /* returns false if OID not found */
387
388 /*
389 * NOTE: as of March 8 2004 this is also used by the SecImportExport
390 * module...not just PKCS12!
391 */
392 bool pkcsOidToParams(
393 const CSSM_OID *oid,
394 CSSM_ALGORITHMS &keyAlg, // e.g., CSSM_ALGID_DES
395 CSSM_ALGORITHMS &encrAlg, // e.g., CSSM_ALGID_3DES_3KEY_EDE
396 CSSM_ALGORITHMS &pbeHashAlg, // SHA1 or MD5
397 uint32 &keySizeInBits,
398 uint32 &blockSizeInBytes, // for IV, optional
399 CSSM_PADDING &padding, // CSSM_PADDING_PKCS7, etc.
400 CSSM_ENCRYPT_MODE &mode, // CSSM_ALGMODE_CBCPadIV8, etc.
401 PKCS_Which &pkcs) // PW_PKCS5_v1_5 or PW_PKCS12
402 {
403 const PKCSOidInfo *info = pkcsOidInfos;
404 pkcs = PW_None;
405
406 for(unsigned dex=0; dex<NUM_PKCS_OID_INFOS; dex++) {
407 if(nssCompareCssmData(oid, info->oid)) {
408 keyAlg = info->keyAlg;
409 encrAlg = info->encrAlg;
410 pbeHashAlg = info->pbeHashAlg;
411 keySizeInBits = info->keySizeInBits;
412 blockSizeInBytes = info->blockSizeInBytes;
413 padding = info->padding;
414 mode = info->mode;
415 pkcs = info->pkcs;
416 return true;
417 }
418 info++;
419 }
420 return false;
421 }
422
423 /*
424 * Verify MAC on an existing PFX.
425 */
426 CSSM_RETURN p12VerifyMac(
427 const NSS_P12_DecodedPFX &pfx,
428 CSSM_CSP_HANDLE cspHand,
429 const CSSM_DATA *pwd, // unicode, double null terminated
430 const CSSM_KEY *passKey,
431 SecNssCoder &coder) // for temp mallocs
432 {
433 if(pfx.macData == NULL) {
434 return CSSMERR_CSP_INVALID_SIGNATURE;
435 }
436 NSS_P12_MacData &macData = *pfx.macData;
437 NSS_P7_DigestInfo &digestInfo = macData.mac;
438 CSSM_OID &algOid = digestInfo.digestAlgorithm.algorithm;
439 CSSM_ALGORITHMS macAlg;
440 if(!cssmOidToAlg(&algOid, &macAlg)) {
441 return CSSMERR_CSP_INVALID_ALGORITHM;
442 }
443 uint32 iterCount = 0;
444 CSSM_DATA &citer = macData.iterations;
445 if(!p12DataToInt(citer, iterCount)) {
446 return CSSMERR_CSP_INVALID_ATTR_ROUNDS;
447 }
448 if(iterCount == 0) {
449 /* optional, default 1 */
450 iterCount = 1;
451 }
452
453 /*
454 * In classic fashion, the PKCS12 spec now says:
455 *
456 * When password integrity mode is used to secure a PFX PDU,
457 * an SHA-1 HMAC is computed on the BER-encoding of the contents
458 * of the content field of the authSafe field in the PFX PDU.
459 *
460 * So here we go.
461 */
462 CSSM_DATA genMac;
463 CSSM_RETURN crtn = p12GenMac(cspHand, *pfx.authSafe.content.data,
464 macAlg, iterCount, macData.macSalt, pwd, passKey, coder, genMac);
465 if(crtn) {
466 return crtn;
467 }
468 if(nssCompareCssmData(&genMac, &digestInfo.digest)) {
469 return CSSM_OK;
470 }
471 else {
472 return CSSMERR_CSP_VERIFY_FAILED;
473 }
474 }
475
476 /* we generate 8 random bytes of salt */
477 #define P12_SALT_LEN 8
478
479 void p12GenSalt(
480 CSSM_DATA &salt,
481 SecNssCoder &coder)
482 {
483 DevRandomGenerator rng;
484 coder.allocItem(salt, P12_SALT_LEN);
485 rng.random(salt.Data, P12_SALT_LEN);
486 }
487
488 /*
489 * Generate random label string to allow associating an imported private
490 * key with a cert.
491 */
492 void p12GenLabel(
493 CSSM_DATA &label,
494 SecNssCoder &coder)
495 {
496 /* first a random uint32 */
497 uint8 d[4];
498 DevRandomGenerator rng;
499 rng.random(d, 4);
500 CSSM_DATA cd = {4, d};
501 uint32 i;
502 p12DataToInt(cd, i);
503
504 /* sprintf that into a real string */
505 coder.allocItem(label, 9);
506 memset(label.Data, 0, 9);
507 sprintf((char *)label.Data, "%08X", (unsigned)i);
508 }
509
510 /* NULL algorithm parameters */
511
512 static const uint8 nullAlg[2] = {SEC_ASN1_NULL, 0};
513
514 void p12NullAlgParams(
515 CSSM_X509_ALGORITHM_IDENTIFIER &algId)
516 {
517 CSSM_DATA &p = algId.parameters;
518 p.Data = (uint8 *)nullAlg;
519 p.Length = 2;
520 }
521
522 /*
523 * Free memory via specified plugin's app-level allocator
524 */
525 void freeCssmMemory(
526 CSSM_HANDLE hand,
527 void *p)
528 {
529 CSSM_API_MEMORY_FUNCS memFuncs;
530 CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs);
531 if(crtn) {
532 p12LogCssmError("CSSM_GetAPIMemoryFunctions", crtn);
533 /* oh well, leak and continue */
534 return;
535 }
536 memFuncs.free_func(p, memFuncs.AllocRef);
537 }
538
539 /*
540 * Find private key by label, modify its Label attr to be the
541 * hash of the associated public key.
542 * Also optionally re-sets the key's PrintName attribute; used to reset
543 * this attr from the random label we create when first unwrap it
544 * to the friendly name we find later after parsing attributes.
545 * Detection of a duplicate key when updating the key's attributes
546 * results in a lookup of the original key and returning it in
547 * foundKey.
548 */
549 CSSM_RETURN p12SetPubKeyHash(
550 CSSM_CSP_HANDLE cspHand, // where the key lives
551 CSSM_DL_DB_HANDLE dlDbHand, // ditto
552 CSSM_DATA &keyLabel, // for DB lookup
553 CSSM_DATA_PTR newPrintName, // optional
554 SecNssCoder &coder, // for mallocing newLabel
555 CSSM_DATA &newLabel, // RETURNED with label as hash
556 CSSM_KEY_PTR &foundKey) // RETURNED
557 {
558 CSSM_QUERY query;
559 CSSM_SELECTION_PREDICATE predicate;
560 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
561 CSSM_RETURN crtn;
562 CSSM_HANDLE resultHand = 0;
563 CSSM_DATA keyData = {0, NULL};
564 CSSM_CC_HANDLE ccHand = 0;
565 CSSM_KEY_PTR privKey = NULL;
566 CSSM_DATA_PTR keyDigest = NULL;
567
568 assert(cspHand != 0);
569 query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
570 query.Conjunctive = CSSM_DB_NONE;
571 query.NumSelectionPredicates = 1;
572 predicate.DbOperator = CSSM_DB_EQUAL;
573
574 predicate.Attribute.Info.AttributeNameFormat =
575 CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
576 predicate.Attribute.Info.Label.AttributeName =
577 (char*) P12_KEY_ATTR_LABEL_AND_HASH;
578 predicate.Attribute.Info.AttributeFormat =
579 CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
580 /* hope this cast is OK */
581 predicate.Attribute.Value = &keyLabel;
582 query.SelectionPredicate = &predicate;
583
584 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
585 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
586 query.QueryFlags = CSSM_QUERY_RETURN_DATA;
587
588 /* build Record attribute with one or two attrs */
589 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
590 CSSM_DB_ATTRIBUTE_DATA attr[2];
591 attr[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
592 attr[0].Info.Label.AttributeName = (char*) P12_KEY_ATTR_LABEL_AND_HASH;
593 attr[0].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
594 if(newPrintName) {
595 attr[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
596 attr[1].Info.Label.AttributeName = (char*) P12_KEY_ATTR_PRINT_NAME;
597 attr[1].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
598 }
599 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
600 recordAttrs.NumberOfAttributes = newPrintName ? 2 : 1;
601 recordAttrs.AttributeData = attr;
602
603 crtn = CSSM_DL_DataGetFirst(dlDbHand,
604 &query,
605 &resultHand,
606 &recordAttrs,
607 &keyData, // theData
608 &record);
609 /* abort only on success */
610 if(crtn != CSSM_OK) {
611 p12LogCssmError("CSSM_DL_DataGetFirst", crtn);
612 p12ErrorLog("***p12SetPubKeyHash: can't find private key\n");
613 return crtn;
614 }
615 /* subsequent errors to errOut: */
616 if(keyData.Data == NULL) {
617 p12ErrorLog("***p12SetPubKeyHash: private key lookup failure\n");
618 crtn = CSSMERR_CSSM_INTERNAL_ERROR;
619 goto errOut;
620 }
621 privKey = (CSSM_KEY_PTR)keyData.Data;
622
623 /* public key hash via passthrough - works on any key, any CSP/CSPDL.... */
624 /*
625 * Warning! This relies on the current default ACL meaning "allow this
626 * current app to access this private key" since we created the key.
627 */
628 crtn = CSSM_CSP_CreatePassThroughContext(cspHand, privKey, &ccHand);
629 if(crtn) {
630 p12LogCssmError("CSSM_CSP_CreatePassThroughContext", crtn);
631 goto errOut;
632 }
633 crtn = CSSM_CSP_PassThrough(ccHand,
634 CSSM_APPLECSP_KEYDIGEST,
635 NULL,
636 (void **)&keyDigest);
637 if(crtn) {
638 p12LogCssmError("CSSM_CSP_PassThrough", crtn);
639 goto errOut;
640 }
641
642 /*
643 * Replace Label attr data with hash.
644 * NOTE: the module which allocated this attribute data - a DL -
645 * was loaded and attached by out client layer, not by us. Thus
646 * we can't use the memory allocator functions *we* used when
647 * attaching to the CSP - we have to use the ones
648 * which the client registered with the DL.
649 */
650 freeCssmMemory(dlDbHand.DLHandle, attr[0].Value->Data);
651 freeCssmMemory(dlDbHand.DLHandle, attr[0].Value);
652 if(newPrintName) {
653 freeCssmMemory(dlDbHand.DLHandle, attr[1].Value->Data);
654 freeCssmMemory(dlDbHand.DLHandle, attr[1].Value);
655 }
656 /* modify key attributes */
657 attr[0].Value = keyDigest;
658 if(newPrintName) {
659 attr[1].Value = newPrintName;
660 }
661 crtn = CSSM_DL_DataModify(dlDbHand,
662 CSSM_DL_DB_RECORD_PRIVATE_KEY,
663 record,
664 &recordAttrs,
665 NULL, // DataToBeModified
666 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
667 switch(crtn) {
668 case CSSM_OK:
669 /* give caller the key's new label */
670 coder.allocCopyItem(*keyDigest, newLabel);
671 break;
672 default:
673 p12LogCssmError("CSSM_DL_DataModify", crtn);
674 break;
675 case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
676 {
677 /*
678 * Special case: dup private key. The label we just tried to modify is
679 * the public key hash so we can be confident that this really is a dup.
680 * Delete it, look up the original, and return the original to caller.
681 */
682 CSSM_RETURN drtn = CSSM_DL_DataDelete(dlDbHand, record);
683 if(drtn) {
684 p12LogCssmError("CSSM_DL_DataDelete on dup key", drtn);
685 crtn = drtn;
686 break;
687 }
688
689 /* Free items created in last search */
690 CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
691 resultHand = 0;
692 CSSM_DL_FreeUniqueRecord(dlDbHand, record);
693 record = NULL;
694
695 /* lookup by label as public key hash this time */
696 predicate.Attribute.Value = keyDigest;
697 drtn = CSSM_DL_DataGetFirst(dlDbHand,
698 &query,
699 &resultHand,
700 NULL, // no attrs this time
701 &keyData,
702 &record);
703 if(drtn) {
704 p12LogCssmError("CSSM_DL_DataGetFirst on original key", crtn);
705 crtn = drtn;
706 break;
707 }
708 foundKey = (CSSM_KEY_PTR)keyData.Data;
709 /* give caller the key's actual label */
710 coder.allocCopyItem(*keyDigest, newLabel);
711 break;
712 }
713 }
714
715 errOut:
716 /* free resources */
717 if(resultHand) {
718 CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
719 }
720 if(record) {
721 CSSM_DL_FreeUniqueRecord(dlDbHand, record);
722 }
723 if(ccHand) {
724 CSSM_DeleteContext(ccHand);
725 }
726 if(privKey) {
727 /* key created by the CSPDL */
728 CSSM_FreeKey(cspHand, NULL, privKey, CSSM_FALSE);
729 freeCssmMemory(dlDbHand.DLHandle, privKey);
730 }
731 if(keyDigest) {
732 /* mallocd by someone else's CSP */
733 freeCssmMemory(cspHand, keyDigest->Data);
734 freeCssmMemory(cspHand, keyDigest);
735 }
736 return crtn;
737 }
738
739 /*
740 * Given a context specified via a CSSM_CC_HANDLE, add a new
741 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
742 * AttributeLength, and an untyped pointer.
743 */
744 CSSM_RETURN p12AddContextAttribute(CSSM_CC_HANDLE CCHandle,
745 uint32 AttributeType,
746 uint32 AttributeLength,
747 const void *AttributePtr)
748 {
749 CSSM_CONTEXT_ATTRIBUTE newAttr;
750 CSSM_RETURN crtn;
751
752 newAttr.AttributeType = AttributeType;
753 newAttr.AttributeLength = AttributeLength;
754 newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr;
755 crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
756 if(crtn) {
757 p12LogCssmError("CSSM_UpdateContextAttributes", crtn);
758 }
759 return crtn;
760 }
761
762 /*
763 * Find private key by specified label, delete it.
764 */
765 CSSM_RETURN p12DeleteKey(
766 CSSM_DL_DB_HANDLE dlDbHand,
767 const CSSM_DATA &keyLabel)
768 {
769 CSSM_QUERY query;
770 CSSM_SELECTION_PREDICATE predicate;
771 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
772 CSSM_RETURN crtn;
773 CSSM_HANDLE resultHand = 0;
774
775 query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
776 query.Conjunctive = CSSM_DB_NONE;
777 query.NumSelectionPredicates = 1;
778 predicate.DbOperator = CSSM_DB_EQUAL;
779
780 predicate.Attribute.Info.AttributeNameFormat =
781 CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
782 predicate.Attribute.Info.Label.AttributeName =
783 (char*) P12_KEY_ATTR_LABEL_AND_HASH;
784 predicate.Attribute.Info.AttributeFormat =
785 CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
786 predicate.Attribute.Value = const_cast<CSSM_DATA_PTR>(&keyLabel);
787
788 query.SelectionPredicate = &predicate;
789 query.QueryLimits.TimeLimit = 0;
790 query.QueryLimits.SizeLimit = 1;
791 query.QueryFlags = 0;
792
793 crtn = CSSM_DL_DataGetFirst(dlDbHand,
794 &query,
795 &resultHand,
796 NULL, // attrs - don't need 'em
797 NULL, // theData - don't need it
798 &record);
799 /* abort only on success */
800 if(crtn) {
801 p12LogCssmError("CSSM_DL_DataGetFirst", crtn);
802 p12ErrorLog("***p12DeleteKey: can't find private key\n");
803 return crtn;
804 }
805
806 crtn = CSSM_DL_DataDelete(dlDbHand, record);
807 if(crtn) {
808 p12LogCssmError("CSSM_DL_DataDelete", crtn);
809 p12ErrorLog("***p12DeleteKey: can't delete private key\n");
810 }
811
812 CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
813 CSSM_DL_FreeUniqueRecord(dlDbHand, record);
814 return crtn;
815 }
816
817 /* convert App passphrase to array of chars used in P12 PBE */
818 void p12ImportPassPhrase(
819 CFStringRef inPhrase,
820 SecNssCoder &coder,
821 CSSM_DATA &outPhrase)
822 {
823 CFDataRef cfData = CFStringCreateExternalRepresentation(NULL,
824 inPhrase, kCFStringEncodingUTF8, 0);
825 if(cfData == NULL) {
826 p12ErrorLog("***p12ImportPassPhrase: can't convert passphrase to UTF8\n");
827 MacOSError::throwMe(paramErr);
828 }
829 unsigned keyLen = CFDataGetLength(cfData);
830 coder.allocItem(outPhrase, keyLen);
831 memmove(outPhrase.Data, CFDataGetBytePtr(cfData), keyLen);
832 CFRelease(cfData);
833 }