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 * p12pbe.h - PKCS12 PBE routine. App space reference version. 20 * 21 * Created 2/28/03 by Doug Mitchell. 22*/ 23 24#include "p12pbe.h" 25#include <string.h> 26#include <stdlib.h> 27#include <stdio.h> 28#include <Security/cssm.h> 29#include <openssl/bn.h> 30/* 31 * For development outside the CSP, malloc using stdlib. 32 * Inside the CSP we'll use CssmAllocator. 33 */ 34#define PBE_MALLOC malloc 35#define PBE_FREE free 36 37/* 38 * implementation dependent hash object 39 * for now just a Digest context handle 40 */ 41typedef CSSM_CC_HANDLE HashHand; 42static HashHand hashCreate(CSSM_CSP_HANDLE cspHand, 43 CSSM_ALGORITHMS alg) 44{ 45 CSSM_CC_HANDLE hashHand; 46 CSSM_RETURN crtn = CSSM_CSP_CreateDigestContext(cspHand, 47 alg, 48 &hashHand); 49 if(crtn) { 50 printf("CSSM_CSP_CreateDigestContext error\n"); 51 return 0; 52 } 53 return hashHand; 54} 55 56static CSSM_RETURN hashInit(HashHand hand) 57{ 58 return CSSM_DigestDataInit(hand); 59} 60 61static CSSM_RETURN hashUpdate(HashHand hand, 62 const unsigned char *buf, 63 unsigned bufLen) 64{ 65 const CSSM_DATA cdata = {bufLen, (uint8 *)buf}; 66 return CSSM_DigestDataUpdate(hand, &cdata, 1); 67} 68 69static CSSM_RETURN hashFinal(HashHand hand, 70 unsigned char *digest, // mallocd by caller 71 unsigned *digestLen) // IN/OUT 72{ 73 CSSM_DATA cdata = {(uint32)digestLen, digest}; 74 return CSSM_DigestDataFinal(hand, &cdata); 75} 76 77static CSSM_RETURN hashDone(HashHand hand) 78{ 79 return CSSM_DeleteContext(hand); 80} 81 82/* 83 * Create a "string" (in the loose p12 notation) of specified length 84 * from the concatention of copies of the specified input string. 85 */ 86static unsigned char *p12StrCat( 87 const unsigned char *inStr, 88 unsigned inStrLen, 89 unsigned outLen, 90 unsigned char *outStr = NULL) // if not present, we malloc 91{ 92 if(outStr == NULL) { 93 outStr = (unsigned char *)PBE_MALLOC(outLen); 94 } 95 unsigned toMove = outLen; 96 unsigned char *outp = outStr; 97 while(toMove) { 98 unsigned thisMove = inStrLen; 99 if(thisMove > toMove) { 100 thisMove = toMove; 101 } 102 memmove(outp, inStr, thisMove); 103 toMove -= thisMove; 104 outp += thisMove; 105 } 106 return outStr; 107} 108 109/* 110 * PBE generator per PKCS12 v.1 section B.2. 111 */ 112CSSM_RETURN p12PbeGen_app( 113 const CSSM_DATA &pwd, // unicode, double null terminated 114 const unsigned char *salt, 115 unsigned saltLen, 116 unsigned iterCount, 117 P12_PBE_ID pbeId, 118 CSSM_ALGORITHMS hashAlg, // MS5 or SHA1 only 119 CSSM_CSP_HANDLE cspHand, 120 /* result goes here, mallocd by caller */ 121 unsigned char *outbuf, 122 unsigned outbufLen) 123{ 124 CSSM_RETURN ourRtn; 125 unsigned unipassLen = pwd.Length; 126 unsigned char *unipass = pwd.Data; 127 128 /* 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 132 * bits. 133 */ 134 unsigned p12_r = iterCount; 135 unsigned p12_n = outbufLen; 136 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 141 142 switch(hashAlg) { 143 case CSSM_ALGID_MD5: 144 p12_u = 16; 145 p12_v = 64; 146 break; 147 case CSSM_ALGID_SHA1: 148 p12_u = 20; 149 p12_v = 64; 150 break; 151 default: 152 return CSSMERR_CSP_INVALID_ALGORITHM; 153 } 154 155 /* 156 * 1. Construct a string, D (the “diversifier”), by 157 * concatenating v/8 copies of ID. 158 */ 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; 164 } 165 166 /* 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. 171 */ 172 unsigned p12_Slen = p12_v * ((saltLen + p12_v - 1) / p12_v); 173 if(p12_Slen) { 174 p12_S = p12StrCat(salt, saltLen, p12_Slen); 175 } 176 177 178 /* 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. 183 */ 184 unsigned p12_Plen = p12_v * ((unipassLen + p12_v - 1) / p12_v); 185 if(p12_Plen) { 186 p12_P = p12StrCat(unipass, unipassLen, p12_Plen); 187 } 188 189 /* 190 * 4. Set I= S||P to be the concatenation of S and P. 191 */ 192 unsigned char *p12_I = 193 (unsigned char *)PBE_MALLOC(p12_Slen + p12_Plen); 194 memmove(p12_I, p12_S, p12_Slen); 195 if(p12_Plen) { 196 memmove(p12_I + p12_Slen, p12_P, p12_Plen); 197 } 198 199 /* 200 * 5. Set c = ceil(n/u). 201 */ 202 unsigned p12_c = (p12_n + p12_u - 1) / p12_u; 203 204 /* allocate c hash-output-size bufs */ 205 unsigned char *p12_A = (unsigned char *)PBE_MALLOC(p12_c * p12_u); 206 207 /* one reusable hash object */ 208 HashHand hashHand = hashCreate(cspHand, hashAlg); 209 if(!hashHand) { 210 return CSSMERR_CSP_INVALID_CONTEXT_HANDLE; // XXX 211 } 212 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(); 217 218 /* 219 * 6. For i=1, 2, ..., p12_c, do the following: 220 */ 221 for(unsigned p12_i=0; p12_i<p12_c; p12_i++) { 222 unsigned char *p12_AsubI = p12_A + (p12_i * p12_u); 223 224 /* 225 * a) Set A[i] = H**r(D||I). (i.e. the rth hash of D||I, 226 * H(H(H(...H(D||I)))) 227 */ 228 ourRtn = hashInit(hashHand); 229 if(ourRtn) break; 230 ourRtn = hashUpdate(hashHand, p12_D, p12_v); 231 if(ourRtn) break; 232 ourRtn = hashUpdate(hashHand, p12_I, p12_Slen + p12_Plen); 233 if(ourRtn) break; 234 unsigned outLen = p12_u; 235 ourRtn = hashFinal(hashHand, p12_AsubI, &outLen); 236 if(ourRtn) break; 237 238 for(unsigned iter=1; iter<p12_r; iter++) { 239 ourRtn = hashInit(hashHand); 240 if(ourRtn) break; 241 ourRtn = hashUpdate(hashHand, p12_AsubI, p12_u); 242 if(ourRtn) break; 243 ourRtn = hashFinal(hashHand, p12_AsubI, &outLen); 244 if(ourRtn) break; 245 } 246 247 /* 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 250 * to create B). 251 */ 252 p12StrCat(p12_AsubI, p12_u, p12_v, p12_B); 253 254 /* 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) 258 * for each j. 259 * 260 * Copied from PKCS12_key_gen_uni() from openssl... 261 */ 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; 266 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 */ 273 if (Ijlen > p12_v) { 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); 281 } 282 } 283 284 if(ourRtn) { 285 goto errOut; 286 } 287 288 /* 289 * 7. Concatenate A[1], A[2], ..., A[c] together to form a 290 * pseudo-random bit string, A. 291 * 292 * 8. Use the first n bits of A as the output of this entire 293 * process. 294 */ 295 memmove(outbuf, p12_A, outbufLen); 296 ourRtn = CSSM_OK; 297 298errOut: 299 /* FIXME clear all these strings */ 300 if(p12_D) { 301 PBE_FREE(p12_D); 302 } 303 if(p12_S) { 304 PBE_FREE(p12_S); 305 } 306 if(p12_P) { 307 PBE_FREE(p12_P); 308 } 309 if(p12_I) { 310 PBE_FREE(p12_I); 311 } 312 if(p12_A) { 313 PBE_FREE(p12_A); 314 } 315 if(p12_B) { 316 PBE_FREE(p12_B); 317 } 318 if(hashHand) { 319 hashDone(hashHand); 320 } 321 BN_free(Bpl1); 322 BN_free(Ij); 323 return ourRtn; 324} 325 326