]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/p12/p12pbe.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / p12 / p12pbe.cpp
1 /*
2 * Copyright (c) 2003 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 * p12pbe.h - PKCS12 PBE routine. App space reference version.
20 *
21 * Created 2/28/03 by Doug Mitchell.
22 */
23
24 #include "p12pbe.h"
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <Security/cssm.h>
29 #include <openssl/bn.h>
30 /*
31 * For development outside the CSP, malloc using stdlib.
32 * Inside the CSP we'll use CssmAllocator.
33 */
34 #define PBE_MALLOC malloc
35 #define PBE_FREE free
36
37 /*
38 * implementation dependent hash object
39 * for now just a Digest context handle
40 */
41 typedef CSSM_CC_HANDLE HashHand;
42 static HashHand hashCreate(CSSM_CSP_HANDLE cspHand,
43 CSSM_ALGORITHMS alg)
44 {
45 CSSM_CC_HANDLE hashHand;
46 CSSM_RETURN crtn = CSSM_CSP_CreateDigestContext(cspHand,
47 alg,
48 &hashHand);
49 if(crtn) {
50 printf("CSSM_CSP_CreateDigestContext error\n");
51 return 0;
52 }
53 return hashHand;
54 }
55
56 static CSSM_RETURN hashInit(HashHand hand)
57 {
58 return CSSM_DigestDataInit(hand);
59 }
60
61 static CSSM_RETURN hashUpdate(HashHand hand,
62 const unsigned char *buf,
63 unsigned bufLen)
64 {
65 const CSSM_DATA cdata = {bufLen, (uint8 *)buf};
66 return CSSM_DigestDataUpdate(hand, &cdata, 1);
67 }
68
69 static CSSM_RETURN hashFinal(HashHand hand,
70 unsigned char *digest, // mallocd by caller
71 unsigned *digestLen) // IN/OUT
72 {
73 CSSM_DATA cdata = {(uint32)digestLen, digest};
74 return CSSM_DigestDataFinal(hand, &cdata);
75 }
76
77 static CSSM_RETURN hashDone(HashHand hand)
78 {
79 return CSSM_DeleteContext(hand);
80 }
81
82 /*
83 * Create a "string" (in the loose p12 notation) of specified length
84 * from the concatention of copies of the specified input string.
85 */
86 static unsigned char *p12StrCat(
87 const unsigned char *inStr,
88 unsigned inStrLen,
89 unsigned outLen,
90 unsigned char *outStr = NULL) // if not present, we malloc
91 {
92 if(outStr == NULL) {
93 outStr = (unsigned char *)PBE_MALLOC(outLen);
94 }
95 unsigned toMove = outLen;
96 unsigned char *outp = outStr;
97 while(toMove) {
98 unsigned thisMove = inStrLen;
99 if(thisMove > toMove) {
100 thisMove = toMove;
101 }
102 memmove(outp, inStr, thisMove);
103 toMove -= thisMove;
104 outp += thisMove;
105 }
106 return outStr;
107 }
108
109 /*
110 * PBE generator per PKCS12 v.1 section B.2.
111 */
112 CSSM_RETURN p12PbeGen_app(
113 const CSSM_DATA &pwd, // unicode, double null terminated
114 const unsigned char *salt,
115 unsigned saltLen,
116 unsigned iterCount,
117 P12_PBE_ID pbeId,
118 CSSM_ALGORITHMS hashAlg, // MS5 or SHA1 only
119 CSSM_CSP_HANDLE cspHand,
120 /* result goes here, mallocd by caller */
121 unsigned char *outbuf,
122 unsigned outbufLen)
123 {
124 CSSM_RETURN ourRtn;
125 unsigned unipassLen = pwd.Length;
126 unsigned char *unipass = pwd.Data;
127
128 /*
129 * all variables of the form p12_<XXX> represent <XXX> from the
130 * PKCS12 spec. E.g., p12_u is u, the length of the digest output.
131 * Only difference here is: all of our sizes are in BYTES, not
132 * bits.
133 */
134 unsigned p12_r = iterCount;
135 unsigned p12_n = outbufLen;
136
137 unsigned p12_u; // hash output size
138 unsigned p12_v; // hash block size
139 unsigned char *p12_P = NULL; // catted passwords
140 unsigned char *p12_S = NULL; // catted salts
141
142 switch(hashAlg) {
143 case CSSM_ALGID_MD5:
144 p12_u = 16;
145 p12_v = 64;
146 break;
147 case CSSM_ALGID_SHA1:
148 p12_u = 20;
149 p12_v = 64;
150 break;
151 default:
152 return CSSMERR_CSP_INVALID_ALGORITHM;
153 }
154
155 /*
156 * 1. Construct a string, D (the “diversifier”), by
157 * concatenating v/8 copies of ID.
158 */
159 unsigned char *p12_D = NULL; // diversifier
160 p12_D = (unsigned char *)PBE_MALLOC(p12_v);
161 /* subsequent errors to errOut: */
162 for(unsigned dex=0; dex<p12_v; dex++) {
163 p12_D[dex] = (unsigned char)pbeId;
164 }
165
166 /*
167 * 2. Concatenate copies of the salt together to create
168 * a string S of length v * ceil(s/v) bits (the final copy
169 * of the salt may be truncated to create S). Note that if
170 * the salt is the empty string, then so is S.
171 */
172 unsigned p12_Slen = p12_v * ((saltLen + p12_v - 1) / p12_v);
173 if(p12_Slen) {
174 p12_S = p12StrCat(salt, saltLen, p12_Slen);
175 }
176
177
178 /*
179 * 3. Concatenate copies of the password together to create
180 * a string P of length v * ceil(p/v) bits (the final copy of
181 * the password may be truncated to create P). Note that
182 * if the password is the empty string, then so is P.
183 */
184 unsigned p12_Plen = p12_v * ((unipassLen + p12_v - 1) / p12_v);
185 if(p12_Plen) {
186 p12_P = p12StrCat(unipass, unipassLen, p12_Plen);
187 }
188
189 /*
190 * 4. Set I= S||P to be the concatenation of S and P.
191 */
192 unsigned char *p12_I =
193 (unsigned char *)PBE_MALLOC(p12_Slen + p12_Plen);
194 memmove(p12_I, p12_S, p12_Slen);
195 if(p12_Plen) {
196 memmove(p12_I + p12_Slen, p12_P, p12_Plen);
197 }
198
199 /*
200 * 5. Set c = ceil(n/u).
201 */
202 unsigned p12_c = (p12_n + p12_u - 1) / p12_u;
203
204 /* allocate c hash-output-size bufs */
205 unsigned char *p12_A = (unsigned char *)PBE_MALLOC(p12_c * p12_u);
206
207 /* one reusable hash object */
208 HashHand hashHand = hashCreate(cspHand, hashAlg);
209 if(!hashHand) {
210 return CSSMERR_CSP_INVALID_CONTEXT_HANDLE; // XXX
211 }
212
213 /* reused inside the loop */
214 unsigned char *p12_B = (unsigned char *)PBE_MALLOC(p12_v + sizeof(int));
215 BIGNUM *Ij = BN_new();
216 BIGNUM *Bpl1 = BN_new();
217
218 /*
219 * 6. For i=1, 2, ..., p12_c, do the following:
220 */
221 for(unsigned p12_i=0; p12_i<p12_c; p12_i++) {
222 unsigned char *p12_AsubI = p12_A + (p12_i * p12_u);
223
224 /*
225 * a) Set A[i] = H**r(D||I). (i.e. the rth hash of D||I,
226 * H(H(H(...H(D||I))))
227 */
228 ourRtn = hashInit(hashHand);
229 if(ourRtn) break;
230 ourRtn = hashUpdate(hashHand, p12_D, p12_v);
231 if(ourRtn) break;
232 ourRtn = hashUpdate(hashHand, p12_I, p12_Slen + p12_Plen);
233 if(ourRtn) break;
234 unsigned outLen = p12_u;
235 ourRtn = hashFinal(hashHand, p12_AsubI, &outLen);
236 if(ourRtn) break;
237
238 for(unsigned iter=1; iter<p12_r; iter++) {
239 ourRtn = hashInit(hashHand);
240 if(ourRtn) break;
241 ourRtn = hashUpdate(hashHand, p12_AsubI, p12_u);
242 if(ourRtn) break;
243 ourRtn = hashFinal(hashHand, p12_AsubI, &outLen);
244 if(ourRtn) break;
245 }
246
247 /*
248 * b) Concatenate copies of A[i] to create a string B of
249 * length v bits (the final copy of A[i]i may be truncated
250 * to create B).
251 */
252 p12StrCat(p12_AsubI, p12_u, p12_v, p12_B);
253
254 /*
255 * c) Treating I as a concatenation I[0], I[1], ...,
256 * I[k-1] of v-bit blocks, where k = ceil(s/v) + ceil(p/v),
257 * modify I by setting I[j]=(I[j]+B+1) mod (2 ** v)
258 * for each j.
259 *
260 * Copied from PKCS12_key_gen_uni() from openssl...
261 */
262 /* Work out B + 1 first then can use B as tmp space */
263 BN_bin2bn (p12_B, p12_v, Bpl1);
264 BN_add_word (Bpl1, 1);
265 unsigned Ilen = p12_Slen + p12_Plen;
266
267 for (unsigned j = 0; j < Ilen; j+=p12_v) {
268 BN_bin2bn (p12_I + j, p12_v, Ij);
269 BN_add (Ij, Ij, Bpl1);
270 BN_bn2bin (Ij, p12_B);
271 unsigned Ijlen = BN_num_bytes (Ij);
272 /* If more than 2^(v*8) - 1 cut off MSB */
273 if (Ijlen > p12_v) {
274 BN_bn2bin (Ij, p12_B);
275 memcpy (p12_I + j, p12_B + 1, p12_v);
276 /* If less than v bytes pad with zeroes */
277 } else if (Ijlen < p12_v) {
278 memset(p12_I + j, 0, p12_v - Ijlen);
279 BN_bn2bin(Ij, p12_I + j + p12_v - Ijlen);
280 } else BN_bn2bin (Ij, p12_I + j);
281 }
282 }
283
284 if(ourRtn) {
285 goto errOut;
286 }
287
288 /*
289 * 7. Concatenate A[1], A[2], ..., A[c] together to form a
290 * pseudo-random bit string, A.
291 *
292 * 8. Use the first n bits of A as the output of this entire
293 * process.
294 */
295 memmove(outbuf, p12_A, outbufLen);
296 ourRtn = CSSM_OK;
297
298 errOut:
299 /* FIXME clear all these strings */
300 if(p12_D) {
301 PBE_FREE(p12_D);
302 }
303 if(p12_S) {
304 PBE_FREE(p12_S);
305 }
306 if(p12_P) {
307 PBE_FREE(p12_P);
308 }
309 if(p12_I) {
310 PBE_FREE(p12_I);
311 }
312 if(p12_A) {
313 PBE_FREE(p12_A);
314 }
315 if(p12_B) {
316 PBE_FREE(p12_B);
317 }
318 if(hashHand) {
319 hashDone(hashHand);
320 }
321 BN_free(Bpl1);
322 BN_free(Ij);
323 return ourRtn;
324 }
325