]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/p12/p12Crypto.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / p12 / p12Crypto.cpp
1 /*
2 * Copyright (c) 2003-2004 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 "p12pbe.h"
27 #include <security_pkcs12/pkcs12Utils.h>
28 #include <security_cdsa_utils/cuCdsaUtils.h>
29 #include <Security/cssmapple.h>
30
31 /*
32 * Free memory via specified plugin's app-level allocator
33 */
34 static void appFreeCssmMemory(
35 CSSM_HANDLE hand,
36 void *p)
37 {
38 CSSM_API_MEMORY_FUNCS memFuncs;
39 CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs);
40 if(crtn) {
41 cssmPerror("CSSM_GetAPIMemoryFunctions", crtn);
42 /* oh well, leak and continue */
43 return;
44 }
45 memFuncs.free_func(p, memFuncs.AllocRef);
46 }
47
48 /*
49 * Given appropriate P12-style parameters, cook up a CSSM_KEY.
50 * Eventually this will use DeriveKey; for now we do it ourself.
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 SecNssCoder &coder) // for mallocing KeyData
64 {
65 memset(&key, 0, sizeof(CSSM_KEY));
66 unsigned keyBytes = (keySizeInBits + 7) / 8;
67 coder.allocItem(key.KeyData, keyBytes);
68 CSSM_RETURN crtn = p12PbeGen_app(pwd,
69 salt.Data, salt.Length,
70 iterCount,
71 isForEncr ? PBE_ID_Key : PBE_ID_Mac,
72 pbeHashAlg,
73 cspHand,
74 (unsigned char *)key.KeyData.Data,
75 key.KeyData.Length);
76 if(crtn) {
77 cuPrintError("p12PbeGen(key)", crtn);
78 return crtn;
79 }
80
81 /* fill in the blanks */
82 CSSM_KEYHEADER &hdr = key.KeyHeader;
83 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
84 /* CspId blank */
85 hdr.BlobType = CSSM_KEYBLOB_RAW;
86 hdr.AlgorithmId = keyAlg;
87 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
88 hdr.KeyClass = CSSM_KEYCLASS_SESSION_KEY;
89 hdr.KeyUsage = CSSM_KEYUSE_ANY;
90 /* start/end date unknown, leave zero */
91 hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
92 hdr.WrapMode = CSSM_ALGMODE_NONE;
93 hdr.LogicalKeySizeInBits = keySizeInBits;
94
95 /* P12 style IV derivation, optional */
96 if(iv.Data != NULL) {
97 crtn = p12PbeGen_app(pwd,
98 salt.Data, salt.Length,
99 iterCount,
100 PBE_ID_IV,
101 pbeHashAlg,
102 cspHand,
103 iv.Data, iv.Length);
104 if(crtn) {
105 cuPrintError("p12PbeGen (IV)", crtn);
106 return crtn;
107 }
108 }
109
110 return CSSM_OK;
111 }
112
113 /*
114 * Decrypt (typically, an encrypted P7 ContentInfo contents or
115 * a P12 ShroudedKeyBag).
116 */
117 CSSM_RETURN p12Decrypt_app(
118 CSSM_CSP_HANDLE cspHand,
119 const CSSM_DATA &cipherText,
120 CSSM_ALGORITHMS keyAlg,
121 CSSM_ALGORITHMS encrAlg,
122 CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only
123 uint32 keySizeInBits,
124 uint32 blockSizeInBytes, // for IV
125 CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc.
126 CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc.
127 uint32 iterCount,
128 const CSSM_DATA &salt,
129 const CSSM_DATA &pwd, // unicode, double null terminated
130 SecNssCoder &coder, // for mallocing KeyData and plainText
131 CSSM_DATA &plainText)
132 {
133 CSSM_RETURN crtn;
134 CSSM_KEY ckey;
135 CSSM_CC_HANDLE ccHand = 0;
136
137 /* P12 style IV derivation, optional */
138 CSSM_DATA iv = {0, NULL};
139 CSSM_DATA_PTR ivPtr = NULL;
140 if(blockSizeInBytes) {
141 coder.allocItem(iv, blockSizeInBytes);
142 ivPtr = &iv;
143 }
144
145 /* P12 style key derivation */
146 crtn = p12KeyGen_app(cspHand, ckey, true, keyAlg, pbeHashAlg,
147 keySizeInBits, iterCount, salt, pwd, iv, coder);
148 if(crtn) {
149 return crtn;
150 }
151
152 /* CSSM context */
153 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
154 encrAlg,
155 mode,
156 NULL, // access cred
157 &ckey,
158 ivPtr, // InitVector, optional
159 padding,
160 NULL, // Params
161 &ccHand);
162 if(crtn) {
163 cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
164 return crtn;
165 }
166
167 /* go - CSP mallocs ptext and rem data */
168 CSSM_DATA ourPtext = {0, NULL};
169 CSSM_DATA remData = {0, NULL};
170 uint32 bytesDecrypted;
171 crtn = CSSM_DecryptData(ccHand,
172 &cipherText,
173 1,
174 &ourPtext,
175 1,
176 &bytesDecrypted,
177 &remData);
178 if(crtn) {
179 cuPrintError("CSSM_EncryptData", crtn);
180 }
181 else {
182 coder.allocCopyItem(ourPtext, plainText);
183 plainText.Length = bytesDecrypted;
184
185 /* plaintext copied into coder space; free the memory allocated
186 * by the CSP */
187 appFreeCssmMemory(cspHand, ourPtext.Data);
188 }
189 /* an artifact of CSPFUllPLuginSession - this never contains
190 * valid data but sometimes gets mallocds */
191 if(remData.Data) {
192 appFreeCssmMemory(cspHand, remData.Data);
193 }
194 CSSM_DeleteContext(ccHand);
195 return crtn;
196 }
197
198 /*
199 * Calculate the MAC for a PFX. Caller is either going compare
200 * the result against an existing PFX's MAC or drop the result into
201 * a newly created PFX.
202 */
203 CSSM_RETURN p12GenMac_app(
204 CSSM_CSP_HANDLE cspHand,
205 const CSSM_DATA &ptext, // e.g., NSS_P12_DecodedPFX.derAuthSaafe
206 CSSM_ALGORITHMS alg, // better be SHA1!
207 unsigned iterCount,
208 const CSSM_DATA &salt,
209 const CSSM_DATA &pwd, // unicode, double null terminated
210 SecNssCoder &coder, // for mallocing macData
211 CSSM_DATA &macData) // RETURNED
212 {
213 CSSM_RETURN crtn;
214
215 /* P12 style key derivation */
216 unsigned keySizeInBits;
217 CSSM_ALGORITHMS hmacAlg;
218 switch(alg) {
219 case CSSM_ALGID_SHA1:
220 keySizeInBits = 160;
221 hmacAlg = CSSM_ALGID_SHA1HMAC;
222 break;
223 case CSSM_ALGID_MD5:
224 /* not even sure if this is legal in p12 world... */
225 keySizeInBits = 128;
226 hmacAlg = CSSM_ALGID_MD5HMAC;
227 break;
228 default:
229 return CSSMERR_CSP_INVALID_ALGORITHM;
230 }
231 CSSM_KEY macKey;
232 CSSM_DATA iv = {0, NULL};
233 crtn = p12KeyGen_app(cspHand, macKey, false, hmacAlg, alg,
234 keySizeInBits, iterCount, salt, pwd, iv, coder);
235 if(crtn) {
236 return crtn;
237 }
238
239 /* prealloc the mac data */
240 coder.allocItem(macData, keySizeInBits / 8);
241 CSSM_CC_HANDLE ccHand = 0;
242 crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand);
243 if(crtn) {
244 cuPrintError("CSSM_CSP_CreateMacContext", crtn);
245 return crtn;
246 }
247
248 crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData);
249 if(crtn) {
250 cuPrintError("CSSM_GenerateMac", crtn);
251 }
252 CSSM_DeleteContext(ccHand);
253 return crtn;
254 }
255
256 /*
257 * Verify MAC on an existing PFX.
258 */
259 CSSM_RETURN p12VerifyMac_app(
260 const NSS_P12_DecodedPFX &pfx,
261 CSSM_CSP_HANDLE cspHand,
262 const CSSM_DATA &pwd, // unicode, double null terminated
263 SecNssCoder &coder) // for temp mallocs
264 {
265 if(pfx.macData == NULL) {
266 return CSSMERR_CSP_INVALID_SIGNATURE;
267 }
268 NSS_P12_MacData &macData = *pfx.macData;
269 NSS_P7_DigestInfo &digestInfo = macData.mac;
270 CSSM_OID &algOid = digestInfo.digestAlgorithm.algorithm;
271 CSSM_ALGORITHMS macAlg;
272 if(!cssmOidToAlg(&algOid, &macAlg)) {
273 return CSSMERR_CSP_INVALID_ALGORITHM;
274 }
275 uint32 iterCount = 0;
276 CSSM_DATA &citer = macData.iterations;
277 if(!p12DataToInt(citer, iterCount)) {
278 return CSSMERR_CSP_INVALID_ATTR_ROUNDS;
279 }
280 if(iterCount == 0) {
281 /* optional, default 1 */
282 iterCount = 1;
283 }
284
285 /*
286 * In classic fashion, the PKCS12 spec now says:
287 *
288 * When password integrity mode is used to secure a PFX PDU,
289 * an SHA-1 HMAC is computed on the BER-encoding of the contents
290 * of the content field of the authSafe field in the PFX PDU.
291 *
292 * So here we go.
293 */
294 CSSM_DATA genMac;
295 CSSM_RETURN crtn = p12GenMac_app(cspHand, *pfx.authSafe.content.data,
296 macAlg, iterCount, macData.macSalt, pwd, coder, genMac);
297 if(crtn) {
298 return crtn;
299 }
300 if(nssCompareCssmData(&genMac, &digestInfo.digest)) {
301 return CSSM_OK;
302 }
303 else {
304 return CSSMERR_CSP_VERIFY_FAILED;
305 }
306 }
307