Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include "plarena.h" |
michael@0 | 6 | |
michael@0 | 7 | #include "seccomon.h" |
michael@0 | 8 | #include "secitem.h" |
michael@0 | 9 | #include "secport.h" |
michael@0 | 10 | #include "hasht.h" |
michael@0 | 11 | #include "pkcs11t.h" |
michael@0 | 12 | #include "sechash.h" |
michael@0 | 13 | #include "secasn1.h" |
michael@0 | 14 | #include "secder.h" |
michael@0 | 15 | #include "secoid.h" |
michael@0 | 16 | #include "secerr.h" |
michael@0 | 17 | #include "secmod.h" |
michael@0 | 18 | #include "pk11func.h" |
michael@0 | 19 | #include "secpkcs5.h" |
michael@0 | 20 | #include "secmodi.h" |
michael@0 | 21 | #include "secmodti.h" |
michael@0 | 22 | #include "pkcs11.h" |
michael@0 | 23 | #include "pk11func.h" |
michael@0 | 24 | #include "secitem.h" |
michael@0 | 25 | #include "key.h" |
michael@0 | 26 | |
michael@0 | 27 | typedef struct SEC_PKCS5PBEParameterStr SEC_PKCS5PBEParameter; |
michael@0 | 28 | struct SEC_PKCS5PBEParameterStr { |
michael@0 | 29 | PLArenaPool *poolp; |
michael@0 | 30 | SECItem salt; /* octet string */ |
michael@0 | 31 | SECItem iteration; /* integer */ |
michael@0 | 32 | SECItem keyLength; /* PKCS5v2 only */ |
michael@0 | 33 | SECAlgorithmID *pPrfAlgId; /* PKCS5v2 only */ |
michael@0 | 34 | SECAlgorithmID prfAlgId; /* PKCS5v2 only */ |
michael@0 | 35 | }; |
michael@0 | 36 | |
michael@0 | 37 | /* PKCS5 V2 has an algorithm ID for the encryption and for |
michael@0 | 38 | * the key generation. This is valid for SEC_OID_PKCS5_PBES2 |
michael@0 | 39 | * and SEC_OID_PKCS5_PBMAC1 |
michael@0 | 40 | */ |
michael@0 | 41 | struct sec_pkcs5V2ParameterStr { |
michael@0 | 42 | PLArenaPool *poolp; |
michael@0 | 43 | SECAlgorithmID pbeAlgId; /* real pbe algorithms */ |
michael@0 | 44 | SECAlgorithmID cipherAlgId; /* encryption/mac */ |
michael@0 | 45 | }; |
michael@0 | 46 | |
michael@0 | 47 | typedef struct sec_pkcs5V2ParameterStr sec_pkcs5V2Parameter; |
michael@0 | 48 | |
michael@0 | 49 | |
michael@0 | 50 | /* template for PKCS 5 PBE Parameter. This template has been expanded |
michael@0 | 51 | * based upon the additions in PKCS 12. This should eventually be moved |
michael@0 | 52 | * if RSA updates PKCS 5. |
michael@0 | 53 | */ |
michael@0 | 54 | const SEC_ASN1Template SEC_PKCS5PBEParameterTemplate[] = |
michael@0 | 55 | { |
michael@0 | 56 | { SEC_ASN1_SEQUENCE, |
michael@0 | 57 | 0, NULL, sizeof(SEC_PKCS5PBEParameter) }, |
michael@0 | 58 | { SEC_ASN1_OCTET_STRING, |
michael@0 | 59 | offsetof(SEC_PKCS5PBEParameter, salt) }, |
michael@0 | 60 | { SEC_ASN1_INTEGER, |
michael@0 | 61 | offsetof(SEC_PKCS5PBEParameter, iteration) }, |
michael@0 | 62 | { 0 } |
michael@0 | 63 | }; |
michael@0 | 64 | |
michael@0 | 65 | const SEC_ASN1Template SEC_V2PKCS12PBEParameterTemplate[] = |
michael@0 | 66 | { |
michael@0 | 67 | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) }, |
michael@0 | 68 | { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) }, |
michael@0 | 69 | { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) }, |
michael@0 | 70 | { 0 } |
michael@0 | 71 | }; |
michael@0 | 72 | |
michael@0 | 73 | SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
michael@0 | 74 | |
michael@0 | 75 | /* SECOID_PKCS5_PBKDF2 */ |
michael@0 | 76 | const SEC_ASN1Template SEC_PKCS5V2PBEParameterTemplate[] = |
michael@0 | 77 | { |
michael@0 | 78 | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) }, |
michael@0 | 79 | /* This is really a choice, but since we only understand this |
michael@0 | 80 | * choice, just inline it */ |
michael@0 | 81 | { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) }, |
michael@0 | 82 | { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) }, |
michael@0 | 83 | { SEC_ASN1_INTEGER|SEC_ASN1_OPTIONAL, |
michael@0 | 84 | offsetof(SEC_PKCS5PBEParameter, keyLength) }, |
michael@0 | 85 | { SEC_ASN1_POINTER | SEC_ASN1_XTRN | SEC_ASN1_OPTIONAL, |
michael@0 | 86 | offsetof(SEC_PKCS5PBEParameter, pPrfAlgId), |
michael@0 | 87 | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
michael@0 | 88 | { 0 } |
michael@0 | 89 | }; |
michael@0 | 90 | |
michael@0 | 91 | /* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */ |
michael@0 | 92 | const SEC_ASN1Template SEC_PKCS5V2ParameterTemplate[] = |
michael@0 | 93 | { |
michael@0 | 94 | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) }, |
michael@0 | 95 | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(sec_pkcs5V2Parameter, pbeAlgId), |
michael@0 | 96 | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
michael@0 | 97 | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
michael@0 | 98 | offsetof(sec_pkcs5V2Parameter, cipherAlgId), |
michael@0 | 99 | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
michael@0 | 100 | { 0 } |
michael@0 | 101 | }; |
michael@0 | 102 | |
michael@0 | 103 | |
michael@0 | 104 | /* |
michael@0 | 105 | * maps a PBE algorithm to a crypto algorithm. for PKCS12 and PKCS5v1 |
michael@0 | 106 | * for PKCS5v2 it returns SEC_OID_PKCS5_PBKDF2. |
michael@0 | 107 | */ |
michael@0 | 108 | SECOidTag |
michael@0 | 109 | sec_pkcs5GetCryptoFromAlgTag(SECOidTag algorithm) |
michael@0 | 110 | { |
michael@0 | 111 | switch(algorithm) |
michael@0 | 112 | { |
michael@0 | 113 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: |
michael@0 | 114 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: |
michael@0 | 115 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC: |
michael@0 | 116 | return SEC_OID_DES_EDE3_CBC; |
michael@0 | 117 | case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC: |
michael@0 | 118 | case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC: |
michael@0 | 119 | case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC: |
michael@0 | 120 | return SEC_OID_DES_CBC; |
michael@0 | 121 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
michael@0 | 122 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
michael@0 | 123 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
michael@0 | 124 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
michael@0 | 125 | return SEC_OID_RC2_CBC; |
michael@0 | 126 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4: |
michael@0 | 127 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4: |
michael@0 | 128 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: |
michael@0 | 129 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: |
michael@0 | 130 | return SEC_OID_RC4; |
michael@0 | 131 | case SEC_OID_PKCS5_PBKDF2: |
michael@0 | 132 | case SEC_OID_PKCS5_PBES2: |
michael@0 | 133 | case SEC_OID_PKCS5_PBMAC1: |
michael@0 | 134 | return SEC_OID_PKCS5_PBKDF2; |
michael@0 | 135 | default: |
michael@0 | 136 | break; |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | return SEC_OID_UNKNOWN; |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | /* |
michael@0 | 143 | * get a new PKCS5 V2 Parameter from the algorithm id. |
michael@0 | 144 | * if arena is passed in, use it, otherwise create a new arena. |
michael@0 | 145 | */ |
michael@0 | 146 | sec_pkcs5V2Parameter * |
michael@0 | 147 | sec_pkcs5_v2_get_v2_param(PLArenaPool *arena, SECAlgorithmID *algid) |
michael@0 | 148 | { |
michael@0 | 149 | PLArenaPool *localArena = NULL; |
michael@0 | 150 | sec_pkcs5V2Parameter *pbeV2_param; |
michael@0 | 151 | SECStatus rv; |
michael@0 | 152 | |
michael@0 | 153 | if (arena == NULL) { |
michael@0 | 154 | localArena = arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
michael@0 | 155 | if (arena == NULL) { |
michael@0 | 156 | return NULL; |
michael@0 | 157 | } |
michael@0 | 158 | } |
michael@0 | 159 | pbeV2_param = PORT_ArenaZNew(arena, sec_pkcs5V2Parameter); |
michael@0 | 160 | if (pbeV2_param == NULL) { |
michael@0 | 161 | goto loser; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | rv = SEC_ASN1DecodeItem(arena, pbeV2_param, |
michael@0 | 165 | SEC_PKCS5V2ParameterTemplate, &algid->parameters); |
michael@0 | 166 | if (rv == SECFailure) { |
michael@0 | 167 | goto loser; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | pbeV2_param->poolp = arena; |
michael@0 | 171 | return pbeV2_param; |
michael@0 | 172 | loser: |
michael@0 | 173 | if (localArena) { |
michael@0 | 174 | PORT_FreeArena(arena, PR_FALSE); |
michael@0 | 175 | } |
michael@0 | 176 | return NULL; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | void |
michael@0 | 180 | sec_pkcs5_v2_destroy_v2_param(sec_pkcs5V2Parameter *param) |
michael@0 | 181 | { |
michael@0 | 182 | if (param && param->poolp) { |
michael@0 | 183 | PORT_FreeArena(param->poolp, PR_TRUE); |
michael@0 | 184 | } |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | |
michael@0 | 188 | /* maps crypto algorithm from PBE algorithm. |
michael@0 | 189 | */ |
michael@0 | 190 | SECOidTag |
michael@0 | 191 | SEC_PKCS5GetCryptoAlgorithm(SECAlgorithmID *algid) |
michael@0 | 192 | { |
michael@0 | 193 | |
michael@0 | 194 | SECOidTag pbeAlg; |
michael@0 | 195 | SECOidTag cipherAlg; |
michael@0 | 196 | |
michael@0 | 197 | if(algid == NULL) |
michael@0 | 198 | return SEC_OID_UNKNOWN; |
michael@0 | 199 | |
michael@0 | 200 | pbeAlg = SECOID_GetAlgorithmTag(algid); |
michael@0 | 201 | cipherAlg = sec_pkcs5GetCryptoFromAlgTag(pbeAlg); |
michael@0 | 202 | if ((cipherAlg == SEC_OID_PKCS5_PBKDF2) && |
michael@0 | 203 | (pbeAlg != SEC_OID_PKCS5_PBKDF2)) { |
michael@0 | 204 | sec_pkcs5V2Parameter *pbeV2_param; |
michael@0 | 205 | cipherAlg = SEC_OID_UNKNOWN; |
michael@0 | 206 | |
michael@0 | 207 | pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid); |
michael@0 | 208 | if (pbeV2_param != NULL) { |
michael@0 | 209 | cipherAlg = SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId); |
michael@0 | 210 | sec_pkcs5_v2_destroy_v2_param(pbeV2_param); |
michael@0 | 211 | } |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | return cipherAlg; |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | /* check to see if an oid is a pbe algorithm |
michael@0 | 218 | */ |
michael@0 | 219 | PRBool |
michael@0 | 220 | SEC_PKCS5IsAlgorithmPBEAlg(SECAlgorithmID *algid) |
michael@0 | 221 | { |
michael@0 | 222 | return (PRBool)(SEC_PKCS5GetCryptoAlgorithm(algid) != SEC_OID_UNKNOWN); |
michael@0 | 223 | } |
michael@0 | 224 | |
michael@0 | 225 | PRBool |
michael@0 | 226 | SEC_PKCS5IsAlgorithmPBEAlgTag(SECOidTag algtag) |
michael@0 | 227 | { |
michael@0 | 228 | return (PRBool)(sec_pkcs5GetCryptoFromAlgTag(algtag) != SEC_OID_UNKNOWN); |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | /* |
michael@0 | 232 | * find the most appropriate PKCS5v2 overall oid tag from a regular |
michael@0 | 233 | * cipher/hash algorithm tag. |
michael@0 | 234 | */ |
michael@0 | 235 | static SECOidTag |
michael@0 | 236 | sec_pkcs5v2_get_pbe(SECOidTag algTag) |
michael@0 | 237 | { |
michael@0 | 238 | /* if it's a valid hash oid... */ |
michael@0 | 239 | if (HASH_GetHashOidTagByHMACOidTag(algTag) != SEC_OID_UNKNOWN) { |
michael@0 | 240 | /* use the MAC tag */ |
michael@0 | 241 | return SEC_OID_PKCS5_PBMAC1; |
michael@0 | 242 | } |
michael@0 | 243 | if (HASH_GetHashTypeByOidTag(algTag) != HASH_AlgNULL) { |
michael@0 | 244 | /* eliminate Hash algorithms */ |
michael@0 | 245 | return SEC_OID_UNKNOWN; |
michael@0 | 246 | } |
michael@0 | 247 | if (PK11_AlgtagToMechanism(algTag) != CKM_INVALID_MECHANISM) { |
michael@0 | 248 | /* it's not a hash, if it has a PKCS #11 mechanism associated |
michael@0 | 249 | * with it, assume it's a cipher. (NOTE this will generate |
michael@0 | 250 | * some false positives). */ |
michael@0 | 251 | return SEC_OID_PKCS5_PBES2; |
michael@0 | 252 | } |
michael@0 | 253 | return SEC_OID_UNKNOWN; |
michael@0 | 254 | } |
michael@0 | 255 | |
michael@0 | 256 | /* |
michael@0 | 257 | * maps PBE algorithm from crypto algorithm, assumes SHA1 hashing. |
michael@0 | 258 | * input keyLen in bits. |
michael@0 | 259 | */ |
michael@0 | 260 | SECOidTag |
michael@0 | 261 | SEC_PKCS5GetPBEAlgorithm(SECOidTag algTag, int keyLen) |
michael@0 | 262 | { |
michael@0 | 263 | switch(algTag) |
michael@0 | 264 | { |
michael@0 | 265 | case SEC_OID_DES_EDE3_CBC: |
michael@0 | 266 | switch(keyLen) { |
michael@0 | 267 | case 168: |
michael@0 | 268 | case 192: |
michael@0 | 269 | case 0: |
michael@0 | 270 | return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC; |
michael@0 | 271 | case 128: |
michael@0 | 272 | case 92: |
michael@0 | 273 | return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC; |
michael@0 | 274 | default: |
michael@0 | 275 | break; |
michael@0 | 276 | } |
michael@0 | 277 | break; |
michael@0 | 278 | case SEC_OID_DES_CBC: |
michael@0 | 279 | return SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC; |
michael@0 | 280 | case SEC_OID_RC2_CBC: |
michael@0 | 281 | switch(keyLen) { |
michael@0 | 282 | case 40: |
michael@0 | 283 | return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC; |
michael@0 | 284 | case 128: |
michael@0 | 285 | case 0: |
michael@0 | 286 | return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC; |
michael@0 | 287 | default: |
michael@0 | 288 | break; |
michael@0 | 289 | } |
michael@0 | 290 | break; |
michael@0 | 291 | case SEC_OID_RC4: |
michael@0 | 292 | switch(keyLen) { |
michael@0 | 293 | case 40: |
michael@0 | 294 | return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4; |
michael@0 | 295 | case 128: |
michael@0 | 296 | case 0: |
michael@0 | 297 | return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4; |
michael@0 | 298 | default: |
michael@0 | 299 | break; |
michael@0 | 300 | } |
michael@0 | 301 | break; |
michael@0 | 302 | default: |
michael@0 | 303 | return sec_pkcs5v2_get_pbe(algTag); |
michael@0 | 304 | } |
michael@0 | 305 | |
michael@0 | 306 | return SEC_OID_UNKNOWN; |
michael@0 | 307 | } |
michael@0 | 308 | |
michael@0 | 309 | /* |
michael@0 | 310 | * get the key length in bytes from a PKCS5 PBE |
michael@0 | 311 | */ |
michael@0 | 312 | int |
michael@0 | 313 | sec_pkcs5v2_key_length(SECAlgorithmID *algid) |
michael@0 | 314 | { |
michael@0 | 315 | SECOidTag algorithm; |
michael@0 | 316 | PLArenaPool *arena = NULL; |
michael@0 | 317 | SEC_PKCS5PBEParameter p5_param; |
michael@0 | 318 | SECStatus rv; |
michael@0 | 319 | int length = -1; |
michael@0 | 320 | |
michael@0 | 321 | algorithm = SECOID_GetAlgorithmTag(algid); |
michael@0 | 322 | /* sanity check, they should all be PBKDF2 here */ |
michael@0 | 323 | if (algorithm != SEC_OID_PKCS5_PBKDF2) { |
michael@0 | 324 | return -1; |
michael@0 | 325 | } |
michael@0 | 326 | |
michael@0 | 327 | arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
michael@0 | 328 | if (arena == NULL) { |
michael@0 | 329 | goto loser; |
michael@0 | 330 | } |
michael@0 | 331 | PORT_Memset(&p5_param, 0, sizeof(p5_param)); |
michael@0 | 332 | rv = SEC_ASN1DecodeItem(arena,&p5_param, |
michael@0 | 333 | SEC_PKCS5V2PBEParameterTemplate, &algid->parameters); |
michael@0 | 334 | if (rv != SECSuccess) { |
michael@0 | 335 | goto loser; |
michael@0 | 336 | } |
michael@0 | 337 | |
michael@0 | 338 | if (p5_param.keyLength.data != NULL) { |
michael@0 | 339 | length = DER_GetInteger(&p5_param.keyLength); |
michael@0 | 340 | } |
michael@0 | 341 | |
michael@0 | 342 | loser: |
michael@0 | 343 | if (arena) { |
michael@0 | 344 | PORT_FreeArena(arena, PR_FALSE); |
michael@0 | 345 | } |
michael@0 | 346 | return length; |
michael@0 | 347 | } |
michael@0 | 348 | |
michael@0 | 349 | /* |
michael@0 | 350 | * get the key length in bytes needed for the PBE algorithm |
michael@0 | 351 | */ |
michael@0 | 352 | int |
michael@0 | 353 | SEC_PKCS5GetKeyLength(SECAlgorithmID *algid) |
michael@0 | 354 | { |
michael@0 | 355 | |
michael@0 | 356 | SECOidTag algorithm; |
michael@0 | 357 | |
michael@0 | 358 | if(algid == NULL) |
michael@0 | 359 | return SEC_OID_UNKNOWN; |
michael@0 | 360 | |
michael@0 | 361 | algorithm = SECOID_GetAlgorithmTag(algid); |
michael@0 | 362 | |
michael@0 | 363 | switch(algorithm) |
michael@0 | 364 | { |
michael@0 | 365 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: |
michael@0 | 366 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC: |
michael@0 | 367 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: |
michael@0 | 368 | return 24; |
michael@0 | 369 | case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC: |
michael@0 | 370 | case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC: |
michael@0 | 371 | case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC: |
michael@0 | 372 | return 8; |
michael@0 | 373 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
michael@0 | 374 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4: |
michael@0 | 375 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: |
michael@0 | 376 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
michael@0 | 377 | return 5; |
michael@0 | 378 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
michael@0 | 379 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4: |
michael@0 | 380 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
michael@0 | 381 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: |
michael@0 | 382 | return 16; |
michael@0 | 383 | case SEC_OID_PKCS5_PBKDF2: |
michael@0 | 384 | return sec_pkcs5v2_key_length(algid); |
michael@0 | 385 | case SEC_OID_PKCS5_PBES2: |
michael@0 | 386 | case SEC_OID_PKCS5_PBMAC1: |
michael@0 | 387 | { |
michael@0 | 388 | sec_pkcs5V2Parameter *pbeV2_param; |
michael@0 | 389 | int length = -1; |
michael@0 | 390 | pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid); |
michael@0 | 391 | if (pbeV2_param != NULL) { |
michael@0 | 392 | length = sec_pkcs5v2_key_length(&pbeV2_param->pbeAlgId); |
michael@0 | 393 | sec_pkcs5_v2_destroy_v2_param(pbeV2_param); |
michael@0 | 394 | } |
michael@0 | 395 | return length; |
michael@0 | 396 | } |
michael@0 | 397 | |
michael@0 | 398 | default: |
michael@0 | 399 | break; |
michael@0 | 400 | } |
michael@0 | 401 | return -1; |
michael@0 | 402 | } |
michael@0 | 403 | |
michael@0 | 404 | |
michael@0 | 405 | /* the PKCS12 V2 algorithms only encode the salt, there is no iteration |
michael@0 | 406 | * count so we need a check for V2 algorithm parameters. |
michael@0 | 407 | */ |
michael@0 | 408 | static PRBool |
michael@0 | 409 | sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(SECOidTag algorithm) |
michael@0 | 410 | { |
michael@0 | 411 | switch(algorithm) |
michael@0 | 412 | { |
michael@0 | 413 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: |
michael@0 | 414 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: |
michael@0 | 415 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: |
michael@0 | 416 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: |
michael@0 | 417 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
michael@0 | 418 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
michael@0 | 419 | return PR_TRUE; |
michael@0 | 420 | default: |
michael@0 | 421 | break; |
michael@0 | 422 | } |
michael@0 | 423 | |
michael@0 | 424 | return PR_FALSE; |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | static PRBool |
michael@0 | 428 | sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(SECOidTag algorithm) |
michael@0 | 429 | { |
michael@0 | 430 | switch(algorithm) |
michael@0 | 431 | { |
michael@0 | 432 | case SEC_OID_PKCS5_PBES2: |
michael@0 | 433 | case SEC_OID_PKCS5_PBMAC1: |
michael@0 | 434 | case SEC_OID_PKCS5_PBKDF2: |
michael@0 | 435 | return PR_TRUE; |
michael@0 | 436 | default: |
michael@0 | 437 | break; |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | return PR_FALSE; |
michael@0 | 441 | } |
michael@0 | 442 | |
michael@0 | 443 | /* destroy a pbe parameter. it assumes that the parameter was |
michael@0 | 444 | * generated using the appropriate create function and therefor |
michael@0 | 445 | * contains an arena pool. |
michael@0 | 446 | */ |
michael@0 | 447 | static void |
michael@0 | 448 | sec_pkcs5_destroy_pbe_param(SEC_PKCS5PBEParameter *pbe_param) |
michael@0 | 449 | { |
michael@0 | 450 | if(pbe_param != NULL) |
michael@0 | 451 | PORT_FreeArena(pbe_param->poolp, PR_TRUE); |
michael@0 | 452 | } |
michael@0 | 453 | |
michael@0 | 454 | /* creates a PBE parameter based on the PBE algorithm. the only required |
michael@0 | 455 | * parameters are algorithm and interation. the return is a PBE parameter |
michael@0 | 456 | * which conforms to PKCS 5 parameter unless an extended parameter is needed. |
michael@0 | 457 | * this is primarily if keyLength and a variable key length algorithm are |
michael@0 | 458 | * specified. |
michael@0 | 459 | * salt - if null, a salt will be generated from random bytes. |
michael@0 | 460 | * iteration - number of iterations to perform hashing. |
michael@0 | 461 | * keyLength - only used in variable key length algorithms. if specified, |
michael@0 | 462 | * should be in bytes. |
michael@0 | 463 | * once a parameter is allocated, it should be destroyed calling |
michael@0 | 464 | * sec_pkcs5_destroy_pbe_parameter or SEC_PKCS5DestroyPBEParameter. |
michael@0 | 465 | */ |
michael@0 | 466 | #define DEFAULT_SALT_LENGTH 16 |
michael@0 | 467 | static SEC_PKCS5PBEParameter * |
michael@0 | 468 | sec_pkcs5_create_pbe_parameter(SECOidTag algorithm, |
michael@0 | 469 | SECItem *salt, |
michael@0 | 470 | int iteration, |
michael@0 | 471 | int keyLength, |
michael@0 | 472 | SECOidTag prfAlg) |
michael@0 | 473 | { |
michael@0 | 474 | PLArenaPool *poolp = NULL; |
michael@0 | 475 | SEC_PKCS5PBEParameter *pbe_param = NULL; |
michael@0 | 476 | SECStatus rv= SECSuccess; |
michael@0 | 477 | void *dummy = NULL; |
michael@0 | 478 | |
michael@0 | 479 | if(iteration < 0) { |
michael@0 | 480 | return NULL; |
michael@0 | 481 | } |
michael@0 | 482 | |
michael@0 | 483 | poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
michael@0 | 484 | if(poolp == NULL) |
michael@0 | 485 | return NULL; |
michael@0 | 486 | |
michael@0 | 487 | pbe_param = (SEC_PKCS5PBEParameter *)PORT_ArenaZAlloc(poolp, |
michael@0 | 488 | sizeof(SEC_PKCS5PBEParameter)); |
michael@0 | 489 | if(!pbe_param) { |
michael@0 | 490 | PORT_FreeArena(poolp, PR_TRUE); |
michael@0 | 491 | return NULL; |
michael@0 | 492 | } |
michael@0 | 493 | |
michael@0 | 494 | pbe_param->poolp = poolp; |
michael@0 | 495 | |
michael@0 | 496 | rv = SECFailure; |
michael@0 | 497 | if (salt && salt->data) { |
michael@0 | 498 | rv = SECITEM_CopyItem(poolp, &pbe_param->salt, salt); |
michael@0 | 499 | } else { |
michael@0 | 500 | /* sigh, the old interface generated salt on the fly, so we have to |
michael@0 | 501 | * preserve the semantics */ |
michael@0 | 502 | pbe_param->salt.len = DEFAULT_SALT_LENGTH; |
michael@0 | 503 | pbe_param->salt.data = PORT_ArenaZAlloc(poolp,DEFAULT_SALT_LENGTH); |
michael@0 | 504 | if (pbe_param->salt.data) { |
michael@0 | 505 | rv = PK11_GenerateRandom(pbe_param->salt.data,DEFAULT_SALT_LENGTH); |
michael@0 | 506 | } |
michael@0 | 507 | } |
michael@0 | 508 | |
michael@0 | 509 | if(rv != SECSuccess) { |
michael@0 | 510 | PORT_FreeArena(poolp, PR_TRUE); |
michael@0 | 511 | return NULL; |
michael@0 | 512 | } |
michael@0 | 513 | |
michael@0 | 514 | /* encode the integer */ |
michael@0 | 515 | dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->iteration, |
michael@0 | 516 | iteration); |
michael@0 | 517 | rv = (dummy) ? SECSuccess : SECFailure; |
michael@0 | 518 | |
michael@0 | 519 | if(rv != SECSuccess) { |
michael@0 | 520 | PORT_FreeArena(poolp, PR_FALSE); |
michael@0 | 521 | return NULL; |
michael@0 | 522 | } |
michael@0 | 523 | |
michael@0 | 524 | /* |
michael@0 | 525 | * for PKCS5 v2 Add the keylength and the prf |
michael@0 | 526 | */ |
michael@0 | 527 | if (algorithm == SEC_OID_PKCS5_PBKDF2) { |
michael@0 | 528 | dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->keyLength, |
michael@0 | 529 | keyLength); |
michael@0 | 530 | rv = (dummy) ? SECSuccess : SECFailure; |
michael@0 | 531 | if (rv != SECSuccess) { |
michael@0 | 532 | PORT_FreeArena(poolp, PR_FALSE); |
michael@0 | 533 | return NULL; |
michael@0 | 534 | } |
michael@0 | 535 | rv = SECOID_SetAlgorithmID(poolp, &pbe_param->prfAlgId, prfAlg, NULL); |
michael@0 | 536 | if (rv != SECSuccess) { |
michael@0 | 537 | PORT_FreeArena(poolp, PR_FALSE); |
michael@0 | 538 | return NULL; |
michael@0 | 539 | } |
michael@0 | 540 | pbe_param->pPrfAlgId = &pbe_param->prfAlgId; |
michael@0 | 541 | } |
michael@0 | 542 | |
michael@0 | 543 | return pbe_param; |
michael@0 | 544 | } |
michael@0 | 545 | |
michael@0 | 546 | /* creates a algorithm ID containing the PBE algorithm and appropriate |
michael@0 | 547 | * parameters. the required parameter is the algorithm. if salt is |
michael@0 | 548 | * not specified, it is generated randomly. |
michael@0 | 549 | * |
michael@0 | 550 | * the returned SECAlgorithmID should be destroyed using |
michael@0 | 551 | * SECOID_DestroyAlgorithmID |
michael@0 | 552 | */ |
michael@0 | 553 | SECAlgorithmID * |
michael@0 | 554 | sec_pkcs5CreateAlgorithmID(SECOidTag algorithm, |
michael@0 | 555 | SECOidTag cipherAlgorithm, |
michael@0 | 556 | SECOidTag prfAlg, |
michael@0 | 557 | SECOidTag *pPbeAlgorithm, |
michael@0 | 558 | int keyLength, |
michael@0 | 559 | SECItem *salt, |
michael@0 | 560 | int iteration) |
michael@0 | 561 | { |
michael@0 | 562 | PLArenaPool *poolp = NULL; |
michael@0 | 563 | SECAlgorithmID *algid, *ret_algid = NULL; |
michael@0 | 564 | SECOidTag pbeAlgorithm = algorithm; |
michael@0 | 565 | SECItem der_param; |
michael@0 | 566 | void *dummy; |
michael@0 | 567 | SECStatus rv = SECFailure; |
michael@0 | 568 | SEC_PKCS5PBEParameter *pbe_param = NULL; |
michael@0 | 569 | sec_pkcs5V2Parameter pbeV2_param; |
michael@0 | 570 | |
michael@0 | 571 | if(iteration <= 0) { |
michael@0 | 572 | return NULL; |
michael@0 | 573 | } |
michael@0 | 574 | |
michael@0 | 575 | poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
michael@0 | 576 | if(!poolp) { |
michael@0 | 577 | goto loser; |
michael@0 | 578 | } |
michael@0 | 579 | |
michael@0 | 580 | if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm) || |
michael@0 | 581 | sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) { |
michael@0 | 582 | /* use PKCS 5 v2 */ |
michael@0 | 583 | SECItem *cipherParams; |
michael@0 | 584 | |
michael@0 | 585 | /* |
michael@0 | 586 | * if we ask for pkcs5 Algorithms directly, then the |
michael@0 | 587 | * application needs to supply the cipher algorithm, |
michael@0 | 588 | * otherwise we are implicitly using pkcs5 v2 and the |
michael@0 | 589 | * passed in algorithm is the encryption algorithm. |
michael@0 | 590 | */ |
michael@0 | 591 | if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) { |
michael@0 | 592 | if (cipherAlgorithm == SEC_OID_UNKNOWN) { |
michael@0 | 593 | goto loser; |
michael@0 | 594 | } |
michael@0 | 595 | } else { |
michael@0 | 596 | cipherAlgorithm = algorithm; |
michael@0 | 597 | /* force algorithm to be chosen below */ |
michael@0 | 598 | algorithm = SEC_OID_PKCS5_PBKDF2; |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | pbeAlgorithm = SEC_OID_PKCS5_PBKDF2; |
michael@0 | 602 | /* |
michael@0 | 603 | * 'algorithm' is the overall algorithm oid tag used to wrap the |
michael@0 | 604 | * entire algoithm ID block. For PKCS5v1 and PKCS12, this |
michael@0 | 605 | * algorithm OID has encoded in it both the PBE KDF function |
michael@0 | 606 | * and the encryption algorithm. For PKCS 5v2, PBE KDF and |
michael@0 | 607 | * encryption/macing oids are encoded as parameters in |
michael@0 | 608 | * the algorithm ID block. |
michael@0 | 609 | * |
michael@0 | 610 | * Thus in PKCS5 v1 and PKCS12, this algorithm maps to a pkcs #11 |
michael@0 | 611 | * mechanism, where as in PKCS 5v2, this alogithm tag does not map |
michael@0 | 612 | * directly to a PKCS #11 mechanim, instead the 2 oids in the |
michael@0 | 613 | * algorithm ID block map the the actual PKCS #11 mechanism. |
michael@0 | 614 | * gorithm is). We use choose this algorithm oid based on the |
michael@0 | 615 | * cipherAlgorithm to determine what this should be (MAC1 or PBES2). |
michael@0 | 616 | */ |
michael@0 | 617 | if (algorithm == SEC_OID_PKCS5_PBKDF2) { |
michael@0 | 618 | /* choose mac or pbes */ |
michael@0 | 619 | algorithm = sec_pkcs5v2_get_pbe(cipherAlgorithm); |
michael@0 | 620 | } |
michael@0 | 621 | |
michael@0 | 622 | /* set the PKCS5v2 specific parameters */ |
michael@0 | 623 | if (keyLength == 0) { |
michael@0 | 624 | SECOidTag hashAlg = HASH_GetHashOidTagByHMACOidTag(cipherAlgorithm); |
michael@0 | 625 | if (hashAlg != SEC_OID_UNKNOWN) { |
michael@0 | 626 | keyLength = HASH_ResultLenByOidTag(hashAlg); |
michael@0 | 627 | } else { |
michael@0 | 628 | CK_MECHANISM_TYPE cryptoMech; |
michael@0 | 629 | cryptoMech = PK11_AlgtagToMechanism(cipherAlgorithm); |
michael@0 | 630 | if (cryptoMech == CKM_INVALID_MECHANISM) { |
michael@0 | 631 | goto loser; |
michael@0 | 632 | } |
michael@0 | 633 | keyLength = PK11_GetMaxKeyLength(cryptoMech); |
michael@0 | 634 | } |
michael@0 | 635 | if (keyLength == 0) { |
michael@0 | 636 | goto loser; |
michael@0 | 637 | } |
michael@0 | 638 | } |
michael@0 | 639 | /* currently only SEC_OID_HMAC_SHA1 is defined */ |
michael@0 | 640 | if (prfAlg == SEC_OID_UNKNOWN) { |
michael@0 | 641 | prfAlg = SEC_OID_HMAC_SHA1; |
michael@0 | 642 | } |
michael@0 | 643 | |
michael@0 | 644 | /* build the PKCS5v2 cipher algorithm id */ |
michael@0 | 645 | cipherParams = pk11_GenerateNewParamWithKeyLen( |
michael@0 | 646 | PK11_AlgtagToMechanism(cipherAlgorithm), keyLength); |
michael@0 | 647 | if (!cipherParams) { |
michael@0 | 648 | goto loser; |
michael@0 | 649 | } |
michael@0 | 650 | |
michael@0 | 651 | PORT_Memset(&pbeV2_param, 0, sizeof (pbeV2_param)); |
michael@0 | 652 | |
michael@0 | 653 | rv = PK11_ParamToAlgid(cipherAlgorithm, cipherParams, |
michael@0 | 654 | poolp, &pbeV2_param.cipherAlgId); |
michael@0 | 655 | SECITEM_FreeItem(cipherParams, PR_TRUE); |
michael@0 | 656 | if (rv != SECSuccess) { |
michael@0 | 657 | goto loser; |
michael@0 | 658 | } |
michael@0 | 659 | } |
michael@0 | 660 | |
michael@0 | 661 | |
michael@0 | 662 | /* generate the parameter */ |
michael@0 | 663 | pbe_param = sec_pkcs5_create_pbe_parameter(pbeAlgorithm, salt, iteration, |
michael@0 | 664 | keyLength, prfAlg); |
michael@0 | 665 | if(!pbe_param) { |
michael@0 | 666 | goto loser; |
michael@0 | 667 | } |
michael@0 | 668 | |
michael@0 | 669 | /* generate the algorithm id */ |
michael@0 | 670 | algid = (SECAlgorithmID *)PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID)); |
michael@0 | 671 | if(algid == NULL) { |
michael@0 | 672 | goto loser; |
michael@0 | 673 | } |
michael@0 | 674 | |
michael@0 | 675 | der_param.data = NULL; |
michael@0 | 676 | der_param.len = 0; |
michael@0 | 677 | if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) { |
michael@0 | 678 | /* first encode the PBE algorithm ID */ |
michael@0 | 679 | dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param, |
michael@0 | 680 | SEC_PKCS5V2PBEParameterTemplate); |
michael@0 | 681 | if (dummy == NULL) { |
michael@0 | 682 | goto loser; |
michael@0 | 683 | } |
michael@0 | 684 | rv = SECOID_SetAlgorithmID(poolp, &pbeV2_param.pbeAlgId, |
michael@0 | 685 | pbeAlgorithm, &der_param); |
michael@0 | 686 | if (rv != SECSuccess) { |
michael@0 | 687 | goto loser; |
michael@0 | 688 | } |
michael@0 | 689 | |
michael@0 | 690 | /* now encode the Full PKCS 5 parameter */ |
michael@0 | 691 | der_param.data = NULL; |
michael@0 | 692 | der_param.len = 0; |
michael@0 | 693 | dummy = SEC_ASN1EncodeItem(poolp, &der_param, &pbeV2_param, |
michael@0 | 694 | SEC_PKCS5V2ParameterTemplate); |
michael@0 | 695 | } else if(!sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) { |
michael@0 | 696 | dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param, |
michael@0 | 697 | SEC_PKCS5PBEParameterTemplate); |
michael@0 | 698 | } else { |
michael@0 | 699 | dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param, |
michael@0 | 700 | SEC_V2PKCS12PBEParameterTemplate); |
michael@0 | 701 | } |
michael@0 | 702 | if (dummy == NULL) { |
michael@0 | 703 | goto loser; |
michael@0 | 704 | } |
michael@0 | 705 | |
michael@0 | 706 | rv = SECOID_SetAlgorithmID(poolp, algid, algorithm, &der_param); |
michael@0 | 707 | if (rv != SECSuccess) { |
michael@0 | 708 | goto loser; |
michael@0 | 709 | } |
michael@0 | 710 | |
michael@0 | 711 | ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID)); |
michael@0 | 712 | if (ret_algid == NULL) { |
michael@0 | 713 | goto loser; |
michael@0 | 714 | } |
michael@0 | 715 | |
michael@0 | 716 | rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid); |
michael@0 | 717 | if (rv != SECSuccess) { |
michael@0 | 718 | SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE); |
michael@0 | 719 | ret_algid = NULL; |
michael@0 | 720 | } else if (pPbeAlgorithm) { |
michael@0 | 721 | *pPbeAlgorithm = pbeAlgorithm; |
michael@0 | 722 | } |
michael@0 | 723 | |
michael@0 | 724 | loser: |
michael@0 | 725 | if (poolp != NULL) { |
michael@0 | 726 | PORT_FreeArena(poolp, PR_TRUE); |
michael@0 | 727 | algid = NULL; |
michael@0 | 728 | } |
michael@0 | 729 | |
michael@0 | 730 | if (pbe_param) { |
michael@0 | 731 | sec_pkcs5_destroy_pbe_param(pbe_param); |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | return ret_algid; |
michael@0 | 735 | } |
michael@0 | 736 | |
michael@0 | 737 | SECStatus |
michael@0 | 738 | pbe_PK11AlgidToParam(SECAlgorithmID *algid,SECItem *mech) |
michael@0 | 739 | { |
michael@0 | 740 | SEC_PKCS5PBEParameter p5_param; |
michael@0 | 741 | SECItem *salt = NULL; |
michael@0 | 742 | SECOidTag algorithm = SECOID_GetAlgorithmTag(algid); |
michael@0 | 743 | PLArenaPool *arena = NULL; |
michael@0 | 744 | SECStatus rv = SECFailure; |
michael@0 | 745 | unsigned char *paramData = NULL; |
michael@0 | 746 | unsigned char *pSalt = NULL; |
michael@0 | 747 | CK_ULONG iterations; |
michael@0 | 748 | int paramLen = 0; |
michael@0 | 749 | int iv_len; |
michael@0 | 750 | |
michael@0 | 751 | |
michael@0 | 752 | arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
michael@0 | 753 | if (arena == NULL) { |
michael@0 | 754 | goto loser; |
michael@0 | 755 | } |
michael@0 | 756 | |
michael@0 | 757 | |
michael@0 | 758 | /* |
michael@0 | 759 | * decode the algid based on the pbe type |
michael@0 | 760 | */ |
michael@0 | 761 | PORT_Memset(&p5_param, 0, sizeof(p5_param)); |
michael@0 | 762 | if (sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) { |
michael@0 | 763 | iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm)); |
michael@0 | 764 | rv = SEC_ASN1DecodeItem(arena, &p5_param, |
michael@0 | 765 | SEC_V2PKCS12PBEParameterTemplate, &algid->parameters); |
michael@0 | 766 | } else if (algorithm == SEC_OID_PKCS5_PBKDF2) { |
michael@0 | 767 | iv_len = 0; |
michael@0 | 768 | rv = SEC_ASN1DecodeItem(arena,&p5_param, |
michael@0 | 769 | SEC_PKCS5V2PBEParameterTemplate, &algid->parameters); |
michael@0 | 770 | } else { |
michael@0 | 771 | iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm)); |
michael@0 | 772 | rv = SEC_ASN1DecodeItem(arena,&p5_param,SEC_PKCS5PBEParameterTemplate, |
michael@0 | 773 | &algid->parameters); |
michael@0 | 774 | } |
michael@0 | 775 | |
michael@0 | 776 | if (iv_len < 0) { |
michael@0 | 777 | goto loser; |
michael@0 | 778 | } |
michael@0 | 779 | |
michael@0 | 780 | if (rv != SECSuccess) { |
michael@0 | 781 | goto loser; |
michael@0 | 782 | } |
michael@0 | 783 | |
michael@0 | 784 | /* get salt */ |
michael@0 | 785 | salt = &p5_param.salt; |
michael@0 | 786 | iterations = (CK_ULONG) DER_GetInteger(&p5_param.iteration); |
michael@0 | 787 | |
michael@0 | 788 | /* allocate and fill in the PKCS #11 parameters |
michael@0 | 789 | * based on the algorithm. */ |
michael@0 | 790 | if (algorithm == SEC_OID_PKCS5_PBKDF2) { |
michael@0 | 791 | SECOidTag prfAlgTag; |
michael@0 | 792 | CK_PKCS5_PBKD2_PARAMS *pbeV2_params = |
michael@0 | 793 | (CK_PKCS5_PBKD2_PARAMS *)PORT_ZAlloc( |
michael@0 | 794 | sizeof(CK_PKCS5_PBKD2_PARAMS)+ salt->len); |
michael@0 | 795 | |
michael@0 | 796 | if (pbeV2_params == NULL) { |
michael@0 | 797 | goto loser; |
michael@0 | 798 | } |
michael@0 | 799 | paramData = (unsigned char *)pbeV2_params; |
michael@0 | 800 | paramLen = sizeof(CK_PKCS5_PBKD2_PARAMS); |
michael@0 | 801 | |
michael@0 | 802 | /* set the prf */ |
michael@0 | 803 | prfAlgTag = SEC_OID_HMAC_SHA1; |
michael@0 | 804 | if (p5_param.pPrfAlgId && |
michael@0 | 805 | p5_param.pPrfAlgId->algorithm.data != 0) { |
michael@0 | 806 | prfAlgTag = SECOID_GetAlgorithmTag(p5_param.pPrfAlgId); |
michael@0 | 807 | } |
michael@0 | 808 | if (prfAlgTag == SEC_OID_HMAC_SHA1) { |
michael@0 | 809 | pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA1; |
michael@0 | 810 | } else { |
michael@0 | 811 | /* only SHA1_HMAC is currently supported by PKCS #11 */ |
michael@0 | 812 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
michael@0 | 813 | goto loser; |
michael@0 | 814 | } |
michael@0 | 815 | |
michael@0 | 816 | /* probably should fetch these from the prfAlgid */ |
michael@0 | 817 | pbeV2_params->pPrfData = NULL; |
michael@0 | 818 | pbeV2_params->ulPrfDataLen = 0; |
michael@0 | 819 | pbeV2_params->saltSource = CKZ_SALT_SPECIFIED; |
michael@0 | 820 | pSalt = ((CK_CHAR_PTR) pbeV2_params)+sizeof(CK_PKCS5_PBKD2_PARAMS); |
michael@0 | 821 | PORT_Memcpy(pSalt, salt->data, salt->len); |
michael@0 | 822 | pbeV2_params->pSaltSourceData = pSalt; |
michael@0 | 823 | pbeV2_params->ulSaltSourceDataLen = salt->len; |
michael@0 | 824 | pbeV2_params->iterations = iterations; |
michael@0 | 825 | } else { |
michael@0 | 826 | CK_PBE_PARAMS *pbe_params = NULL; |
michael@0 | 827 | pbe_params = (CK_PBE_PARAMS *)PORT_ZAlloc(sizeof(CK_PBE_PARAMS)+ |
michael@0 | 828 | salt->len+iv_len); |
michael@0 | 829 | if (pbe_params == NULL) { |
michael@0 | 830 | goto loser; |
michael@0 | 831 | } |
michael@0 | 832 | paramData = (unsigned char *)pbe_params; |
michael@0 | 833 | paramLen = sizeof(CK_PBE_PARAMS); |
michael@0 | 834 | |
michael@0 | 835 | pSalt = ((CK_CHAR_PTR) pbe_params)+sizeof(CK_PBE_PARAMS); |
michael@0 | 836 | pbe_params->pSalt = pSalt; |
michael@0 | 837 | PORT_Memcpy(pSalt, salt->data, salt->len); |
michael@0 | 838 | pbe_params->ulSaltLen = salt->len; |
michael@0 | 839 | if (iv_len) { |
michael@0 | 840 | pbe_params->pInitVector = |
michael@0 | 841 | ((CK_CHAR_PTR) pbe_params)+ sizeof(CK_PBE_PARAMS)+salt->len; |
michael@0 | 842 | } |
michael@0 | 843 | pbe_params->ulIteration = iterations; |
michael@0 | 844 | } |
michael@0 | 845 | |
michael@0 | 846 | /* copy into the mechanism sec item */ |
michael@0 | 847 | mech->data = paramData; |
michael@0 | 848 | mech->len = paramLen; |
michael@0 | 849 | if (arena) { |
michael@0 | 850 | PORT_FreeArena(arena,PR_TRUE); |
michael@0 | 851 | } |
michael@0 | 852 | return SECSuccess; |
michael@0 | 853 | |
michael@0 | 854 | loser: |
michael@0 | 855 | if (paramData) { |
michael@0 | 856 | PORT_Free(paramData); |
michael@0 | 857 | } |
michael@0 | 858 | if (arena) { |
michael@0 | 859 | PORT_FreeArena(arena,PR_TRUE); |
michael@0 | 860 | } |
michael@0 | 861 | return SECFailure; |
michael@0 | 862 | } |
michael@0 | 863 | |
michael@0 | 864 | /* |
michael@0 | 865 | * public, deprecated, not valid for pkcs5 v2 |
michael@0 | 866 | * |
michael@0 | 867 | * use PK11_CreatePBEV2AlgorithmID or PK11_CreatePBEAlgorithmID to create |
michael@0 | 868 | * PBE algorithmID's directly. |
michael@0 | 869 | */ |
michael@0 | 870 | SECStatus |
michael@0 | 871 | PBE_PK11ParamToAlgid(SECOidTag algTag, SECItem *param, PLArenaPool *arena, |
michael@0 | 872 | SECAlgorithmID *algId) |
michael@0 | 873 | { |
michael@0 | 874 | CK_PBE_PARAMS *pbe_param; |
michael@0 | 875 | SECItem pbeSalt; |
michael@0 | 876 | SECAlgorithmID *pbeAlgID = NULL; |
michael@0 | 877 | SECStatus rv; |
michael@0 | 878 | |
michael@0 | 879 | if(!param || !algId) { |
michael@0 | 880 | return SECFailure; |
michael@0 | 881 | } |
michael@0 | 882 | |
michael@0 | 883 | pbe_param = (CK_PBE_PARAMS *)param->data; |
michael@0 | 884 | pbeSalt.data = (unsigned char *)pbe_param->pSalt; |
michael@0 | 885 | pbeSalt.len = pbe_param->ulSaltLen; |
michael@0 | 886 | pbeAlgID = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, |
michael@0 | 887 | SEC_OID_UNKNOWN, NULL, 0, &pbeSalt, (int)pbe_param->ulIteration); |
michael@0 | 888 | if(!pbeAlgID) { |
michael@0 | 889 | return SECFailure; |
michael@0 | 890 | } |
michael@0 | 891 | |
michael@0 | 892 | rv = SECOID_CopyAlgorithmID(arena, algId, pbeAlgID); |
michael@0 | 893 | SECOID_DestroyAlgorithmID(pbeAlgID, PR_TRUE); |
michael@0 | 894 | return rv; |
michael@0 | 895 | } |
michael@0 | 896 | |
michael@0 | 897 | /* |
michael@0 | 898 | * public, Deprecated, This function is only for binary compatibility with |
michael@0 | 899 | * older applications. Does not support PKCS5v2. |
michael@0 | 900 | * |
michael@0 | 901 | * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for |
michael@0 | 902 | * iv values rather than generating PBE bits directly. |
michael@0 | 903 | */ |
michael@0 | 904 | PBEBitGenContext * |
michael@0 | 905 | PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose, |
michael@0 | 906 | SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded, |
michael@0 | 907 | unsigned int iterations) |
michael@0 | 908 | { |
michael@0 | 909 | SECItem *context = NULL; |
michael@0 | 910 | SECItem mechItem; |
michael@0 | 911 | CK_PBE_PARAMS pbe_params; |
michael@0 | 912 | CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; |
michael@0 | 913 | PK11SlotInfo *slot; |
michael@0 | 914 | PK11SymKey *symKey = NULL; |
michael@0 | 915 | unsigned char ivData[8]; |
michael@0 | 916 | |
michael@0 | 917 | |
michael@0 | 918 | /* use the purpose to select the low level keygen algorithm */ |
michael@0 | 919 | switch (bitGenPurpose) { |
michael@0 | 920 | case pbeBitGenIntegrityKey: |
michael@0 | 921 | switch (hashAlgorithm) { |
michael@0 | 922 | case SEC_OID_SHA1: |
michael@0 | 923 | mechanism = CKM_PBA_SHA1_WITH_SHA1_HMAC; |
michael@0 | 924 | break; |
michael@0 | 925 | case SEC_OID_MD2: |
michael@0 | 926 | mechanism = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; |
michael@0 | 927 | break; |
michael@0 | 928 | case SEC_OID_MD5: |
michael@0 | 929 | mechanism = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; |
michael@0 | 930 | break; |
michael@0 | 931 | default: |
michael@0 | 932 | break; |
michael@0 | 933 | } |
michael@0 | 934 | break; |
michael@0 | 935 | case pbeBitGenCipherIV: |
michael@0 | 936 | if (bitsNeeded > 64) { |
michael@0 | 937 | break; |
michael@0 | 938 | } |
michael@0 | 939 | if (hashAlgorithm != SEC_OID_SHA1) { |
michael@0 | 940 | break; |
michael@0 | 941 | } |
michael@0 | 942 | mechanism = CKM_PBE_SHA1_DES3_EDE_CBC; |
michael@0 | 943 | break; |
michael@0 | 944 | case pbeBitGenCipherKey: |
michael@0 | 945 | if (hashAlgorithm != SEC_OID_SHA1) { |
michael@0 | 946 | break; |
michael@0 | 947 | } |
michael@0 | 948 | switch (bitsNeeded) { |
michael@0 | 949 | case 40: |
michael@0 | 950 | mechanism = CKM_PBE_SHA1_RC4_40; |
michael@0 | 951 | break; |
michael@0 | 952 | case 128: |
michael@0 | 953 | mechanism = CKM_PBE_SHA1_RC4_128; |
michael@0 | 954 | break; |
michael@0 | 955 | default: |
michael@0 | 956 | break; |
michael@0 | 957 | } |
michael@0 | 958 | case pbeBitGenIDNull: |
michael@0 | 959 | break; |
michael@0 | 960 | } |
michael@0 | 961 | |
michael@0 | 962 | if (mechanism == CKM_INVALID_MECHANISM) { |
michael@0 | 963 | /* we should set an error, but this is a deprecated function, and |
michael@0 | 964 | * we are keeping bug for bug compatibility;)... */ |
michael@0 | 965 | return NULL; |
michael@0 | 966 | } |
michael@0 | 967 | |
michael@0 | 968 | pbe_params.pInitVector = ivData; |
michael@0 | 969 | pbe_params.pPassword = pwitem->data; |
michael@0 | 970 | pbe_params.ulPasswordLen = pwitem->len; |
michael@0 | 971 | pbe_params.pSalt = salt->data; |
michael@0 | 972 | pbe_params.ulSaltLen = salt->len; |
michael@0 | 973 | pbe_params.ulIteration = iterations; |
michael@0 | 974 | mechItem.data = (unsigned char *) &pbe_params; |
michael@0 | 975 | mechItem.len = sizeof(pbe_params); |
michael@0 | 976 | |
michael@0 | 977 | |
michael@0 | 978 | slot = PK11_GetInternalSlot(); |
michael@0 | 979 | symKey = PK11_RawPBEKeyGen(slot,mechanism, |
michael@0 | 980 | &mechItem, pwitem, PR_FALSE, NULL); |
michael@0 | 981 | PK11_FreeSlot(slot); |
michael@0 | 982 | if (symKey != NULL) { |
michael@0 | 983 | if (bitGenPurpose == pbeBitGenCipherIV) { |
michael@0 | 984 | /* NOTE: this assumes that bitsNeeded is a multiple of 8! */ |
michael@0 | 985 | SECItem ivItem; |
michael@0 | 986 | |
michael@0 | 987 | ivItem.data = ivData; |
michael@0 | 988 | ivItem.len = bitsNeeded/8; |
michael@0 | 989 | context = SECITEM_DupItem(&ivItem); |
michael@0 | 990 | } else { |
michael@0 | 991 | SECItem *keyData; |
michael@0 | 992 | PK11_ExtractKeyValue(symKey); |
michael@0 | 993 | keyData = PK11_GetKeyData(symKey); |
michael@0 | 994 | |
michael@0 | 995 | /* assert bitsNeeded with length? */ |
michael@0 | 996 | if (keyData) { |
michael@0 | 997 | context = SECITEM_DupItem(keyData); |
michael@0 | 998 | } |
michael@0 | 999 | } |
michael@0 | 1000 | PK11_FreeSymKey(symKey); |
michael@0 | 1001 | } |
michael@0 | 1002 | |
michael@0 | 1003 | return (PBEBitGenContext *)context; |
michael@0 | 1004 | } |
michael@0 | 1005 | |
michael@0 | 1006 | /* |
michael@0 | 1007 | * public, Deprecated, This function is only for binary compatibility with |
michael@0 | 1008 | * older applications. Does not support PKCS5v2. |
michael@0 | 1009 | * |
michael@0 | 1010 | * Applications should use PK11_PBEKeyGen() for keys and PK11_GetIV() for |
michael@0 | 1011 | * iv values rather than generating PBE bits directly. |
michael@0 | 1012 | */ |
michael@0 | 1013 | SECItem * |
michael@0 | 1014 | PBE_GenerateBits(PBEBitGenContext *context) |
michael@0 | 1015 | { |
michael@0 | 1016 | return (SECItem *)context; |
michael@0 | 1017 | } |
michael@0 | 1018 | |
michael@0 | 1019 | /* |
michael@0 | 1020 | * public, Deprecated, This function is only for binary compatibility with |
michael@0 | 1021 | * older applications. Does not support PKCS5v2. |
michael@0 | 1022 | * |
michael@0 | 1023 | * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for |
michael@0 | 1024 | * iv values rather than generating PBE bits directly. |
michael@0 | 1025 | */ |
michael@0 | 1026 | void |
michael@0 | 1027 | PBE_DestroyContext(PBEBitGenContext *context) |
michael@0 | 1028 | { |
michael@0 | 1029 | SECITEM_FreeItem((SECItem *)context,PR_TRUE); |
michael@0 | 1030 | } |
michael@0 | 1031 | |
michael@0 | 1032 | /* |
michael@0 | 1033 | * public, deprecated. Replaced with PK11_GetPBEIV(). |
michael@0 | 1034 | */ |
michael@0 | 1035 | SECItem * |
michael@0 | 1036 | SEC_PKCS5GetIV(SECAlgorithmID *algid, SECItem *pwitem, PRBool faulty3DES) |
michael@0 | 1037 | { |
michael@0 | 1038 | /* pbe stuff */ |
michael@0 | 1039 | CK_MECHANISM_TYPE type; |
michael@0 | 1040 | SECItem *param = NULL; |
michael@0 | 1041 | SECItem *iv = NULL; |
michael@0 | 1042 | SECItem src; |
michael@0 | 1043 | int iv_len = 0; |
michael@0 | 1044 | PK11SymKey *symKey; |
michael@0 | 1045 | PK11SlotInfo *slot; |
michael@0 | 1046 | CK_PBE_PARAMS_PTR pPBEparams; |
michael@0 | 1047 | SECOidTag pbeAlg; |
michael@0 | 1048 | |
michael@0 | 1049 | pbeAlg = SECOID_GetAlgorithmTag(algid); |
michael@0 | 1050 | if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) { |
michael@0 | 1051 | unsigned char *ivData; |
michael@0 | 1052 | sec_pkcs5V2Parameter *pbeV2_param = NULL; |
michael@0 | 1053 | |
michael@0 | 1054 | /* can only return the IV if the crypto Algorithm exists */ |
michael@0 | 1055 | if (pbeAlg == SEC_OID_PKCS5_PBKDF2) { |
michael@0 | 1056 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
michael@0 | 1057 | goto loser; |
michael@0 | 1058 | } |
michael@0 | 1059 | pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid); |
michael@0 | 1060 | if (pbeV2_param == NULL) { |
michael@0 | 1061 | goto loser; |
michael@0 | 1062 | } |
michael@0 | 1063 | /* extract the IV from the cipher algid portion of our pkcs 5 v2 |
michael@0 | 1064 | * algorithm id */ |
michael@0 | 1065 | type = PK11_AlgtagToMechanism( |
michael@0 | 1066 | SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId)); |
michael@0 | 1067 | param = PK11_ParamFromAlgid(&pbeV2_param->cipherAlgId); |
michael@0 | 1068 | sec_pkcs5_v2_destroy_v2_param(pbeV2_param); |
michael@0 | 1069 | if (!param) { |
michael@0 | 1070 | goto loser; |
michael@0 | 1071 | } |
michael@0 | 1072 | /* NOTE: NULL is a permissible return here */ |
michael@0 | 1073 | ivData = PK11_IVFromParam(type, param, &iv_len); |
michael@0 | 1074 | src.data = ivData; |
michael@0 | 1075 | src.len = iv_len; |
michael@0 | 1076 | goto done; |
michael@0 | 1077 | } |
michael@0 | 1078 | |
michael@0 | 1079 | type = PK11_AlgtagToMechanism(pbeAlg); |
michael@0 | 1080 | param = PK11_ParamFromAlgid(algid); |
michael@0 | 1081 | if (param == NULL) { |
michael@0 | 1082 | goto done; |
michael@0 | 1083 | } |
michael@0 | 1084 | slot = PK11_GetInternalSlot(); |
michael@0 | 1085 | symKey = PK11_RawPBEKeyGen(slot, type, param, pwitem, faulty3DES, NULL); |
michael@0 | 1086 | PK11_FreeSlot(slot); |
michael@0 | 1087 | if (symKey == NULL) { |
michael@0 | 1088 | goto loser; |
michael@0 | 1089 | } |
michael@0 | 1090 | PK11_FreeSymKey(symKey); |
michael@0 | 1091 | pPBEparams = (CK_PBE_PARAMS_PTR)param->data; |
michael@0 | 1092 | iv_len = PK11_GetIVLength(type); |
michael@0 | 1093 | |
michael@0 | 1094 | src.data = (unsigned char *)pPBEparams->pInitVector; |
michael@0 | 1095 | src.len = iv_len; |
michael@0 | 1096 | |
michael@0 | 1097 | done: |
michael@0 | 1098 | iv = SECITEM_DupItem(&src); |
michael@0 | 1099 | |
michael@0 | 1100 | loser: |
michael@0 | 1101 | if (param) { |
michael@0 | 1102 | SECITEM_ZfreeItem(param, PR_TRUE); |
michael@0 | 1103 | } |
michael@0 | 1104 | return iv; |
michael@0 | 1105 | } |
michael@0 | 1106 | |
michael@0 | 1107 | /* |
michael@0 | 1108 | * Subs from nss 3.x that are deprecated |
michael@0 | 1109 | */ |
michael@0 | 1110 | PBEBitGenContext * |
michael@0 | 1111 | __PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose, |
michael@0 | 1112 | SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded, |
michael@0 | 1113 | unsigned int iterations) |
michael@0 | 1114 | { |
michael@0 | 1115 | PORT_Assert("__PBE_CreateContext is Deprecated" == NULL); |
michael@0 | 1116 | return NULL; |
michael@0 | 1117 | } |
michael@0 | 1118 | |
michael@0 | 1119 | SECItem * |
michael@0 | 1120 | __PBE_GenerateBits(PBEBitGenContext *context) |
michael@0 | 1121 | { |
michael@0 | 1122 | PORT_Assert("__PBE_GenerateBits is Deprecated" == NULL); |
michael@0 | 1123 | return NULL; |
michael@0 | 1124 | } |
michael@0 | 1125 | |
michael@0 | 1126 | void |
michael@0 | 1127 | __PBE_DestroyContext(PBEBitGenContext *context) |
michael@0 | 1128 | { |
michael@0 | 1129 | PORT_Assert("__PBE_DestroyContext is Deprecated" == NULL); |
michael@0 | 1130 | } |
michael@0 | 1131 | |
michael@0 | 1132 | SECStatus |
michael@0 | 1133 | RSA_FormatBlock(SECItem *result, unsigned modulusLen, |
michael@0 | 1134 | int blockType, SECItem *data) |
michael@0 | 1135 | { |
michael@0 | 1136 | PORT_Assert("RSA_FormatBlock is Deprecated" == NULL); |
michael@0 | 1137 | return SECFailure; |
michael@0 | 1138 | } |
michael@0 | 1139 | |
michael@0 | 1140 | /**************************************************************************** |
michael@0 | 1141 | * |
michael@0 | 1142 | * Now Do The PBE Functions Here... |
michael@0 | 1143 | * |
michael@0 | 1144 | ****************************************************************************/ |
michael@0 | 1145 | |
michael@0 | 1146 | static void |
michael@0 | 1147 | pk11_destroy_ck_pbe_params(CK_PBE_PARAMS *pbe_params) |
michael@0 | 1148 | { |
michael@0 | 1149 | if (pbe_params) { |
michael@0 | 1150 | if (pbe_params->pPassword) |
michael@0 | 1151 | PORT_ZFree(pbe_params->pPassword, pbe_params->ulPasswordLen); |
michael@0 | 1152 | if (pbe_params->pSalt) |
michael@0 | 1153 | PORT_ZFree(pbe_params->pSalt, pbe_params->ulSaltLen); |
michael@0 | 1154 | PORT_ZFree(pbe_params, sizeof(CK_PBE_PARAMS)); |
michael@0 | 1155 | } |
michael@0 | 1156 | } |
michael@0 | 1157 | |
michael@0 | 1158 | /* |
michael@0 | 1159 | * public, deprecated. use PK11_CreatePBEAlgorithmID or |
michael@0 | 1160 | * PK11_CreatePBEV2AlgorithmID instead. If you needthe pkcs #11 parameters, |
michael@0 | 1161 | * use PK11_ParamFromAlgid from the algorithm id you created using |
michael@0 | 1162 | * PK11_CreatePBEAlgorithmID or PK11_CreatePBEV2AlgorithmID. |
michael@0 | 1163 | */ |
michael@0 | 1164 | SECItem * |
michael@0 | 1165 | PK11_CreatePBEParams(SECItem *salt, SECItem *pwd, unsigned int iterations) |
michael@0 | 1166 | { |
michael@0 | 1167 | CK_PBE_PARAMS *pbe_params = NULL; |
michael@0 | 1168 | SECItem *paramRV = NULL; |
michael@0 | 1169 | |
michael@0 | 1170 | paramRV = SECITEM_AllocItem(NULL, NULL, sizeof(CK_PBE_PARAMS)); |
michael@0 | 1171 | if (!paramRV ) { |
michael@0 | 1172 | goto loser; |
michael@0 | 1173 | } |
michael@0 | 1174 | /* init paramRV->data with zeros. SECITEM_AllocItem does not do it */ |
michael@0 | 1175 | PORT_Memset(paramRV->data, 0, sizeof(CK_PBE_PARAMS)); |
michael@0 | 1176 | |
michael@0 | 1177 | pbe_params = (CK_PBE_PARAMS *)paramRV->data; |
michael@0 | 1178 | pbe_params->pPassword = (CK_CHAR_PTR)PORT_ZAlloc(pwd->len); |
michael@0 | 1179 | if (!pbe_params->pPassword) { |
michael@0 | 1180 | goto loser; |
michael@0 | 1181 | } |
michael@0 | 1182 | PORT_Memcpy(pbe_params->pPassword, pwd->data, pwd->len); |
michael@0 | 1183 | pbe_params->ulPasswordLen = pwd->len; |
michael@0 | 1184 | |
michael@0 | 1185 | pbe_params->pSalt = (CK_CHAR_PTR)PORT_ZAlloc(salt->len); |
michael@0 | 1186 | if (!pbe_params->pSalt) { |
michael@0 | 1187 | goto loser; |
michael@0 | 1188 | } |
michael@0 | 1189 | PORT_Memcpy(pbe_params->pSalt, salt->data, salt->len); |
michael@0 | 1190 | pbe_params->ulSaltLen = salt->len; |
michael@0 | 1191 | |
michael@0 | 1192 | pbe_params->ulIteration = (CK_ULONG)iterations; |
michael@0 | 1193 | return paramRV; |
michael@0 | 1194 | |
michael@0 | 1195 | loser: |
michael@0 | 1196 | if (pbe_params) |
michael@0 | 1197 | pk11_destroy_ck_pbe_params(pbe_params); |
michael@0 | 1198 | if (paramRV) |
michael@0 | 1199 | PORT_ZFree(paramRV, sizeof(SECItem)); |
michael@0 | 1200 | return NULL; |
michael@0 | 1201 | } |
michael@0 | 1202 | |
michael@0 | 1203 | /* |
michael@0 | 1204 | * public, deprecated. |
michael@0 | 1205 | */ |
michael@0 | 1206 | void |
michael@0 | 1207 | PK11_DestroyPBEParams(SECItem *pItem) |
michael@0 | 1208 | { |
michael@0 | 1209 | if (pItem) { |
michael@0 | 1210 | CK_PBE_PARAMS * params = (CK_PBE_PARAMS *)(pItem->data); |
michael@0 | 1211 | if (params) |
michael@0 | 1212 | pk11_destroy_ck_pbe_params(params); |
michael@0 | 1213 | PORT_ZFree(pItem, sizeof(SECItem)); |
michael@0 | 1214 | } |
michael@0 | 1215 | } |
michael@0 | 1216 | |
michael@0 | 1217 | /* |
michael@0 | 1218 | * public, Partially supports PKCS5 V2 (some parameters are not controllable |
michael@0 | 1219 | * through this interface). Use PK11_CreatePBEV2AlgorithmID() if you need |
michael@0 | 1220 | * finer control these. |
michael@0 | 1221 | */ |
michael@0 | 1222 | SECAlgorithmID * |
michael@0 | 1223 | PK11_CreatePBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt) |
michael@0 | 1224 | { |
michael@0 | 1225 | SECAlgorithmID *algid = NULL; |
michael@0 | 1226 | algid = sec_pkcs5CreateAlgorithmID(algorithm, |
michael@0 | 1227 | SEC_OID_UNKNOWN, SEC_OID_UNKNOWN, NULL, 0, salt, iteration); |
michael@0 | 1228 | return algid; |
michael@0 | 1229 | } |
michael@0 | 1230 | |
michael@0 | 1231 | /* |
michael@0 | 1232 | * public, fully support pkcs5v2. |
michael@0 | 1233 | */ |
michael@0 | 1234 | SECAlgorithmID * |
michael@0 | 1235 | PK11_CreatePBEV2AlgorithmID(SECOidTag pbeAlgTag, SECOidTag cipherAlgTag, |
michael@0 | 1236 | SECOidTag prfAlgTag, int keyLength, int iteration, |
michael@0 | 1237 | SECItem *salt) |
michael@0 | 1238 | { |
michael@0 | 1239 | SECAlgorithmID *algid = NULL; |
michael@0 | 1240 | algid = sec_pkcs5CreateAlgorithmID(pbeAlgTag, cipherAlgTag, prfAlgTag, |
michael@0 | 1241 | NULL, keyLength, salt, iteration); |
michael@0 | 1242 | return algid; |
michael@0 | 1243 | } |
michael@0 | 1244 | |
michael@0 | 1245 | /* |
michael@0 | 1246 | * private. |
michael@0 | 1247 | */ |
michael@0 | 1248 | PK11SymKey * |
michael@0 | 1249 | pk11_RawPBEKeyGenWithKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, |
michael@0 | 1250 | SECItem *params, CK_KEY_TYPE keyType, int keyLen, |
michael@0 | 1251 | SECItem *pwitem, void *wincx) |
michael@0 | 1252 | { |
michael@0 | 1253 | CK_ULONG pwLen; |
michael@0 | 1254 | /* do some sanity checks */ |
michael@0 | 1255 | if ((params == NULL) || (params->data == NULL)) { |
michael@0 | 1256 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 1257 | return NULL; |
michael@0 | 1258 | } |
michael@0 | 1259 | |
michael@0 | 1260 | if (type == CKM_INVALID_MECHANISM) { |
michael@0 | 1261 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
michael@0 | 1262 | return NULL; |
michael@0 | 1263 | } |
michael@0 | 1264 | |
michael@0 | 1265 | /* set the password pointer in the parameters... */ |
michael@0 | 1266 | if (type == CKM_PKCS5_PBKD2) { |
michael@0 | 1267 | CK_PKCS5_PBKD2_PARAMS *pbev2_params; |
michael@0 | 1268 | if (params->len < sizeof(CK_PKCS5_PBKD2_PARAMS)) { |
michael@0 | 1269 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 1270 | return NULL; |
michael@0 | 1271 | } |
michael@0 | 1272 | pbev2_params = (CK_PKCS5_PBKD2_PARAMS *)params->data; |
michael@0 | 1273 | pbev2_params->pPassword = pwitem->data; |
michael@0 | 1274 | pwLen = pwitem->len; |
michael@0 | 1275 | pbev2_params->ulPasswordLen = &pwLen; |
michael@0 | 1276 | } else { |
michael@0 | 1277 | CK_PBE_PARAMS *pbe_params; |
michael@0 | 1278 | if (params->len < sizeof(CK_PBE_PARAMS)) { |
michael@0 | 1279 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 1280 | return NULL; |
michael@0 | 1281 | } |
michael@0 | 1282 | pbe_params = (CK_PBE_PARAMS *)params->data; |
michael@0 | 1283 | pbe_params->pPassword = pwitem->data; |
michael@0 | 1284 | pbe_params->ulPasswordLen = pwitem->len; |
michael@0 | 1285 | } |
michael@0 | 1286 | |
michael@0 | 1287 | /* generate the key (and sometimes the IV as a side effect...) */ |
michael@0 | 1288 | return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, params, keyType, |
michael@0 | 1289 | keyLen, NULL, CKF_SIGN|CKF_ENCRYPT|CKF_DECRYPT|CKF_UNWRAP|CKF_WRAP, |
michael@0 | 1290 | 0, wincx); |
michael@0 | 1291 | } |
michael@0 | 1292 | |
michael@0 | 1293 | /* |
michael@0 | 1294 | * public, deprecated. use PK11_PBEKeyGen instead. |
michael@0 | 1295 | */ |
michael@0 | 1296 | PK11SymKey * |
michael@0 | 1297 | PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *mech, |
michael@0 | 1298 | SECItem *pwitem, PRBool faulty3DES, void *wincx) |
michael@0 | 1299 | { |
michael@0 | 1300 | if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) { |
michael@0 | 1301 | type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC; |
michael@0 | 1302 | } |
michael@0 | 1303 | return pk11_RawPBEKeyGenWithKeyType(slot, type, mech, -1, 0, pwitem, wincx); |
michael@0 | 1304 | } |
michael@0 | 1305 | |
michael@0 | 1306 | /* |
michael@0 | 1307 | * pubic, supports pkcs5 v2. |
michael@0 | 1308 | * |
michael@0 | 1309 | * Create symkey from a PBE key. The algid can be created with |
michael@0 | 1310 | * PK11_CreatePBEV2AlgorithmID and PK11_CreatePBEAlgorithmID, or by |
michael@0 | 1311 | * extraction of der data. |
michael@0 | 1312 | */ |
michael@0 | 1313 | PK11SymKey * |
michael@0 | 1314 | PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem, |
michael@0 | 1315 | PRBool faulty3DES, void *wincx) |
michael@0 | 1316 | { |
michael@0 | 1317 | CK_MECHANISM_TYPE type; |
michael@0 | 1318 | SECItem *param = NULL; |
michael@0 | 1319 | PK11SymKey *symKey = NULL; |
michael@0 | 1320 | SECOidTag pbeAlg; |
michael@0 | 1321 | CK_KEY_TYPE keyType = -1; |
michael@0 | 1322 | int keyLen = 0; |
michael@0 | 1323 | |
michael@0 | 1324 | pbeAlg = SECOID_GetAlgorithmTag(algid); |
michael@0 | 1325 | /* if we're using PKCS5v2, extract the additional information we need |
michael@0 | 1326 | * (key length, key type, and pbeAlg). */ |
michael@0 | 1327 | if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) { |
michael@0 | 1328 | CK_MECHANISM_TYPE cipherMech; |
michael@0 | 1329 | sec_pkcs5V2Parameter *pbeV2_param; |
michael@0 | 1330 | |
michael@0 | 1331 | pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid); |
michael@0 | 1332 | if (pbeV2_param == NULL) { |
michael@0 | 1333 | return NULL; |
michael@0 | 1334 | } |
michael@0 | 1335 | cipherMech = PK11_AlgtagToMechanism( |
michael@0 | 1336 | SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId)); |
michael@0 | 1337 | pbeAlg = SECOID_GetAlgorithmTag(&pbeV2_param->pbeAlgId); |
michael@0 | 1338 | param = PK11_ParamFromAlgid(&pbeV2_param->pbeAlgId); |
michael@0 | 1339 | sec_pkcs5_v2_destroy_v2_param(pbeV2_param); |
michael@0 | 1340 | keyLen = SEC_PKCS5GetKeyLength(algid); |
michael@0 | 1341 | if (keyLen == -1) { |
michael@0 | 1342 | keyLen = 0; |
michael@0 | 1343 | } |
michael@0 | 1344 | keyType = PK11_GetKeyType(cipherMech, keyLen); |
michael@0 | 1345 | } else { |
michael@0 | 1346 | param = PK11_ParamFromAlgid(algid); |
michael@0 | 1347 | } |
michael@0 | 1348 | |
michael@0 | 1349 | if(param == NULL) { |
michael@0 | 1350 | goto loser; |
michael@0 | 1351 | } |
michael@0 | 1352 | |
michael@0 | 1353 | type = PK11_AlgtagToMechanism(pbeAlg); |
michael@0 | 1354 | if (type == CKM_INVALID_MECHANISM) { |
michael@0 | 1355 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
michael@0 | 1356 | goto loser; |
michael@0 | 1357 | } |
michael@0 | 1358 | if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) { |
michael@0 | 1359 | type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC; |
michael@0 | 1360 | } |
michael@0 | 1361 | symKey = pk11_RawPBEKeyGenWithKeyType(slot, type, param, keyType, keyLen, |
michael@0 | 1362 | pwitem, wincx); |
michael@0 | 1363 | |
michael@0 | 1364 | loser: |
michael@0 | 1365 | if (param) { |
michael@0 | 1366 | SECITEM_ZfreeItem(param, PR_TRUE); |
michael@0 | 1367 | } |
michael@0 | 1368 | return symKey; |
michael@0 | 1369 | } |
michael@0 | 1370 | |
michael@0 | 1371 | /* |
michael@0 | 1372 | * public, supports pkcs5v2 |
michael@0 | 1373 | */ |
michael@0 | 1374 | SECItem * |
michael@0 | 1375 | PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem) |
michael@0 | 1376 | { |
michael@0 | 1377 | return SEC_PKCS5GetIV(algid, pwitem, PR_FALSE); |
michael@0 | 1378 | } |
michael@0 | 1379 | |
michael@0 | 1380 | CK_MECHANISM_TYPE |
michael@0 | 1381 | pk11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param, |
michael@0 | 1382 | SECItem *pbe_pwd, PRBool faulty3DES) |
michael@0 | 1383 | { |
michael@0 | 1384 | int keyLen = 0; |
michael@0 | 1385 | SECOidTag algTag = SEC_PKCS5GetCryptoAlgorithm(algid); |
michael@0 | 1386 | CK_MECHANISM_TYPE mech = PK11_AlgtagToMechanism(algTag); |
michael@0 | 1387 | CK_MECHANISM_TYPE returnedMechanism = CKM_INVALID_MECHANISM; |
michael@0 | 1388 | SECItem *iv = NULL; |
michael@0 | 1389 | |
michael@0 | 1390 | if (mech == CKM_INVALID_MECHANISM) { |
michael@0 | 1391 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
michael@0 | 1392 | goto loser; |
michael@0 | 1393 | } |
michael@0 | 1394 | if (PK11_GetIVLength(mech)) { |
michael@0 | 1395 | iv = SEC_PKCS5GetIV(algid, pbe_pwd, faulty3DES); |
michael@0 | 1396 | if (iv == NULL) { |
michael@0 | 1397 | goto loser; |
michael@0 | 1398 | } |
michael@0 | 1399 | } |
michael@0 | 1400 | |
michael@0 | 1401 | keyLen = SEC_PKCS5GetKeyLength(algid); |
michael@0 | 1402 | |
michael@0 | 1403 | *param = pk11_ParamFromIVWithLen(mech, iv, keyLen); |
michael@0 | 1404 | if (*param == NULL) { |
michael@0 | 1405 | goto loser; |
michael@0 | 1406 | } |
michael@0 | 1407 | returnedMechanism = mech; |
michael@0 | 1408 | |
michael@0 | 1409 | loser: |
michael@0 | 1410 | if (iv) { |
michael@0 | 1411 | SECITEM_FreeItem(iv,PR_TRUE); |
michael@0 | 1412 | } |
michael@0 | 1413 | return returnedMechanism; |
michael@0 | 1414 | } |
michael@0 | 1415 | |
michael@0 | 1416 | /* |
michael@0 | 1417 | * Public, supports pkcs5 v2 |
michael@0 | 1418 | * |
michael@0 | 1419 | * Get the crypto mechanism directly from the pbe algorithmid. |
michael@0 | 1420 | * |
michael@0 | 1421 | * It's important to go directly from the algorithm id so that we can |
michael@0 | 1422 | * handle both the PKCS #5 v1, PKCS #12, and PKCS #5 v2 cases. |
michael@0 | 1423 | * |
michael@0 | 1424 | * This function returns both the mechanism and the parameter for the mechanism. |
michael@0 | 1425 | * The caller is responsible for freeing the parameter. |
michael@0 | 1426 | */ |
michael@0 | 1427 | CK_MECHANISM_TYPE |
michael@0 | 1428 | PK11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param, |
michael@0 | 1429 | SECItem *pbe_pwd) |
michael@0 | 1430 | { |
michael@0 | 1431 | return pk11_GetPBECryptoMechanism(algid, param, pbe_pwd, PR_FALSE); |
michael@0 | 1432 | } |