2 * Copyright (c) 2003 Apple Computer, 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 * p12pbe.h - PKCS12 PBE routine. App space reference version.
21 * Created 2/28/03 by Doug Mitchell.
28 #include <Security/cssm.h>
29 #include <openssl/bn.h>
31 * For development outside the CSP, malloc using stdlib.
32 * Inside the CSP we'll use CssmAllocator.
34 #define PBE_MALLOC malloc
38 * implementation dependent hash object
39 * for now just a Digest context handle
41 typedef CSSM_CC_HANDLE HashHand
;
42 static HashHand
hashCreate(CSSM_CSP_HANDLE cspHand
,
45 CSSM_CC_HANDLE hashHand
;
46 CSSM_RETURN crtn
= CSSM_CSP_CreateDigestContext(cspHand
,
50 printf("CSSM_CSP_CreateDigestContext error\n");
56 static CSSM_RETURN
hashInit(HashHand hand
)
58 return CSSM_DigestDataInit(hand
);
61 static CSSM_RETURN
hashUpdate(HashHand hand
,
62 const unsigned char *buf
,
65 const CSSM_DATA cdata
= {bufLen
, (uint8
*)buf
};
66 return CSSM_DigestDataUpdate(hand
, &cdata
, 1);
69 static CSSM_RETURN
hashFinal(HashHand hand
,
70 unsigned char *digest
, // mallocd by caller
71 unsigned *digestLen
) // IN/OUT
73 CSSM_DATA cdata
= {(uint32
)digestLen
, digest
};
74 return CSSM_DigestDataFinal(hand
, &cdata
);
77 static CSSM_RETURN
hashDone(HashHand hand
)
79 return CSSM_DeleteContext(hand
);
83 * Create a "string" (in the loose p12 notation) of specified length
84 * from the concatention of copies of the specified input string.
86 static unsigned char *p12StrCat(
87 const unsigned char *inStr
,
90 unsigned char *outStr
= NULL
) // if not present, we malloc
93 outStr
= (unsigned char *)PBE_MALLOC(outLen
);
95 unsigned toMove
= outLen
;
96 unsigned char *outp
= outStr
;
98 unsigned thisMove
= inStrLen
;
99 if(thisMove
> toMove
) {
102 memmove(outp
, inStr
, thisMove
);
110 * PBE generator per PKCS12 v.1 section B.2.
112 CSSM_RETURN
p12PbeGen_app(
113 const CSSM_DATA
&pwd
, // unicode, double null terminated
114 const unsigned char *salt
,
118 CSSM_ALGORITHMS hashAlg
, // MS5 or SHA1 only
119 CSSM_CSP_HANDLE cspHand
,
120 /* result goes here, mallocd by caller */
121 unsigned char *outbuf
,
125 unsigned unipassLen
= pwd
.Length
;
126 unsigned char *unipass
= pwd
.Data
;
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
134 unsigned p12_r
= iterCount
;
135 unsigned p12_n
= outbufLen
;
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
147 case CSSM_ALGID_SHA1
:
152 return CSSMERR_CSP_INVALID_ALGORITHM
;
156 * 1. Construct a string, D (the “diversifier”), by
157 * concatenating v/8 copies of ID.
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
;
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.
172 unsigned p12_Slen
= p12_v
* ((saltLen
+ p12_v
- 1) / p12_v
);
174 p12_S
= p12StrCat(salt
, saltLen
, p12_Slen
);
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.
184 unsigned p12_Plen
= p12_v
* ((unipassLen
+ p12_v
- 1) / p12_v
);
186 p12_P
= p12StrCat(unipass
, unipassLen
, p12_Plen
);
190 * 4. Set I= S||P to be the concatenation of S and P.
192 unsigned char *p12_I
=
193 (unsigned char *)PBE_MALLOC(p12_Slen
+ p12_Plen
);
194 memmove(p12_I
, p12_S
, p12_Slen
);
196 memmove(p12_I
+ p12_Slen
, p12_P
, p12_Plen
);
200 * 5. Set c = ceil(n/u).
202 unsigned p12_c
= (p12_n
+ p12_u
- 1) / p12_u
;
204 /* allocate c hash-output-size bufs */
205 unsigned char *p12_A
= (unsigned char *)PBE_MALLOC(p12_c
* p12_u
);
207 /* one reusable hash object */
208 HashHand hashHand
= hashCreate(cspHand
, hashAlg
);
210 return CSSMERR_CSP_INVALID_CONTEXT_HANDLE
; // XXX
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();
219 * 6. For i=1, 2, ..., p12_c, do the following:
221 for(unsigned p12_i
=0; p12_i
<p12_c
; p12_i
++) {
222 unsigned char *p12_AsubI
= p12_A
+ (p12_i
* p12_u
);
225 * a) Set A[i] = H**r(D||I). (i.e. the rth hash of D||I,
226 * H(H(H(...H(D||I))))
228 ourRtn
= hashInit(hashHand
);
230 ourRtn
= hashUpdate(hashHand
, p12_D
, p12_v
);
232 ourRtn
= hashUpdate(hashHand
, p12_I
, p12_Slen
+ p12_Plen
);
234 unsigned outLen
= p12_u
;
235 ourRtn
= hashFinal(hashHand
, p12_AsubI
, &outLen
);
238 for(unsigned iter
=1; iter
<p12_r
; iter
++) {
239 ourRtn
= hashInit(hashHand
);
241 ourRtn
= hashUpdate(hashHand
, p12_AsubI
, p12_u
);
243 ourRtn
= hashFinal(hashHand
, p12_AsubI
, &outLen
);
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
252 p12StrCat(p12_AsubI
, p12_u
, p12_v
, p12_B
);
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)
260 * Copied from PKCS12_key_gen_uni() from openssl...
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
;
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 */
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
);
289 * 7. Concatenate A[1], A[2], ..., A[c] together to form a
290 * pseudo-random bit string, A.
292 * 8. Use the first n bits of A as the output of this entire
295 memmove(outbuf
, p12_A
, outbufLen
);
299 /* FIXME clear all these strings */