2 * Copyright (c) 2003,2005 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
20 * p12Crypto.cpp - PKCS12 Crypto routines. App space reference version.
22 * Created 2/28/03 by Doug Mitchell.
25 #include "p12Crypto.h"
26 #include "pkcs12Utils.h"
27 #include <security_cdsa_utils/cuCdsaUtils.h>
28 #include <Security/cssmapple.h>
31 * Free memory via specified plugin's app-level allocator
33 static void appFreeCssmMemory(
37 CSSM_API_MEMORY_FUNCS memFuncs
;
38 CSSM_RETURN crtn
= CSSM_GetAPIMemoryFunctions(hand
, &memFuncs
);
40 cssmPerror("CSSM_GetAPIMemoryFunctions", crtn
);
41 /* oh well, leak and continue */
44 memFuncs
.free_func(p
, memFuncs
.AllocRef
);
47 #define KEY_LABEL "p12 key"
50 * Given appropriate P12-style parameters, cook up a CSSM_KEY.
52 CSSM_RETURN
p12KeyGen_app(
53 CSSM_CSP_HANDLE cspHand
,
55 bool isForEncr
, // true: en/decrypt false: MAC
56 CSSM_ALGORITHMS keyAlg
,
57 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
60 const CSSM_DATA
&salt
,
61 const CSSM_DATA
&pwd
, // unicode, double null terminated
62 CSSM_DATA
&iv
) // referent is optional
65 CSSM_CC_HANDLE ccHand
;
67 CSSM_ACCESS_CREDENTIALS creds
;
69 memset(&key
, 0, sizeof(CSSM_KEY
));
70 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
72 /* infer key derivation algorithm */
73 CSSM_ALGORITHMS deriveAlg
= CSSM_ALGID_NONE
;
74 if(pbeHashAlg
!= CSSM_ALGID_SHA1
) {
75 return CSSMERR_CSP_INVALID_ALGORITHM
;
79 * FIXME - if this key is going to be used to wrap/unwrap a
80 * shrouded key bag, its usage will change accordingly...
82 deriveAlg
= CSSM_ALGID_PKCS12_PBE_ENCR
;
85 deriveAlg
= CSSM_ALGID_PKCS12_PBE_MAC
;
87 CSSM_CRYPTO_DATA seed
;
90 seed
.CallerCtx
= NULL
;
92 crtn
= CSSM_CSP_CreateDeriveKeyContext(cspHand
,
103 cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn
);
107 dummyLabel
.Length
= strlen(KEY_LABEL
);
108 dummyLabel
.Data
= (uint8
*)KEY_LABEL
;
110 /* KEYUSE_ANY - this is just an ephemeral session key */
111 crtn
= CSSM_DeriveKey(ccHand
,
114 //CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
115 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
117 NULL
, // cred and acl
119 CSSM_DeleteContext(ccHand
);
121 cuPrintError("CSSM_DeriveKey", crtn
);
127 * Decrypt (typically, an encrypted P7 ContentInfo contents or
128 * a P12 ShroudedKeyBag).
130 CSSM_RETURN
p12Decrypt_app(
131 CSSM_CSP_HANDLE cspHand
,
132 const CSSM_DATA
&cipherText
,
133 CSSM_ALGORITHMS keyAlg
,
134 CSSM_ALGORITHMS encrAlg
,
135 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
136 uint32 keySizeInBits
,
137 uint32 blockSizeInBytes
, // for IV
138 CSSM_PADDING padding
, // CSSM_PADDING_PKCS7, etc.
139 CSSM_ENCRYPT_MODE mode
, // CSSM_ALGMODE_CBCPadIV8, etc.
141 const CSSM_DATA
&salt
,
142 const CSSM_DATA
&pwd
, // unicode, double null terminated
143 SecNssCoder
&coder
, // for mallocing KeyData and plainText
144 CSSM_DATA
&plainText
)
148 CSSM_CC_HANDLE ccHand
= 0;
150 /* P12 style IV derivation, optional */
151 CSSM_DATA iv
= {0, NULL
};
152 CSSM_DATA_PTR ivPtr
= NULL
;
153 if(blockSizeInBytes
) {
154 coder
.allocItem(iv
, blockSizeInBytes
);
158 /* P12 style key derivation */
159 crtn
= p12KeyGen_app(cspHand
, ckey
, true, keyAlg
, pbeHashAlg
,
160 keySizeInBits
, iterCount
, salt
, pwd
, iv
);
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_DATA ourPtext
= {0, NULL
};
182 CSSM_DATA remData
= {0, NULL
};
183 uint32 bytesDecrypted
;
184 crtn
= CSSM_DecryptData(ccHand
,
192 cuPrintError("CSSM_EncryptData", crtn
);
195 coder
.allocCopyItem(ourPtext
, plainText
);
196 plainText
.Length
= bytesDecrypted
;
198 /* plaintext copied into coder space; free the memory allocated
200 appFreeCssmMemory(cspHand
, ourPtext
.Data
);
202 /* an artifact of CSPFUllPLuginSession - this never contains
203 * valid data but sometimes gets mallocds */
205 appFreeCssmMemory(cspHand
, remData
.Data
);
207 CSSM_DeleteContext(ccHand
);
208 CSSM_FreeKey(cspHand
, NULL
, &ckey
, CSSM_FALSE
);
213 * Calculate the MAC for a PFX. Caller is either going compare
214 * the result against an existing PFX's MAC or drop the result into
215 * a newly created PFX.
217 CSSM_RETURN
p12GenMac_app(
218 CSSM_CSP_HANDLE cspHand
,
219 const CSSM_DATA
&ptext
, // e.g., NSS_P12_DecodedPFX.derAuthSaafe
220 CSSM_ALGORITHMS alg
, // better be SHA1!
222 const CSSM_DATA
&salt
,
223 const CSSM_DATA
&pwd
, // unicode, double null terminated
224 SecNssCoder
&coder
, // for mallocing macData
225 CSSM_DATA
&macData
) // RETURNED
229 /* P12 style key derivation */
230 unsigned keySizeInBits
;
231 CSSM_ALGORITHMS hmacAlg
;
233 case CSSM_ALGID_SHA1
:
235 hmacAlg
= CSSM_ALGID_SHA1HMAC
;
238 /* not even sure if this is legal in p12 world... */
240 hmacAlg
= CSSM_ALGID_MD5HMAC
;
243 return CSSMERR_CSP_INVALID_ALGORITHM
;
246 CSSM_DATA iv
= {0, NULL
};
247 crtn
= p12KeyGen_app(cspHand
, macKey
, false, hmacAlg
, alg
,
248 keySizeInBits
, iterCount
, salt
, pwd
, iv
);
253 /* prealloc the mac data */
254 coder
.allocItem(macData
, keySizeInBits
/ 8);
255 CSSM_CC_HANDLE ccHand
= 0;
256 crtn
= CSSM_CSP_CreateMacContext(cspHand
, hmacAlg
, &macKey
, &ccHand
);
258 cuPrintError("CSSM_CSP_CreateMacContext", crtn
);
262 crtn
= CSSM_GenerateMac (ccHand
, &ptext
, 1, &macData
);
264 cuPrintError("CSSM_GenerateMac", crtn
);
266 CSSM_DeleteContext(ccHand
);
267 CSSM_FreeKey(cspHand
, NULL
, &macKey
, CSSM_FALSE
);
272 * Verify MAC on an existing PFX.
274 CSSM_RETURN
p12VerifyMac_app(
275 const NSS_P12_DecodedPFX
&pfx
,
276 CSSM_CSP_HANDLE cspHand
,
277 const CSSM_DATA
&pwd
, // unicode, double null terminated
278 SecNssCoder
&coder
) // for temp mallocs
280 if(pfx
.macData
== NULL
) {
281 return CSSMERR_CSP_INVALID_SIGNATURE
;
283 NSS_P12_MacData
&macData
= *pfx
.macData
;
284 NSS_P7_DigestInfo
&digestInfo
= macData
.mac
;
285 CSSM_OID
&algOid
= digestInfo
.digestAlgorithm
.algorithm
;
286 CSSM_ALGORITHMS macAlg
;
287 if(!cssmOidToAlg(&algOid
, &macAlg
)) {
288 return CSSMERR_CSP_INVALID_ALGORITHM
;
290 uint32 iterCount
= 0;
291 CSSM_DATA
&citer
= macData
.iterations
;
292 if(!p12DataToInt(citer
, iterCount
)) {
293 return CSSMERR_CSP_INVALID_ATTR_ROUNDS
;
296 /* optional, default 1 */
301 * In classic fashion, the PKCS12 spec now says:
303 * When password integrity mode is used to secure a PFX PDU,
304 * an SHA-1 HMAC is computed on the BER-encoding of the contents
305 * of the content field of the authSafe field in the PFX PDU.
310 CSSM_RETURN crtn
= p12GenMac_app(cspHand
, *pfx
.authSafe
.content
.data
,
311 macAlg
, iterCount
, macData
.macSalt
, pwd
, coder
, genMac
);
315 if(nssCompareCssmData(&genMac
, &digestInfo
.digest
)) {
319 return CSSMERR_CSP_VERIFY_FAILED
;