2 * Copyright (c) 2003,2011-2012,2014 Apple Inc. All Rights Reserved.
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.
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.
19 * pkcs12Derive.cpp - PKCS12 PBE routine
23 #include <Security/cssmapple.h>
24 #include <openssl/bn_legacy.h>
25 #include "pbkdDigest.h"
27 #include "pkcs12Derive.h"
28 #include "AppleCSPUtils.h"
29 #include "AppleCSPContext.h"
34 #include <security_utilities/simulatecrash_assert.h>
35 #include <security_asn1/SecNssCoder.h>
37 #include <CoreFoundation/CoreFoundation.h>
39 /* specify which flavor of bits to generate */
47 * Create a "string" (in the loose p12 notation) of specified length
48 * from the concatention of copies of the specified input string.
50 static unsigned char *p12StrCat(
51 const unsigned char *inStr
,
55 unsigned char *outStr
= NULL
) // if not present, we malloc
58 outStr
= (unsigned char *)coder
.malloc(outLen
);
60 unsigned toMove
= outLen
;
61 unsigned char *outp
= outStr
;
63 unsigned thisMove
= inStrLen
;
64 if(thisMove
> toMove
) {
67 memmove(outp
, inStr
, thisMove
);
75 * PBE generator per PKCS12 v.1 section B.2.
77 static CSSM_RETURN
p12PbeGen(
78 const CSSM_DATA
&pwd
, // unicode, double null terminated
83 CSSM_ALGORITHMS hashAlg
, // MS5 or SHA1 only
84 SecNssCoder
&coder
, // for temp allocs
85 /* result goes here, mallocd by caller */
89 CSSM_RETURN ourRtn
= CSSM_OK
;
90 unsigned unipassLen
= (unsigned)pwd
.Length
;
91 unsigned char *unipass
= pwd
.Data
;
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
100 unsigned p12_r
= iterCount
;
101 unsigned p12_n
= outbufLen
;
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
110 p12_u
= kMD5DigestSize
;
111 p12_v
= kMD5BlockSize
;
113 case CSSM_ALGID_SHA1
:
114 p12_u
= kSHA1DigestSize
;
115 p12_v
= kSHA1BlockSize
;
118 return CSSMERR_CSP_INVALID_ALGORITHM
;
122 * 1. Construct a string, D (the diversifier), by
123 * concatenating v/8 copies of ID.
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
;
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.
137 unsigned p12_Slen
= p12_v
* ((saltLen
+ p12_v
- 1) / p12_v
);
139 p12_S
= p12StrCat(salt
, saltLen
, coder
, p12_Slen
);
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.
149 unsigned p12_Plen
= p12_v
* ((unipassLen
+ p12_v
- 1) / p12_v
);
151 p12_P
= p12StrCat(unipass
, unipassLen
, coder
, p12_Plen
);
155 * 4. Set I= S||P to be the concatenation of S and P.
157 unsigned char *p12_I
=
158 (unsigned char *)coder
.malloc(p12_Slen
+ p12_Plen
);
159 memmove(p12_I
, p12_S
, p12_Slen
);
161 memmove(p12_I
+ p12_Slen
, p12_P
, p12_Plen
);
165 * 5. Set c = ceil(n/u).
167 unsigned p12_c
= (p12_n
+ p12_u
- 1) / p12_u
;
169 /* allocate c hash-output-size bufs */
170 unsigned char *p12_A
= (unsigned char *)coder
.malloc(p12_c
* p12_u
);
172 /* one reusable hash object */
174 DigestCtx
*hashHand
= &ourDigest
;
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();
182 * 6. For i=1, 2, ..., p12_c, do the following:
184 for(unsigned p12_i
=0; p12_i
<p12_c
; p12_i
++) {
185 unsigned char *p12_AsubI
= p12_A
+ (p12_i
* p12_u
);
188 * a) Set A[i] = H**r(D||I). (i.e. the rth hash of D||I,
189 * H(H(H(...H(D||I))))
191 irtn
= DigestCtxInit(hashHand
, hashAlg
);
193 ourRtn
= CSSMERR_CSP_INTERNAL_ERROR
;
196 DigestCtxUpdate(hashHand
, p12_D
, p12_v
);
197 DigestCtxUpdate(hashHand
, p12_I
, p12_Slen
+ p12_Plen
);
198 DigestCtxFinal(hashHand
, p12_AsubI
);
200 for(unsigned iter
=1; iter
<p12_r
; iter
++) {
201 irtn
= DigestCtxInit(hashHand
, hashAlg
);
203 ourRtn
= CSSMERR_CSP_INTERNAL_ERROR
;
206 DigestCtxUpdate(hashHand
, p12_AsubI
, p12_u
);
207 DigestCtxFinal(hashHand
, p12_AsubI
);
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
215 p12StrCat(p12_AsubI
, p12_u
, coder
, p12_v
, p12_B
);
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)
223 * Copied from PKCS12_key_gen_uni() from openssl...
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
;
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 */
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
);
247 if(ourRtn
== CSSM_OK
) {
249 * 7. Concatenate A[1], A[2], ..., A[c] together to form a
250 * pseudo-random bit string, A.
252 * 8. Use the first n bits of A as the output of this entire
255 memmove(outbuf
, p12_A
, outbufLen
);
258 /* clear all these strings */
260 memset(p12_D
, 0, p12_v
);
263 memset(p12_S
, 0, p12_Slen
);
266 memset(p12_P
, 0, p12_Plen
);
269 memset(p12_I
, 0, p12_Slen
+ p12_Plen
);
272 memset(p12_A
, 0, p12_c
* p12_u
);
275 memset(p12_B
, 0, p12_v
);
278 DigestCtxFree(hashHand
);
286 * Public P12 derive key function, called out from
287 * AppleCSPSession::DeriveKey()
291 * Context parameters:
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
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
310 SecNssCoder tmpCoder
;
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).
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
;
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
);
337 * The incoming passphrase is a UTF8 encoded enternal representation
338 * of a CFString. Convert to CFString and obtain the unicode characters
341 CFDataRef cfData
= CFDataCreate(NULL
, appPwd
.Data
, appPwd
.Length
);
342 CFStringRef cfStr
= CFStringCreateFromExternalRepresentation(NULL
,
343 cfData
, kCFStringEncodingUTF8
);
347 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED
);
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
;
355 for(CFIndex dex
=0; dex
<len
; dex
++) {
356 uc
= CFStringGetCharacterAtIndex(cfStr
, dex
);
360 /* CFString tends to include a NULL at the end; add it if it's not there */
363 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED
);
375 /* salt from context */
378 CssmData
*csalt
= context
.get
<CssmData
>(CSSM_ATTRIBUTE_SALT
);
381 saltLen
= (uint32
)csalt
->Length
;
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
390 uint32 iterCount
= context
.getInt(CSSM_ATTRIBUTE_ITERATION_COUNT
,
391 CSSMERR_CSP_MISSING_ATTR_ITERATION_COUNT
);
393 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ITERATION_COUNT
);
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.
400 P12_PBE_ID pbeId
= PBE_ID_Key
;
401 switch(context
.algorithm()) {
402 case CSSM_ALGID_PKCS12_PBE_ENCR
:
405 case CSSM_ALGID_PKCS12_PBE_MAC
:
409 /* really should not be here */
411 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
415 CSSM_RETURN crtn
= p12PbeGen(pwd
,
419 CSSM_ALGID_SHA1
, // all we support for now
422 (unsigned)keyData
->Length
);
424 CssmError::throwMe(crtn
);
428 * Optional IV - makes no sense if we just did PBE_ID_MAC, but why
429 * bother restricting?
432 crtn
= p12PbeGen(pwd
,
436 CSSM_ALGID_SHA1
, // all we support for now
439 (unsigned)Param
.Length
);
441 CssmError::throwMe(crtn
);