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