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