]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/p12Parse/p12Crypto.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / SecurityTests / clxutils / p12Parse / p12Crypto.cpp
1 /*
2 * Copyright (c) 2003,2005 Apple Computer, Inc. All Rights Reserved.
3 *
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.
9 *
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.
17 */
18
19 /*
20 * p12Crypto.cpp - PKCS12 Crypto routines. App space reference version.
21 *
22 * Created 2/28/03 by Doug Mitchell.
23 */
24
25 #include "p12Crypto.h"
26 #include "pkcs12Utils.h"
27 #include <security_cdsa_utils/cuCdsaUtils.h>
28 #include <Security/cssmapple.h>
29
30 /*
31 * Free memory via specified plugin's app-level allocator
32 */
33 static void appFreeCssmMemory(
34 CSSM_HANDLE hand,
35 void *p)
36 {
37 CSSM_API_MEMORY_FUNCS memFuncs;
38 CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs);
39 if(crtn) {
40 cssmPerror("CSSM_GetAPIMemoryFunctions", crtn);
41 /* oh well, leak and continue */
42 return;
43 }
44 memFuncs.free_func(p, memFuncs.AllocRef);
45 }
46
47 #define KEY_LABEL "p12 key"
48
49 /*
50 * Given appropriate P12-style parameters, cook up a CSSM_KEY.
51 */
52 CSSM_RETURN p12KeyGen_app(
53 CSSM_CSP_HANDLE cspHand,
54 CSSM_KEY &key,
55 bool isForEncr, // true: en/decrypt false: MAC
56 CSSM_ALGORITHMS keyAlg,
57 CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only
58 uint32 keySizeInBits,
59 uint32 iterCount,
60 const CSSM_DATA &salt,
61 const CSSM_DATA &pwd, // unicode, double null terminated
62 CSSM_DATA &iv) // referent is optional
63 {
64 CSSM_RETURN crtn;
65 CSSM_CC_HANDLE ccHand;
66 CSSM_DATA dummyLabel;
67 CSSM_ACCESS_CREDENTIALS creds;
68
69 memset(&key, 0, sizeof(CSSM_KEY));
70 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
71
72 /* infer key derivation algorithm */
73 CSSM_ALGORITHMS deriveAlg = CSSM_ALGID_NONE;
74 if(pbeHashAlg != CSSM_ALGID_SHA1) {
75 return CSSMERR_CSP_INVALID_ALGORITHM;
76 }
77 if(isForEncr) {
78 /*
79 * FIXME - if this key is going to be used to wrap/unwrap a
80 * shrouded key bag, its usage will change accordingly...
81 */
82 deriveAlg = CSSM_ALGID_PKCS12_PBE_ENCR;
83 }
84 else {
85 deriveAlg = CSSM_ALGID_PKCS12_PBE_MAC;
86 }
87 CSSM_CRYPTO_DATA seed;
88 seed.Param = pwd;
89 seed.Callback = NULL;
90 seed.CallerCtx = NULL;
91
92 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
93 deriveAlg,
94 keyAlg,
95 keySizeInBits,
96 &creds,
97 NULL, // BaseKey
98 iterCount,
99 &salt,
100 &seed, // seed
101 &ccHand);
102 if(crtn) {
103 cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
104 return crtn;
105 }
106
107 dummyLabel.Length = strlen(KEY_LABEL);
108 dummyLabel.Data = (uint8 *)KEY_LABEL;
109
110 /* KEYUSE_ANY - this is just an ephemeral session key */
111 crtn = CSSM_DeriveKey(ccHand,
112 &iv,
113 CSSM_KEYUSE_ANY,
114 //CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
115 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
116 &dummyLabel,
117 NULL, // cred and acl
118 &key);
119 CSSM_DeleteContext(ccHand);
120 if(crtn) {
121 cuPrintError("CSSM_DeriveKey", crtn);
122 }
123 return crtn;
124 }
125
126 /*
127 * Decrypt (typically, an encrypted P7 ContentInfo contents or
128 * a P12 ShroudedKeyBag).
129 */
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.
140 uint32 iterCount,
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)
145 {
146 CSSM_RETURN crtn;
147 CSSM_KEY ckey;
148 CSSM_CC_HANDLE ccHand = 0;
149
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);
155 ivPtr = &iv;
156 }
157
158 /* P12 style key derivation */
159 crtn = p12KeyGen_app(cspHand, ckey, true, keyAlg, pbeHashAlg,
160 keySizeInBits, iterCount, salt, pwd, iv);
161 if(crtn) {
162 return crtn;
163 }
164
165 /* CSSM context */
166 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
167 encrAlg,
168 mode,
169 NULL, // access cred
170 &ckey,
171 ivPtr, // InitVector, optional
172 padding,
173 NULL, // Params
174 &ccHand);
175 if(crtn) {
176 cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
177 return crtn;
178 }
179
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,
185 &cipherText,
186 1,
187 &ourPtext,
188 1,
189 &bytesDecrypted,
190 &remData);
191 if(crtn) {
192 cuPrintError("CSSM_EncryptData", crtn);
193 }
194 else {
195 coder.allocCopyItem(ourPtext, plainText);
196 plainText.Length = bytesDecrypted;
197
198 /* plaintext copied into coder space; free the memory allocated
199 * by the CSP */
200 appFreeCssmMemory(cspHand, ourPtext.Data);
201 }
202 /* an artifact of CSPFUllPLuginSession - this never contains
203 * valid data but sometimes gets mallocds */
204 if(remData.Data) {
205 appFreeCssmMemory(cspHand, remData.Data);
206 }
207 CSSM_DeleteContext(ccHand);
208 CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
209 return crtn;
210 }
211
212 /*
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.
216 */
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!
221 unsigned iterCount,
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
226 {
227 CSSM_RETURN crtn;
228
229 /* P12 style key derivation */
230 unsigned keySizeInBits;
231 CSSM_ALGORITHMS hmacAlg;
232 switch(alg) {
233 case CSSM_ALGID_SHA1:
234 keySizeInBits = 160;
235 hmacAlg = CSSM_ALGID_SHA1HMAC;
236 break;
237 case CSSM_ALGID_MD5:
238 /* not even sure if this is legal in p12 world... */
239 keySizeInBits = 128;
240 hmacAlg = CSSM_ALGID_MD5HMAC;
241 break;
242 default:
243 return CSSMERR_CSP_INVALID_ALGORITHM;
244 }
245 CSSM_KEY macKey;
246 CSSM_DATA iv = {0, NULL};
247 crtn = p12KeyGen_app(cspHand, macKey, false, hmacAlg, alg,
248 keySizeInBits, iterCount, salt, pwd, iv);
249 if(crtn) {
250 return crtn;
251 }
252
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);
257 if(crtn) {
258 cuPrintError("CSSM_CSP_CreateMacContext", crtn);
259 return crtn;
260 }
261
262 crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData);
263 if(crtn) {
264 cuPrintError("CSSM_GenerateMac", crtn);
265 }
266 CSSM_DeleteContext(ccHand);
267 CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE);
268 return crtn;
269 }
270
271 /*
272 * Verify MAC on an existing PFX.
273 */
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
279 {
280 if(pfx.macData == NULL) {
281 return CSSMERR_CSP_INVALID_SIGNATURE;
282 }
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;
289 }
290 uint32 iterCount = 0;
291 CSSM_DATA &citer = macData.iterations;
292 if(!p12DataToInt(citer, iterCount)) {
293 return CSSMERR_CSP_INVALID_ATTR_ROUNDS;
294 }
295 if(iterCount == 0) {
296 /* optional, default 1 */
297 iterCount = 1;
298 }
299
300 /*
301 * In classic fashion, the PKCS12 spec now says:
302 *
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.
306 *
307 * So here we go.
308 */
309 CSSM_DATA genMac;
310 CSSM_RETURN crtn = p12GenMac_app(cspHand, *pfx.authSafe.content.data,
311 macAlg, iterCount, macData.macSalt, pwd, coder, genMac);
312 if(crtn) {
313 return crtn;
314 }
315 if(nssCompareCssmData(&genMac, &digestInfo.digest)) {
316 return CSSM_OK;
317 }
318 else {
319 return CSSMERR_CSP_VERIFY_FAILED;
320 }
321 }
322