2 * Copyright (c) 2003-2004,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * pkc12Crypto.cpp - PKCS12-specific cyptrographic routines
28 #include "pkcs12Crypto.h"
29 #include "pkcs12Utils.h"
30 #include "pkcs12Debug.h"
31 #include <security_cdsa_utils/cuCdsaUtils.h>
32 #include <security_cdsa_utilities/cssmacl.h>
33 #include <security_keychain/Access.h>
36 * Given appropriate P12-style parameters, cook up a CSSM_KEY.
37 * Caller MUST CSSM_FreeKey() when it's done with the key.
39 #define KEY_LABEL "p12 key"
41 CSSM_RETURN
p12KeyGen(
42 CSSM_CSP_HANDLE cspHand
,
44 bool isForEncr
, // true: en/decrypt false: MAC
45 CSSM_ALGORITHMS keyAlg
,
46 CSSM_ALGORITHMS pbeHashAlg
, // actually must be SHA1 for now
49 const CSSM_DATA
&salt
,
50 /* exactly one of the following two must be valid */
51 const CSSM_DATA
*pwd
, // unicode external representation
52 const CSSM_KEY
*passKey
,
53 CSSM_DATA
&iv
) // referent is optional
56 CSSM_CC_HANDLE ccHand
;
58 CSSM_ACCESS_CREDENTIALS creds
;
60 memset(&key
, 0, sizeof(CSSM_KEY
));
61 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
63 /* infer key derivation algorithm */
64 CSSM_ALGORITHMS deriveAlg
= CSSM_ALGID_NONE
;
65 if(pbeHashAlg
!= CSSM_ALGID_SHA1
) {
66 return CSSMERR_CSP_INVALID_ALGORITHM
;
70 * FIXME - if this key is going to be used to wrap/unwrap a
71 * shrouded key bag, its usage will change accordingly...
73 deriveAlg
= CSSM_ALGID_PKCS12_PBE_ENCR
;
76 deriveAlg
= CSSM_ALGID_PKCS12_PBE_MAC
;
78 CSSM_CRYPTO_DATA seed
;
83 seed
.Param
.Data
= NULL
;
84 seed
.Param
.Length
= 0;
87 seed
.CallerCtx
= NULL
;
89 crtn
= CSSM_CSP_CreateDeriveKeyContext(cspHand
,
100 p12LogCssmError("CSSM_CSP_CreateDeriveKeyContext", crtn
);
104 dummyLabel
.Length
= strlen(KEY_LABEL
);
105 dummyLabel
.Data
= (uint8
*)KEY_LABEL
;
107 /* KEYUSE_ANY - this is just an ephemeral session key */
108 crtn
= CSSM_DeriveKey(ccHand
,
111 CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_SENSITIVE
,
113 NULL
, // cred and acl
115 CSSM_DeleteContext(ccHand
);
117 p12LogCssmError("CSSM_DeriveKey", crtn
);
123 * Decrypt (typically, an encrypted P7 ContentInfo contents)
125 CSSM_RETURN
p12Decrypt(
126 CSSM_CSP_HANDLE cspHand
,
127 const CSSM_DATA
&cipherText
,
128 CSSM_ALGORITHMS keyAlg
,
129 CSSM_ALGORITHMS encrAlg
,
130 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
131 uint32 keySizeInBits
,
132 uint32 blockSizeInBytes
, // for IV
133 CSSM_PADDING padding
, // CSSM_PADDING_PKCS7, etc.
134 CSSM_ENCRYPT_MODE mode
, // CSSM_ALGMODE_CBCPadIV8, etc.
136 const CSSM_DATA
&salt
,
137 /* exactly one of the following two must be valid */
138 const CSSM_DATA
*pwd
, // unicode external representation
139 const CSSM_KEY
*passKey
,
140 SecNssCoder
&coder
, // for mallocing plainText
141 CSSM_DATA
&plainText
)
145 CSSM_CC_HANDLE ccHand
= 0;
146 CSSM_DATA ourPtext
= {0, NULL
};
147 CSSM_DATA remData
= {0, NULL
};
149 /* P12 style IV derivation, optional */
150 CSSM_DATA iv
= {0, NULL
};
151 CSSM_DATA_PTR ivPtr
= NULL
;
152 if(blockSizeInBytes
) {
153 coder
.allocItem(iv
, blockSizeInBytes
);
157 /* P12 style key derivation */
158 crtn
= p12KeyGen(cspHand
, ckey
, true, keyAlg
, pbeHashAlg
,
159 keySizeInBits
, iterCount
, salt
, pwd
, passKey
, iv
);
163 /* subsequent errors to errOut: */
166 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
171 ivPtr
, // InitVector, optional
176 cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn
);
180 /* go - CSP mallocs ptext and rem data */
181 CSSM_SIZE bytesDecrypted
;
182 crtn
= CSSM_DecryptData(ccHand
,
190 cuPrintError("CSSM_DecryptData", crtn
);
193 coder
.allocCopyItem(ourPtext
, plainText
);
194 plainText
.Length
= bytesDecrypted
;
196 /* plaintext copied into coder space; free the memory allocated
198 freeCssmMemory(cspHand
, ourPtext
.Data
);
200 /* an artifact of CSPFullPLuginSession - this never contains
201 * valid data but sometimes gets mallocds */
203 freeCssmMemory(cspHand
, remData
.Data
);
207 CSSM_DeleteContext(ccHand
);
209 CSSM_FreeKey(cspHand
, NULL
, &ckey
, CSSM_FALSE
);
214 * Decrypt (typically, an encrypted P7 ContentInfo contents)
216 CSSM_RETURN
p12Encrypt(
217 CSSM_CSP_HANDLE cspHand
,
218 const CSSM_DATA
&plainText
,
219 CSSM_ALGORITHMS keyAlg
,
220 CSSM_ALGORITHMS encrAlg
,
221 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
222 uint32 keySizeInBits
,
223 uint32 blockSizeInBytes
, // for IV
224 CSSM_PADDING padding
, // CSSM_PADDING_PKCS7, etc.
225 CSSM_ENCRYPT_MODE mode
, // CSSM_ALGMODE_CBCPadIV8, etc.
227 const CSSM_DATA
&salt
,
228 /* exactly one of the following two must be valid */
229 const CSSM_DATA
*pwd
, // unicode external representation
230 const CSSM_KEY
*passKey
,
231 SecNssCoder
&coder
, // for mallocing cipherText
232 CSSM_DATA
&cipherText
)
236 CSSM_CC_HANDLE ccHand
= 0;
237 CSSM_DATA ourCtext
= {0, NULL
};
238 CSSM_DATA remData
= {0, NULL
};
240 /* P12 style IV derivation, optional */
241 CSSM_DATA iv
= {0, NULL
};
242 CSSM_DATA_PTR ivPtr
= NULL
;
243 if(blockSizeInBytes
) {
244 coder
.allocItem(iv
, blockSizeInBytes
);
248 /* P12 style key derivation */
249 crtn
= p12KeyGen(cspHand
, ckey
, true, keyAlg
, pbeHashAlg
,
250 keySizeInBits
, iterCount
, salt
, pwd
, passKey
, iv
);
254 /* subsequent errors to errOut: */
257 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
262 ivPtr
, // InitVector, optional
267 cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn
);
271 /* go - CSP mallocs ctext and rem data */
272 CSSM_SIZE bytesEncrypted
;
273 crtn
= CSSM_EncryptData(ccHand
,
281 cuPrintError("CSSM_DecryptData", crtn
);
284 coder
.allocCopyItem(ourCtext
, cipherText
);
285 cipherText
.Length
= bytesEncrypted
;
287 /* plaintext copied into coder space; free the memory allocated
289 freeCssmMemory(cspHand
, ourCtext
.Data
);
291 /* an artifact of CSPFUllPLuginSession - this never contains
292 * valid data but sometimes gets mallocds */
294 freeCssmMemory(cspHand
, remData
.Data
);
298 CSSM_DeleteContext(ccHand
);
300 CSSM_FreeKey(cspHand
, NULL
, &ckey
, CSSM_FALSE
);
305 * Calculate the MAC for a PFX. Caller is either going compare
306 * the result against an existing PFX's MAC or drop the result into
307 * a newly created PFX.
309 CSSM_RETURN
p12GenMac(
310 CSSM_CSP_HANDLE cspHand
,
311 const CSSM_DATA
&ptext
, // e.g., NSS_P12_DecodedPFX.derAuthSaafe
312 CSSM_ALGORITHMS alg
, // better be SHA1!
314 const CSSM_DATA
&salt
,
315 /* exactly one of the following two must be valid */
316 const CSSM_DATA
*pwd
, // unicode external representation
317 const CSSM_KEY
*passKey
,
318 SecNssCoder
&coder
, // for mallocing macData
319 CSSM_DATA
&macData
) // RETURNED
322 CSSM_CC_HANDLE ccHand
= 0;
324 /* P12 style key derivation */
325 unsigned keySizeInBits
;
326 CSSM_ALGORITHMS hmacAlg
;
328 case CSSM_ALGID_SHA1
:
330 hmacAlg
= CSSM_ALGID_SHA1HMAC
;
333 /* not even sure if this is legal in p12 world... */
335 hmacAlg
= CSSM_ALGID_MD5HMAC
;
338 return CSSMERR_CSP_INVALID_ALGORITHM
;
341 CSSM_DATA iv
= {0, NULL
};
342 crtn
= p12KeyGen(cspHand
, macKey
, false, hmacAlg
, alg
,
343 keySizeInBits
, iterCount
, salt
, pwd
, passKey
, iv
);
347 /* subsequent errors to errOut: */
349 /* prealloc the mac data */
350 coder
.allocItem(macData
, keySizeInBits
/ 8);
351 crtn
= CSSM_CSP_CreateMacContext(cspHand
, hmacAlg
, &macKey
, &ccHand
);
353 cuPrintError("CSSM_CSP_CreateMacContext", crtn
);
357 crtn
= CSSM_GenerateMac (ccHand
, &ptext
, 1, &macData
);
359 cuPrintError("CSSM_GenerateMac", crtn
);
363 CSSM_DeleteContext(ccHand
);
365 CSSM_FreeKey(cspHand
, NULL
, &macKey
, CSSM_FALSE
);
370 * Unwrap a shrouded key.
372 CSSM_RETURN
p12UnwrapKey(
373 CSSM_CSP_HANDLE cspHand
,
374 CSSM_DL_DB_HANDLE_PTR dlDbHand
, // optional
375 int keyIsPermanent
, // nonzero - store in DB
376 const CSSM_DATA
&shroudedKeyBits
,
377 CSSM_ALGORITHMS keyAlg
, // of the unwrapping key
378 CSSM_ALGORITHMS encrAlg
,
379 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
380 uint32 keySizeInBits
,
381 uint32 blockSizeInBytes
, // for IV
382 CSSM_PADDING padding
, // CSSM_PADDING_PKCS7, etc.
383 CSSM_ENCRYPT_MODE mode
, // CSSM_ALGMODE_CBCPadIV8, etc.
385 const CSSM_DATA
&salt
,
386 const CSSM_DATA
*pwd
, // unicode external representation
387 const CSSM_KEY
*passKey
,
388 SecNssCoder
&coder
, // for mallocing privKey
389 const CSSM_DATA
&labelData
,
390 SecAccessRef access
, // optional
392 CSSM_KEYUSE keyUsage
,
393 CSSM_KEYATTR_FLAGS keyAttrs
,
396 * Result: a private key, reference format, optionaly stored
399 CSSM_KEY_PTR
&privKey
)
403 CSSM_CC_HANDLE ccHand
= 0;
405 CSSM_KEY unwrappedKey
;
406 CSSM_KEYHEADER
&hdr
= wrappedKey
.KeyHeader
;
407 CSSM_DATA descrData
= {0, NULL
}; // not used for PKCS8 wrap
408 CSSM_KEYATTR_FLAGS reqAttr
= keyAttrs
;
410 ResourceControlContext rcc
;
411 ResourceControlContext
*rccPtr
= NULL
;
412 Security::KeychainCore::Access::Maker maker
;
414 /* P12 style IV derivation, optional */
415 CSSM_DATA iv
= {0, NULL
};
416 CSSM_DATA_PTR ivPtr
= NULL
;
417 if(blockSizeInBytes
) {
418 coder
.allocItem(iv
, blockSizeInBytes
);
422 /* P12 style key derivation */
423 crtn
= p12KeyGen(cspHand
, ckey
, true, keyAlg
, pbeHashAlg
,
424 keySizeInBits
, iterCount
, salt
, pwd
, passKey
, iv
);
428 /* subsequent errors to errOut: */
431 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
436 ivPtr
, // InitVector, optional
441 p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn
);
445 crtn
= p12AddContextAttribute(ccHand
,
446 CSSM_ATTRIBUTE_DL_DB_HANDLE
,
447 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE
),
450 p12LogCssmError("AddContextAttribute", crtn
);
456 * Cook up minimal WrappedKey header fields
458 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
459 memset(&unwrappedKey
, 0, sizeof(CSSM_KEY
));
461 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
462 hdr
.BlobType
= CSSM_KEYBLOB_WRAPPED
;
463 hdr
.Format
= CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8
;
466 * This one we do not know. The CSP will figure out the format
467 * of the unwrapped key after it decrypts the raw key material.
469 hdr
.AlgorithmId
= CSSM_ALGID_NONE
;
470 hdr
.KeyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
472 /* also inferred by CSP */
473 hdr
.LogicalKeySizeInBits
= 0;
474 hdr
.KeyAttr
= CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_EXTRACTABLE
;
475 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
476 hdr
.WrapAlgorithmId
= encrAlg
;
479 if(dlDbHand
&& keyIsPermanent
) {
480 reqAttr
|= CSSM_KEYATTR_PERMANENT
;
483 wrappedKey
.KeyData
= shroudedKeyBits
;
486 // Create a Access::Maker for the initial owner of the private key.
487 memset(&rcc
, 0, sizeof(rcc
));
488 maker
.initialOwner(rcc
);
492 crtn
= CSSM_UnwrapKey(ccHand
,
498 rccPtr
, // CredAndAclEntry
500 &descrData
); // required
502 p12LogCssmError("CSSM_UnwrapKey", crtn
);
503 if(crtn
== CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA
) {
504 /* report in a keychain-friendly way */
505 crtn
= errSecDuplicateItem
;
509 // Finally fix the acl and owner of the private key to the
510 // specified access control settings.
511 if((crtn
== CSSM_OK
) && !noAcl
) {
513 CssmClient::KeyAclBearer
bearer(
514 cspHand
, *privKey
, Allocator::standard());
515 SecPointer
<KeychainCore::Access
> initialAccess(access
?
516 KeychainCore::Access::required(access
) : /* caller-supplied */
517 new KeychainCore::Access("privateKey")); /* default */
518 initialAccess
->setAccess(bearer
, maker
);
520 catch (const CssmError
&e
) {
521 /* not implemented means we're talking to the CSP which does
522 * not implement ACLs */
523 if(e
.error
!= CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED
) {
528 p12ErrorLog("p12 exception on setAccess\n");
529 crtn
= errSecAuthFailed
; /* ??? */
535 CSSM_DeleteContext(ccHand
);
537 CSSM_FreeKey(cspHand
, NULL
, &ckey
, CSSM_FALSE
);
542 * Wrap a private key, yielding shrouded key bits.
544 CSSM_RETURN
p12WrapKey(
545 CSSM_CSP_HANDLE cspHand
,
546 CSSM_KEY_PTR privKey
,
547 const CSSM_ACCESS_CREDENTIALS
*privKeyCreds
,
548 CSSM_ALGORITHMS keyAlg
, // of the unwrapping key
549 CSSM_ALGORITHMS encrAlg
,
550 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
551 uint32 keySizeInBits
,
552 uint32 blockSizeInBytes
, // for IV
553 CSSM_PADDING padding
, // CSSM_PADDING_PKCS7, etc.
554 CSSM_ENCRYPT_MODE mode
, // CSSM_ALGMODE_CBCPadIV8, etc.
556 const CSSM_DATA
&salt
,
557 const CSSM_DATA
*pwd
, // unicode external representation
558 const CSSM_KEY
*passKey
,
559 SecNssCoder
&coder
, // for mallocing keyBits
560 CSSM_DATA
&shroudedKeyBits
) // RETURNED
564 CSSM_CC_HANDLE ccHand
= 0;
566 CSSM_CONTEXT_ATTRIBUTE attr
;
567 CSSM_DATA descrData
= {0, NULL
};
568 CSSM_ACCESS_CREDENTIALS creds
;
570 /* key must be extractable */
571 if (!(privKey
->KeyHeader
.KeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
572 return errSecDataNotAvailable
;
575 if(privKeyCreds
== NULL
) {
576 /* i.e., key is from the bare CSP with no ACL support */
577 memset(&creds
, 0, sizeof(creds
));
578 privKeyCreds
= &creds
;
581 /* P12 style IV derivation, optional */
582 CSSM_DATA iv
= {0, NULL
};
583 CSSM_DATA_PTR ivPtr
= NULL
;
584 if(blockSizeInBytes
) {
585 coder
.allocItem(iv
, blockSizeInBytes
);
589 /* P12 style key derivation */
590 crtn
= p12KeyGen(cspHand
, ckey
, true, keyAlg
, pbeHashAlg
,
591 keySizeInBits
, iterCount
, salt
, pwd
, passKey
, iv
);
595 /* subsequent errors to errOut: */
598 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
603 ivPtr
, // InitVector, optional
608 p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn
);
612 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
614 /* specify PKCS8 wrap format */
615 attr
.AttributeType
= CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
;
616 attr
.AttributeLength
= sizeof(uint32
);
617 attr
.Attribute
.Uint32
= CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8
;
618 crtn
= CSSM_UpdateContextAttributes(
623 p12LogCssmError("CSSM_UpdateContextAttributes", crtn
);
627 crtn
= CSSM_WrapKey(ccHand
,
630 &descrData
, // DescriptiveData
633 p12LogCssmError("CSSM_WrapKey", crtn
);
636 coder
.allocCopyItem(wrappedKey
.KeyData
, shroudedKeyBits
);
638 /* this was mallocd by CSP */
639 freeCssmMemory(cspHand
, wrappedKey
.KeyData
.Data
);
643 CSSM_DeleteContext(ccHand
);
645 CSSM_FreeKey(cspHand
, NULL
, &ckey
, CSSM_FALSE
);