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