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