]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_pkcs12/lib/pkcs12Utils.cpp
Security-59754.41.1.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/errors.h>
37 #include <security_cdsa_utils/cuCdsaUtils.h>
38 #include <Security/oidsattr.h>
39 #include <Security/oidsalg.h>
40 #include <Security/cssmapple.h>
41
42 /* malloc a NULL-ed array of pointers of size num+1 */
43 void **p12NssNullArray(
44 uint32 num,
45 SecNssCoder &coder)
46 {
47 unsigned len = (num + 1) * sizeof(void *);
48 void **p = (void **)coder.malloc(len);
49 memset(p, 0, len);
50 return p;
51 }
52
53 /* CSSM_DATA --> uint32. Returns true if OK. */
54 bool p12DataToInt(
55 const CSSM_DATA &cdata,
56 uint32 &u)
57 {
58 if((cdata.Length == 0) || (cdata.Data == NULL)) {
59 /* default/not present */
60 u = 0;
61 return true;
62 }
63 CSSM_SIZE len = cdata.Length;
64 if(len > sizeof(uint32)) {
65 return false;
66 }
67
68 uint32 rtn = 0;
69 uint8 *cp = cdata.Data;
70 for(uint32 i=0; i<len; i++) {
71 rtn = (rtn << 8) | *cp++;
72 }
73 u = rtn;
74 return true;
75 }
76
77 /* uint32 --> CSSM_DATA */
78 void p12IntToData(
79 uint32 num,
80 CSSM_DATA &cdata,
81 SecNssCoder &coder)
82 {
83 uint32 len = 0;
84
85 if(num < 0x100) {
86 len = 1;
87 }
88 else if(num < 0x10000) {
89 len = 2;
90 }
91 else if(num < 0x1000000) {
92 len = 3;
93 }
94 else {
95 len = 4;
96 }
97 coder.allocItem(cdata, len);
98 uint8 *cp = &cdata.Data[len - 1];
99 for(unsigned i=0; i<len; i++) {
100 *cp-- = num & 0xff;
101 num >>= 8;
102 }
103 }
104
105 /* CFDataRef <--> CSSM_DATA */
106 CFDataRef CF_RETURNS_RETAINED p12CssmDataToCf(
107 const CSSM_DATA &c)
108 {
109 return CFDataCreate(NULL, c.Data, c.Length);
110 }
111
112 void p12CfDataToCssm(
113 CFDataRef cf,
114 CSSM_DATA &c,
115 SecNssCoder &coder)
116 {
117 coder.allocCopyItem(CFDataGetBytePtr(cf),
118 CFDataGetLength(cf), c);
119 }
120
121 /*
122 * Attempt to convert a CFStringRef, which represents a SafeBag's
123 * FriendlyName, to a UTF8-encoded CSSM_DATA. The CSSM_DATA and its
124 * referent are allocated in the specified SecNssCoder's memory.
125 * No guarantee that this conversion works. If it doesn't we return
126 * NULL and caller must be prepared to deal with that.
127 */
128 CSSM_DATA_PTR p12StringToUtf8(
129 CFStringRef cfStr,
130 SecNssCoder &coder)
131 {
132 if(cfStr == NULL) {
133 return NULL;
134 }
135
136 CFIndex strLen = 0;
137 CFRange range = { 0, CFStringGetLength(cfStr) };
138 CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &strLen);
139 if(strLen == 0) {
140 return NULL;
141 }
142
143 CSSM_DATA_PTR rtn = coder.mallocn<CSSM_DATA>();
144 coder.allocItem(*rtn, strLen);
145
146 if(!CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, 0, FALSE, (UInt8*)rtn->Data, strLen, &strLen)) {
147 /* not convertible from native Unicode to UTF8 */
148 return NULL;
149 }
150 return rtn;
151 }
152
153 /*
154 * Enum to string mappper.
155 * Maybe DEBUG only.
156 */
157 /*
158 * Each type of attribute has a name/value pair in a table of these:
159 */
160 typedef struct {
161 unsigned value;
162 const char *name;
163 } p12NameValuePair;
164
165 /* declare one entry in a table of p12NameValuePair */
166 #define NVP(attr) {attr, #attr}
167
168 /* the NULL entry which terminates all p12NameValuePair tables */
169 #define NVP_END {0, NULL}
170
171 static const p12NameValuePair p7CITypeNames[] =
172 {
173 NVP(CT_None),
174 NVP(CT_Data),
175 NVP(CT_SignedData),
176 NVP(CT_EnvData),
177 NVP(CT_SignedEnvData),
178 NVP(CT_DigestData),
179 NVP(CT_EncryptedData),
180 NVP_END
181 };
182
183 static const p12NameValuePair p12BagTypeNames[] =
184 {
185 NVP(BT_None),
186 NVP(BT_KeyBag),
187 NVP(BT_ShroudedKeyBag),
188 NVP(BT_CertBag),
189 NVP(BT_CrlBag),
190 NVP(BT_SecretBag),
191 NVP(BT_SafeContentsBag),
192 NVP_END
193 };
194
195 static const char *typeToStr(
196 unsigned type,
197 const p12NameValuePair *table)
198 {
199 while(table->name) {
200 if(table->value == type) {
201 return table->name;
202 }
203 table++;
204 }
205 return "Unknown";
206 }
207
208 const char *p12BagTypeStr(
209 NSS_P12_SB_Type type)
210 {
211 return typeToStr(type, p12BagTypeNames);
212 }
213
214 const char *p7ContentInfoTypeStr(
215 NSS_P7_CI_Type type)
216 {
217 return typeToStr(type, p7CITypeNames);
218 }
219
220 /*
221 * OIDS for P12 and PKCS5 v1.5 (PBES1) encrypt and decrypt map to the following
222 * attributes.
223 */
224 typedef struct {
225 const CSSM_OID *oid;
226 CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES
227 CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE
228 CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5
229 uint32 keySizeInBits;
230 uint32 blockSizeInBytes; // for IV, optional
231 CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc.
232 CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc.
233 PKCS_Which pkcs; // PW_PKCS12 (for this module) or PW_PKCS5_v1_5
234 } PKCSOidInfo;
235
236 static const PKCSOidInfo pkcsOidInfos[] = {
237 /* PKCS12 first, the ones this module uses */
238 {
239 &CSSMOID_PKCS12_pbeWithSHAAnd128BitRC4,
240 CSSM_ALGID_RC4,
241 CSSM_ALGID_RC4,
242 CSSM_ALGID_SHA1,
243 128,
244 0, // RC4 is a stream cipher
245 CSSM_PADDING_NONE,
246 CSSM_ALGMODE_NONE,
247 PW_PKCS12
248 },
249 {
250 &CSSMOID_PKCS12_pbeWithSHAAnd40BitRC4,
251 CSSM_ALGID_RC4,
252 CSSM_ALGID_RC4,
253 CSSM_ALGID_SHA1,
254 40,
255 0, // RC4 is a stream cipher
256 CSSM_PADDING_NONE,
257 CSSM_ALGMODE_NONE,
258 PW_PKCS12
259 },
260 {
261 &CSSMOID_PKCS12_pbeWithSHAAnd3Key3DESCBC,
262 CSSM_ALGID_3DES_3KEY,
263 CSSM_ALGID_3DES_3KEY_EDE,
264 CSSM_ALGID_SHA1,
265 64 * 3,
266 8,
267 CSSM_PADDING_PKCS7,
268 CSSM_ALGMODE_CBCPadIV8,
269 PW_PKCS12
270 },
271 {
272 &CSSMOID_PKCS12_pbeWithSHAAnd2Key3DESCBC,
273 CSSM_ALGID_3DES_2KEY,
274 CSSM_ALGID_3DES_2KEY_EDE,
275 CSSM_ALGID_SHA1,
276 64 * 2,
277 8,
278 CSSM_PADDING_PKCS7,
279 CSSM_ALGMODE_CBCPadIV8,
280 PW_PKCS12
281 },
282 {
283 &CSSMOID_PKCS12_pbeWithSHAAnd128BitRC2CBC,
284 CSSM_ALGID_RC2,
285 CSSM_ALGID_RC2,
286 CSSM_ALGID_SHA1,
287 128,
288 8,
289 CSSM_PADDING_PKCS7,
290 CSSM_ALGMODE_CBCPadIV8,
291 PW_PKCS12
292 },
293 {
294 &CSSMOID_PKCS12_pbewithSHAAnd40BitRC2CBC,
295 CSSM_ALGID_RC2,
296 CSSM_ALGID_RC2,
297 CSSM_ALGID_SHA1,
298 40,
299 8,
300 CSSM_PADDING_PKCS7,
301 CSSM_ALGMODE_CBCPadIV8,
302 PW_PKCS12
303 },
304
305 /* PKCS5 v1.5, used for SecImportExport module */
306 {
307 &CSSMOID_PKCS5_pbeWithMD2AndDES,
308 CSSM_ALGID_DES,
309 CSSM_ALGID_DES,
310 CSSM_ALGID_MD2,
311 64,
312 8,
313 CSSM_PADDING_PKCS7,
314 CSSM_ALGMODE_CBCPadIV8,
315 PW_PKCS5_v1_5
316 },
317 {
318 &CSSMOID_PKCS5_pbeWithMD2AndRC2,
319 CSSM_ALGID_RC2,
320 CSSM_ALGID_RC2,
321 CSSM_ALGID_MD2,
322 64,
323 8,
324 CSSM_PADDING_PKCS7,
325 CSSM_ALGMODE_CBCPadIV8,
326 PW_PKCS5_v1_5
327 },
328 {
329 &CSSMOID_PKCS5_pbeWithMD5AndDES,
330 CSSM_ALGID_DES,
331 CSSM_ALGID_DES,
332 CSSM_ALGID_MD5,
333 64,
334 8,
335 CSSM_PADDING_PKCS7,
336 CSSM_ALGMODE_CBCPadIV8,
337 PW_PKCS5_v1_5
338 },
339 {
340 &CSSMOID_PKCS5_pbeWithMD5AndRC2,
341 CSSM_ALGID_RC2,
342 CSSM_ALGID_RC2,
343 CSSM_ALGID_MD5,
344 64,
345 8,
346 CSSM_PADDING_PKCS7,
347 CSSM_ALGMODE_CBCPadIV8,
348 PW_PKCS5_v1_5
349 },
350 {
351 &CSSMOID_PKCS5_pbeWithSHA1AndDES,
352 CSSM_ALGID_DES,
353 CSSM_ALGID_DES,
354 CSSM_ALGID_SHA1,
355 64,
356 8,
357 CSSM_PADDING_PKCS7,
358 CSSM_ALGMODE_CBCPadIV8,
359 PW_PKCS5_v1_5
360 },
361 {
362 &CSSMOID_PKCS5_pbeWithSHA1AndRC2,
363 CSSM_ALGID_RC2,
364 CSSM_ALGID_RC2,
365 CSSM_ALGID_SHA1,
366 64,
367 8,
368 CSSM_PADDING_PKCS7,
369 CSSM_ALGMODE_CBCPadIV8,
370 PW_PKCS5_v1_5
371 },
372
373 /* finally one for PKCS5 v2.0, which has its own means of
374 * cooking up all the parameters */
375 {
376 &CSSMOID_PKCS5_PBES2,
377 CSSM_ALGID_NONE,
378 CSSM_ALGID_NONE,
379 CSSM_ALGID_NONE,
380 0, 0, 0, 0,
381 PW_PKCS5_v2
382 }
383 };
384
385 #define NUM_PKCS_OID_INFOS (sizeof(pkcsOidInfos) / sizeof(pkcsOidInfos[1]))
386
387 /* map an OID to the components */
388 /* returns false if OID not found */
389
390 /*
391 * NOTE: as of March 8 2004 this is also used by the SecImportExport
392 * module...not just PKCS12!
393 */
394 bool pkcsOidToParams(
395 const CSSM_OID *oid,
396 CSSM_ALGORITHMS &keyAlg, // e.g., CSSM_ALGID_DES
397 CSSM_ALGORITHMS &encrAlg, // e.g., CSSM_ALGID_3DES_3KEY_EDE
398 CSSM_ALGORITHMS &pbeHashAlg, // SHA1 or MD5
399 uint32 &keySizeInBits,
400 uint32 &blockSizeInBytes, // for IV, optional
401 CSSM_PADDING &padding, // CSSM_PADDING_PKCS7, etc.
402 CSSM_ENCRYPT_MODE &mode, // CSSM_ALGMODE_CBCPadIV8, etc.
403 PKCS_Which &pkcs) // PW_PKCS5_v1_5 or PW_PKCS12
404 {
405 const PKCSOidInfo *info = pkcsOidInfos;
406 pkcs = PW_None;
407
408 for(unsigned dex=0; dex<NUM_PKCS_OID_INFOS; dex++) {
409 if(nssCompareCssmData(oid, info->oid)) {
410 keyAlg = info->keyAlg;
411 encrAlg = info->encrAlg;
412 pbeHashAlg = info->pbeHashAlg;
413 keySizeInBits = info->keySizeInBits;
414 blockSizeInBytes = info->blockSizeInBytes;
415 padding = info->padding;
416 mode = info->mode;
417 pkcs = info->pkcs;
418 return true;
419 }
420 info++;
421 }
422 return false;
423 }
424
425 /*
426 * Verify MAC on an existing PFX.
427 */
428 CSSM_RETURN p12VerifyMac(
429 const NSS_P12_DecodedPFX &pfx,
430 CSSM_CSP_HANDLE cspHand,
431 const CSSM_DATA *pwd, // unicode, double null terminated
432 const CSSM_KEY *passKey,
433 SecNssCoder &coder) // for temp mallocs
434 {
435 if(pfx.macData == NULL) {
436 return CSSMERR_CSP_INVALID_SIGNATURE;
437 }
438 NSS_P12_MacData &macData = *pfx.macData;
439 NSS_P7_DigestInfo &digestInfo = macData.mac;
440 CSSM_OID &algOid = digestInfo.digestAlgorithm.algorithm;
441 CSSM_ALGORITHMS macAlg;
442 if(!cssmOidToAlg(&algOid, &macAlg)) {
443 return CSSMERR_CSP_INVALID_ALGORITHM;
444 }
445 uint32 iterCount = 0;
446 CSSM_DATA &citer = macData.iterations;
447 if(!p12DataToInt(citer, iterCount)) {
448 return CSSMERR_CSP_INVALID_ATTR_ROUNDS;
449 }
450 if(iterCount == 0) {
451 /* optional, default 1 */
452 iterCount = 1;
453 }
454
455 /*
456 * In classic fashion, the PKCS12 spec now says:
457 *
458 * When password integrity mode is used to secure a PFX PDU,
459 * an SHA-1 HMAC is computed on the BER-encoding of the contents
460 * of the content field of the authSafe field in the PFX PDU.
461 *
462 * So here we go.
463 */
464 CSSM_DATA genMac;
465 CSSM_RETURN crtn = p12GenMac(cspHand, *pfx.authSafe.content.data,
466 macAlg, iterCount, macData.macSalt, pwd, passKey, coder, genMac);
467 if(crtn) {
468 return crtn;
469 }
470 if(nssCompareCssmData(&genMac, &digestInfo.digest)) {
471 return CSSM_OK;
472 }
473 else {
474 return CSSMERR_CSP_VERIFY_FAILED;
475 }
476 }
477
478 /* we generate 8 random bytes of salt */
479 #define P12_SALT_LEN 8
480
481 void p12GenSalt(
482 CSSM_DATA &salt,
483 SecNssCoder &coder)
484 {
485 coder.allocItem(salt, P12_SALT_LEN);
486 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, P12_SALT_LEN, salt.Data));
487 }
488
489 /*
490 * Generate random label string to allow associating an imported private
491 * key with a cert.
492 */
493 void p12GenLabel(
494 CSSM_DATA &label,
495 SecNssCoder &coder)
496 {
497 /* first a random uint32 */
498 uint8 d[4];
499 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, 4, d));
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(errSecParam);
828 }
829 CFIndex keyLen = CFDataGetLength(cfData);
830 coder.allocItem(outPhrase, keyLen);
831 memmove(outPhrase.Data, CFDataGetBytePtr(cfData), keyLen);
832 CFRelease(cfData);
833 }