]> git.saurik.com Git - apple/security.git/blob - AppleCSP/MiscCSPAlgs/pkcs12Derive.cpp
Security-163.tar.gz
[apple/security.git] / AppleCSP / MiscCSPAlgs / pkcs12Derive.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 * pkcs12Derive.cpp - PKCS12 PBE routine
20 *
21 * Created 2/28/03 by Doug Mitchell.
22 */
23
24 #include <Security/cssmapple.h>
25 #include <open_ssl/openssl/bn.h>
26 #include <PBKDF2/pbkdDigest.h>
27
28 #include "pkcs12Derive.h"
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <assert.h>
33 #include <SecurityNssAsn1/SecNssCoder.h>
34
35 /* specify which flavor of bits to generate */
36 typedef enum {
37 PBE_ID_Key = 1,
38 PBE_ID_IV = 2,
39 PBE_ID_MAC = 3
40 } P12_PBE_ID;
41
42 /*
43 * implementation dependent hash object
44 */
45 #if 0
46 typedef CSSM_CC_HANDLE HashHand;
47 static HashHand hashCreate(CSSM_CSP_HANDLE cspHand,
48 CSSM_ALGORITHMS alg)
49 {
50 CSSM_CC_HANDLE hashHand;
51 CSSM_RETURN crtn = CSSM_CSP_CreateDigestContext(cspHand,
52 alg,
53 &hashHand);
54 if(crtn) {
55 printf("CSSM_CSP_CreateDigestContext error\n");
56 return 0;
57 }
58 return hashHand;
59 }
60
61 static CSSM_RETURN hashInit(HashHand hand)
62 {
63 return CSSM_DigestDataInit(hand);
64 }
65
66 static CSSM_RETURN hashUpdate(HashHand hand,
67 const unsigned char *buf,
68 unsigned bufLen)
69 {
70 const CSSM_DATA cdata = {bufLen, (uint8 *)buf};
71 return CSSM_DigestDataUpdate(hand, &cdata, 1);
72 }
73
74 static CSSM_RETURN hashFinal(HashHand hand,
75 unsigned char *digest, // mallocd by caller
76 unsigned *digestLen) // IN/OUT
77 {
78 CSSM_DATA cdata = {(uint32)digestLen, digest};
79 return CSSM_DigestDataFinal(hand, &cdata);
80 }
81
82 static CSSM_RETURN hashDone(HashHand hand)
83 {
84 return CSSM_DeleteContext(hand);
85 }
86 #endif
87
88 /*
89 * Create a "string" (in the loose p12 notation) of specified length
90 * from the concatention of copies of the specified input string.
91 */
92 static unsigned char *p12StrCat(
93 const unsigned char *inStr,
94 unsigned inStrLen,
95 SecNssCoder &coder,
96 unsigned outLen,
97 unsigned char *outStr = NULL) // if not present, we malloc
98 {
99 if(outStr == NULL) {
100 outStr = (unsigned char *)coder.malloc(outLen);
101 }
102 unsigned toMove = outLen;
103 unsigned char *outp = outStr;
104 while(toMove) {
105 unsigned thisMove = inStrLen;
106 if(thisMove > toMove) {
107 thisMove = toMove;
108 }
109 memmove(outp, inStr, thisMove);
110 toMove -= thisMove;
111 outp += thisMove;
112 }
113 return outStr;
114 }
115
116 /*
117 * PBE generator per PKCS12 v.1 section B.2.
118 */
119 static CSSM_RETURN p12PbeGen(
120 const CSSM_DATA &pwd, // unicode, double null terminated
121 const uint8 *salt,
122 unsigned saltLen,
123 unsigned iterCount,
124 P12_PBE_ID pbeId,
125 CSSM_ALGORITHMS hashAlg, // MS5 or SHA1 only
126 SecNssCoder &coder, // for temp allocs
127 /* result goes here, mallocd by caller */
128 uint8 *outbuf,
129 unsigned outbufLen)
130 {
131 CSSM_RETURN ourRtn = CSSM_OK;
132 unsigned unipassLen = pwd.Length;
133 unsigned char *unipass = pwd.Data;
134
135 /*
136 * all variables of the form p12_<XXX> represent <XXX> from the
137 * PKCS12 spec. E.g., p12_u is u, the length of the digest output.
138 * Only difference here is: all of our sizes are in BYTES, not
139 * bits.
140 */
141 unsigned p12_r = iterCount;
142 unsigned p12_n = outbufLen;
143
144 unsigned p12_u; // hash output size
145 unsigned p12_v; // hash block size
146 unsigned char *p12_P = NULL; // catted passwords
147 unsigned char *p12_S = NULL; // catted salts
148 CSSM_BOOL isSha1 = CSSM_TRUE; // for DigestCtx
149
150 switch(hashAlg) {
151 case CSSM_ALGID_MD5:
152 p12_u = kMD5DigestSize;
153 p12_v = kMD5BlockSize;
154 isSha1 = CSSM_FALSE;
155 break;
156 case CSSM_ALGID_SHA1:
157 p12_u = kSHA1DigestSize;
158 p12_v = kSHA1BlockSize;
159 break;
160 default:
161 return CSSMERR_CSP_INVALID_ALGORITHM;
162 }
163
164 /*
165 * 1. Construct a string, D (the diversifier), by
166 * concatenating v/8 copies of ID.
167 */
168 unsigned char *p12_D = NULL; // diversifier
169 p12_D = (unsigned char *)coder.malloc(p12_v);
170 for(unsigned dex=0; dex<p12_v; dex++) {
171 p12_D[dex] = (unsigned char)pbeId;
172 }
173
174 /*
175 * 2. Concatenate copies of the salt together to create
176 * a string S of length v * ceil(s/v) bits (the final copy
177 * of the salt may be truncated to create S). Note that if
178 * the salt is the empty string, then so is S.
179 */
180 unsigned p12_Slen = p12_v * ((saltLen + p12_v - 1) / p12_v);
181 if(p12_Slen) {
182 p12_S = p12StrCat(salt, saltLen, coder, p12_Slen);
183 }
184
185
186 /*
187 * 3. Concatenate copies of the password together to create
188 * a string P of length v * ceil(p/v) bits (the final copy of
189 * the password may be truncated to create P). Note that
190 * if the password is the empty string, then so is P.
191 */
192 unsigned p12_Plen = p12_v * ((unipassLen + p12_v - 1) / p12_v);
193 if(p12_Plen) {
194 p12_P = p12StrCat(unipass, unipassLen, coder, p12_Plen);
195 }
196
197 /*
198 * 4. Set I= S||P to be the concatenation of S and P.
199 */
200 unsigned char *p12_I =
201 (unsigned char *)coder.malloc(p12_Slen + p12_Plen);
202 memmove(p12_I, p12_S, p12_Slen);
203 if(p12_Plen) {
204 memmove(p12_I + p12_Slen, p12_P, p12_Plen);
205 }
206
207 /*
208 * 5. Set c = ceil(n/u).
209 */
210 unsigned p12_c = (p12_n + p12_u - 1) / p12_u;
211
212 /* allocate c hash-output-size bufs */
213 unsigned char *p12_A = (unsigned char *)coder.malloc(p12_c * p12_u);
214
215 /* one reusable hash object */
216 DigestCtx ourDigest;
217 DigestCtx *hashHand = &ourDigest;
218 memset(hashHand, 0, sizeof(hashHand));
219
220 /* reused inside the loop */
221 unsigned char *p12_B = (unsigned char *)coder.malloc(p12_v);
222 BIGNUM *Ij = BN_new();
223 BIGNUM *Bpl1 = BN_new();
224
225 /*
226 * 6. For i=1, 2, ..., p12_c, do the following:
227 */
228 for(unsigned p12_i=0; p12_i<p12_c; p12_i++) {
229 unsigned char *p12_AsubI = p12_A + (p12_i * p12_u);
230
231 /*
232 * a) Set A[i] = H**r(D||I). (i.e. the rth hash of D||I,
233 * H(H(H(...H(D||I))))
234 */
235 ourRtn = DigestCtxInit(hashHand, isSha1);
236 if(ourRtn) break;
237 DigestCtxUpdate(hashHand, p12_D, p12_v);
238 DigestCtxUpdate(hashHand, p12_I, p12_Slen + p12_Plen);
239 DigestCtxFinal(hashHand, p12_AsubI);
240
241 for(unsigned iter=1; iter<p12_r; iter++) {
242 ourRtn = DigestCtxInit(hashHand, isSha1);
243 if(ourRtn) break;
244 DigestCtxUpdate(hashHand, p12_AsubI, p12_u);
245 DigestCtxFinal(hashHand, p12_AsubI);
246 }
247
248 /*
249 * b) Concatenate copies of A[i] to create a string B of
250 * length v bits (the final copy of A[i]i may be truncated
251 * to create B).
252 */
253 p12StrCat(p12_AsubI, p12_u, coder, p12_v, p12_B);
254
255 /*
256 * c) Treating I as a concatenation I[0], I[1], ...,
257 * I[k-1] of v-bit blocks, where k = ceil(s/v) + ceil(p/v),
258 * modify I by setting I[j]=(I[j]+B+1) mod (2 ** v)
259 * for each j.
260 *
261 * Copied from PKCS12_key_gen_uni() from openssl...
262 */
263 /* Work out B + 1 first then can use B as tmp space */
264 BN_bin2bn (p12_B, p12_v, Bpl1);
265 BN_add_word (Bpl1, 1);
266 unsigned Ilen = p12_Slen + p12_Plen;
267
268 for (unsigned j = 0; j < Ilen; j+=p12_v) {
269 BN_bin2bn (p12_I + j, p12_v, Ij);
270 BN_add (Ij, Ij, Bpl1);
271 BN_bn2bin (Ij, p12_B);
272 unsigned Ijlen = BN_num_bytes (Ij);
273 /* If more than 2^(v*8) - 1 cut off MSB */
274 if (Ijlen > p12_v) {
275 BN_bn2bin (Ij, p12_B);
276 memcpy (p12_I + j, p12_B + 1, p12_v);
277 /* If less than v bytes pad with zeroes */
278 } else if (Ijlen < p12_v) {
279 memset(p12_I + j, 0, p12_v - Ijlen);
280 BN_bn2bin(Ij, p12_I + j + p12_v - Ijlen);
281 } else BN_bn2bin (Ij, p12_I + j);
282 }
283 }
284
285 if(ourRtn == CSSM_OK) {
286 /*
287 * 7. Concatenate A[1], A[2], ..., A[c] together to form a
288 * pseudo-random bit string, A.
289 *
290 * 8. Use the first n bits of A as the output of this entire
291 * process.
292 */
293 memmove(outbuf, p12_A, outbufLen);
294 }
295
296 /* clear all these strings */
297 if(p12_D) {
298 memset(p12_D, 0, p12_v);
299 }
300 if(p12_S) {
301 memset(p12_S, 0, p12_Slen);
302 }
303 if(p12_P) {
304 memset(p12_P, 0, p12_Plen);
305 }
306 if(p12_I) {
307 memset(p12_I, 0, p12_Slen + p12_Plen);
308 }
309 if(p12_A) {
310 memset(p12_A, 0, p12_c * p12_u);
311 }
312 if(p12_B) {
313 memset(p12_B, 0, p12_v);
314 }
315 if(hashHand) {
316 DigestCtxFree(hashHand);
317 }
318 BN_free(Bpl1);
319 BN_free(Ij);
320 return ourRtn;
321 }
322
323 /*
324 * Public P12 derive key function, called out from
325 * AppleCSPSession::DeriveKey()
326 *
327 * On input:
328 * ---------
329 * Context parameters:
330 * Salt
331 * Iteration Count
332 * CSSM_CRYPTO_DATA.Param - Unicode passphrase, double-NULL terminated
333 * Algorithm - CSSM_ALGID_PKCS12_PBE_{ENCR,MAC}
334 * Passed explicitly from DeriveKey():
335 * CSSM_DATA Param - IN/OUT - optional IV - caller mallocs space to
336 * tell us to generate an IV. The param itself is not
337 * optional; the presence or absence of allocated data in it
338 * is our IV indicator (present/absent as well as size)
339 * KeyData - mallocd by caller, we fill in keyData->Length bytes
340 */
341 void DeriveKey_PKCS12 (
342 const Context &context,
343 const CssmData &Param, // other's public key
344 CSSM_DATA *keyData) // mallocd by caller
345 // we fill in keyData->Length bytes
346 {
347 /*
348 * According to the spec, both passphrase and salt are optional.
349 * Get them from context if they're present.
350 */
351 CSSM_DATA pwd = {0, NULL};
352 CssmCryptoData *cryptData =
353 context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED);
354 if(cryptData) {
355 pwd.Length = cryptData->Param.Length;
356 pwd.Data = cryptData->Param.Data;
357 }
358
359 /* salt from context */
360 uint32 saltLen = 0;
361 uint8 *salt = NULL;
362 CssmData *csalt = context.get<CssmData>(CSSM_ATTRIBUTE_SALT);
363 if(csalt) {
364 salt = csalt->Data;
365 saltLen = csalt->Length;
366 }
367
368 /*
369 * Iteration count, from context, required.
370 * The spec's ASN1 definition says this is optional with a default
371 * of one but that's a BER encode/decode issue. Here we require
372 * a nonzero value.
373 */
374 uint32 iterCount = context.getInt(CSSM_ATTRIBUTE_ITERATION_COUNT,
375 CSSMERR_CSP_MISSING_ATTR_ITERATION_COUNT);
376 if(iterCount == 0) {
377 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ITERATION_COUNT);
378 }
379
380 /*
381 * Algorithm determines which of {PBE_ID_Key,PBE_ID_MAC} we now
382 * generate. We'll also do an optional PBE_ID_IV later.
383 */
384 P12_PBE_ID pbeId = PBE_ID_Key;
385 switch(context.algorithm()) {
386 case CSSM_ALGID_PKCS12_PBE_ENCR:
387 pbeId = PBE_ID_Key;
388 break;
389 case CSSM_ALGID_PKCS12_PBE_MAC:
390 pbeId = PBE_ID_MAC;
391 break;
392 default:
393 /* really should not be here */
394 assert(0);
395 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
396 }
397
398 /* Go */
399 SecNssCoder tmpCoder;
400 CSSM_RETURN crtn = p12PbeGen(pwd,
401 salt, saltLen,
402 iterCount,
403 pbeId,
404 CSSM_ALGID_SHA1, // all we support for now
405 tmpCoder,
406 keyData->Data,
407 keyData->Length);
408 if(crtn) {
409 CssmError::throwMe(crtn);
410 }
411
412 /*
413 * Optional IV - makes no sense if we just did PBE_ID_MAC, but why
414 * bother restricting?
415 */
416 if(Param.Data) {
417 crtn = p12PbeGen(pwd,
418 salt, saltLen,
419 iterCount,
420 PBE_ID_IV,
421 CSSM_ALGID_SHA1, // all we support for now
422 tmpCoder,
423 Param.Data,
424 Param.Length);
425 if(crtn) {
426 CssmError::throwMe(crtn);
427 }
428 }
429 }
430