From: Dr. Stephen Henson Date: Sun, 14 May 2006 18:40:53 +0000 (+0000) Subject: Extend PBE code to support non default PKCS#5 v2.0 PRFs. X-Git-Tag: OpenSSL_0_9_8k^2~1329 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=856640b54f3d22a34d6565e9c78c441a15222577 Extend PBE code to support non default PKCS#5 v2.0 PRFs. --- diff --git a/CHANGES b/CHANGES index 366a8c90f1..412c9fd371 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Changes between 0.9.8b and 0.9.9 [xx XXX xxxx] + *) Initial support for PKCS#5 v2.0 PRFs other than default SHA1 HMAC. + [Steve Henson] + *) Replace the algorithm specific calls to generate keys in "req" with the new API. [Steve Henson] diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index 73f211e4d3..db33634e47 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -799,8 +799,20 @@ void PKCS5_PBE_add(void); int EVP_PBE_CipherInit (ASN1_OBJECT *pbe_obj, const char *pass, int passlen, ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de); + +/* PBE type */ + +/* Can appear as the outermost AlgorithmIdentifier */ +#define EVP_PBE_TYPE_OUTER 0x0 +/* Is an PRF type OID */ +#define EVP_PBE_TYPE_PRF 0x1 + +int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid, int md_nid, + EVP_PBE_KEYGEN *keygen); int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md, EVP_PBE_KEYGEN *keygen); +int EVP_PBE_find(int type, int pbe_nid, + int *pcnid, int *pmnid, EVP_PBE_KEYGEN **pkeygen); void EVP_PBE_cleanup(void); #define ASN1_PKEY_ALIAS 0x1 diff --git a/crypto/evp/evp_pbe.c b/crypto/evp/evp_pbe.c index c26d2de0f3..c634e1b643 100644 --- a/crypto/evp/evp_pbe.c +++ b/crypto/evp/evp_pbe.c @@ -3,7 +3,7 @@ * project 1999. */ /* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -67,71 +67,135 @@ static STACK *pbe_algs; /* Setup a cipher context from a PBE algorithm */ -typedef struct { -int pbe_nid; -const EVP_CIPHER *cipher; -const EVP_MD *md; -EVP_PBE_KEYGEN *keygen; -} EVP_PBE_CTL; +typedef struct + { + int pbe_type; + int pbe_nid; + int cipher_nid; + int md_nid; + EVP_PBE_KEYGEN *keygen; + } EVP_PBE_CTL; int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen, ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de) -{ + { + const EVP_CIPHER *cipher; + const EVP_MD *md; + int cipher_nid, md_nid; + EVP_PBE_KEYGEN *keygen; - EVP_PBE_CTL *pbetmp, pbelu; - int i; - pbelu.pbe_nid = OBJ_obj2nid(pbe_obj); - if (pbelu.pbe_nid != NID_undef) i = sk_find(pbe_algs, (char *)&pbelu); - else i = -1; - - if (i == -1) { + if (!EVP_PBE_find(EVP_PBE_TYPE_OUTER, OBJ_obj2nid(pbe_obj), + &cipher_nid, &md_nid, &keygen)) + { char obj_tmp[80]; EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_PBE_ALGORITHM); if (!pbe_obj) BUF_strlcpy (obj_tmp, "NULL", sizeof obj_tmp); else i2t_ASN1_OBJECT(obj_tmp, sizeof obj_tmp, pbe_obj); ERR_add_error_data(2, "TYPE=", obj_tmp); return 0; - } - if(!pass) passlen = 0; - else if (passlen == -1) passlen = strlen(pass); - pbetmp = (EVP_PBE_CTL *)sk_value (pbe_algs, i); - i = (*pbetmp->keygen)(ctx, pass, passlen, param, pbetmp->cipher, - pbetmp->md, en_de); - if (!i) { + } + + if(!pass) + passlen = 0; + else if (passlen == -1) + passlen = strlen(pass); + + if (cipher_nid == -1) + cipher = NULL; + else + cipher = EVP_get_cipherbynid(cipher_nid); + + if (md_nid == -1) + md = NULL; + else + md = EVP_get_digestbynid(md_nid); + + if (!keygen(ctx, pass, passlen, param, cipher, md, en_de)) + { EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_KEYGEN_FAILURE); return 0; - } + } return 1; } static int pbe_cmp(const char * const *a, const char * const *b) -{ + { const EVP_PBE_CTL * const *pbe1 = (const EVP_PBE_CTL * const *) a, * const *pbe2 = (const EVP_PBE_CTL * const *)b; - return ((*pbe1)->pbe_nid - (*pbe2)->pbe_nid); -} + int ret = (*pbe1)->pbe_type - (*pbe2)->pbe_type; + if (ret) + return ret; + else + return (*pbe1)->pbe_nid - (*pbe2)->pbe_nid; + } /* Add a PBE algorithm */ -int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md, +int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid, int md_nid, EVP_PBE_KEYGEN *keygen) -{ + { EVP_PBE_CTL *pbe_tmp; - if (!pbe_algs) pbe_algs = sk_new(pbe_cmp); - if (!(pbe_tmp = (EVP_PBE_CTL*) OPENSSL_malloc (sizeof(EVP_PBE_CTL)))) { + if (!pbe_algs) + pbe_algs = sk_new(pbe_cmp); + if (!(pbe_tmp = (EVP_PBE_CTL*) OPENSSL_malloc (sizeof(EVP_PBE_CTL)))) + { EVPerr(EVP_F_EVP_PBE_ALG_ADD,ERR_R_MALLOC_FAILURE); return 0; - } - pbe_tmp->pbe_nid = nid; - pbe_tmp->cipher = cipher; - pbe_tmp->md = md; + } + pbe_tmp->pbe_type = pbe_type; + pbe_tmp->pbe_nid = pbe_nid; + pbe_tmp->cipher_nid = cipher_nid; + pbe_tmp->md_nid = md_nid; pbe_tmp->keygen = keygen; + + sk_push (pbe_algs, (char *)pbe_tmp); return 1; -} + } + +int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md, + EVP_PBE_KEYGEN *keygen) + { + int cipher_nid, md_nid; + if (cipher) + cipher_nid = EVP_CIPHER_type(cipher); + else + cipher_nid = -1; + if (md) + md_nid = EVP_MD_type(md); + else + md_nid = -1; + + return EVP_PBE_alg_add_type(EVP_PBE_TYPE_OUTER, nid, + cipher_nid, md_nid, keygen); + } + +int EVP_PBE_find(int type, int pbe_nid, + int *pcnid, int *pmnid, EVP_PBE_KEYGEN **pkeygen) + { + EVP_PBE_CTL *pbetmp, pbelu; + int i; + if (pbe_nid == NID_undef) + return 0; + pbelu.pbe_type = type; + pbelu.pbe_nid = pbe_nid; + i = sk_find(pbe_algs, (char *)&pbelu); + if (i == -1) + return 0; + pbetmp = (EVP_PBE_CTL *)sk_value (pbe_algs, i); + if (pcnid) + *pcnid = pbetmp->cipher_nid; + if (pmnid) + *pmnid = pbetmp->md_nid; + if (pkeygen) + *pkeygen = pbetmp->keygen; + return 1; + } + + void EVP_PBE_cleanup(void) -{ + { sk_pop_free(pbe_algs, OPENSSL_freeFunc); pbe_algs = NULL; -} + } diff --git a/crypto/evp/p5_crpt.c b/crypto/evp/p5_crpt.c index 48d50014a0..185a153601 100644 --- a/crypto/evp/p5_crpt.c +++ b/crypto/evp/p5_crpt.c @@ -97,6 +97,7 @@ EVP_PBE_alg_add(NID_pbeWithSHA1AndRC2_CBC, EVP_rc2_64_cbc(), EVP_sha1(), #endif #ifndef OPENSSL_NO_HMAC EVP_PBE_alg_add(NID_pbes2, NULL, NULL, PKCS5_v2_PBE_keyivgen); +EVP_PBE_alg_add_type(EVP_PBE_TYPE_PRF, NID_hmacWithSHA1, -1, NID_sha1, 0); #endif } diff --git a/crypto/evp/p5_crpt2.c b/crypto/evp/p5_crpt2.c index c969d5a206..94189ff9f7 100644 --- a/crypto/evp/p5_crpt2.c +++ b/crypto/evp/p5_crpt2.c @@ -3,7 +3,7 @@ * project 1999. */ /* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -71,28 +71,36 @@ #endif /* This is an implementation of PKCS#5 v2.0 password based encryption key - * derivation function PBKDF2 using the only currently defined function HMAC - * with SHA1. Verified against test vectors posted by Peter Gutmann + * derivation function PBKDF2. + * SHA1 version verified against test vectors posted by Peter Gutmann * to the PKCS-TNG mailing list. */ -int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, +int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, + const EVP_MD *digest, int keylen, unsigned char *out) -{ - unsigned char digtmp[SHA_DIGEST_LENGTH], *p, itmp[4]; - int cplen, j, k, tkeylen; + { + unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4]; + int cplen, j, k, tkeylen, mdlen; unsigned long i = 1; HMAC_CTX hctx; + mdlen = EVP_MD_size(digest); + HMAC_CTX_init(&hctx); p = out; tkeylen = keylen; - if(!pass) passlen = 0; - else if(passlen == -1) passlen = strlen(pass); - while(tkeylen) { - if(tkeylen > SHA_DIGEST_LENGTH) cplen = SHA_DIGEST_LENGTH; - else cplen = tkeylen; + if(!pass) + passlen = 0; + else if(passlen == -1) + passlen = strlen(pass); + while(tkeylen) + { + if(tkeylen > mdlen) + cplen = mdlen; + else + cplen = tkeylen; /* We are unlikely to ever use more than 256 blocks (5120 bits!) * but just in case... */ @@ -100,20 +108,22 @@ int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, itmp[1] = (unsigned char)((i >> 16) & 0xff); itmp[2] = (unsigned char)((i >> 8) & 0xff); itmp[3] = (unsigned char)(i & 0xff); - HMAC_Init_ex(&hctx, pass, passlen, EVP_sha1(), NULL); + HMAC_Init_ex(&hctx, pass, passlen, digest, NULL); HMAC_Update(&hctx, salt, saltlen); HMAC_Update(&hctx, itmp, 4); HMAC_Final(&hctx, digtmp, NULL); memcpy(p, digtmp, cplen); - for(j = 1; j < iter; j++) { - HMAC(EVP_sha1(), pass, passlen, - digtmp, SHA_DIGEST_LENGTH, digtmp, NULL); - for(k = 0; k < cplen; k++) p[k] ^= digtmp[k]; - } + for(j = 1; j < iter; j++) + { + HMAC(digest, pass, passlen, + digtmp, mdlen, digtmp, NULL); + for(k = 0; k < cplen; k++) + p[k] ^= digtmp[k]; + } tkeylen-= cplen; i++; p+= cplen; - } + } HMAC_CTX_cleanup(&hctx); #ifdef DEBUG_PKCS5V2 fprintf(stderr, "Password:\n"); @@ -125,7 +135,15 @@ int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, h__dump (out, keylen); #endif return 1; -} + } + +int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + int keylen, unsigned char *out) + { + return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, EVP_sha1(), + keylen, out); + } #ifdef DO_TEST main() @@ -155,6 +173,8 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, PBE2PARAM *pbe2 = NULL; const EVP_CIPHER *cipher; PBKDF2PARAM *kdf = NULL; + const EVP_MD *prfmd; + int prf_nid, hmac_md_nid; if (param == NULL || param->type != V_ASN1_SEQUENCE || param->value.sequence == NULL) { @@ -226,10 +246,23 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, goto err; } - if(kdf->prf && (OBJ_obj2nid(kdf->prf->algorithm) != NID_hmacWithSHA1)) { + if (kdf->prf) + prf_nid = OBJ_obj2nid(kdf->prf->algorithm); + else + prf_nid = NID_hmacWithSHA1; + + if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0)) + { EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); goto err; - } + } + + prfmd = EVP_get_digestbynid(hmac_md_nid); + if (prfmd == NULL) + { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); + goto err; + } if(kdf->salt->type != V_ASN1_OCTET_STRING) { EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, @@ -241,7 +274,8 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, salt = kdf->salt->value.octet_string->data; saltlen = kdf->salt->value.octet_string->length; iter = ASN1_INTEGER_get(kdf->iter); - PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, salt, saltlen, iter, keylen, key); + PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd, + keylen, key); EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de); OPENSSL_cleanse(key, keylen); PBKDF2PARAM_free(kdf); diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h index b10d85df4b..48bcb25248 100644 --- a/crypto/objects/obj_dat.h +++ b/crypto/objects/obj_dat.h @@ -62,12 +62,12 @@ * [including the GNU Public Licence.] */ -#define NUM_NID 802 -#define NUM_SN 798 -#define NUM_LN 798 -#define NUM_OBJ 760 +#define NUM_NID 803 +#define NUM_SN 799 +#define NUM_LN 799 +#define NUM_OBJ 761 -static unsigned char lvalues[5345]={ +static unsigned char lvalues[5353]={ 0x00, /* [ 0] OBJ_undef */ 0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 1] OBJ_rsadsi */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, /* [ 7] OBJ_pkcs */ @@ -828,6 +828,7 @@ static unsigned char lvalues[5345]={ 0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x03, /* [5320] OBJ_id_GostR3411_94_with_GostR3410_94_cc */ 0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x04, /* [5328] OBJ_id_GostR3411_94_with_GostR3410_2001_cc */ 0x2A,0x85,0x03,0x02,0x09,0x01,0x08,0x01, /* [5336] OBJ_id_GostR3410_2001_ParamSet_cc */ +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x06, /* [5344] OBJ_hmacWithMD5 */ }; static ASN1_OBJECT nid_objs[NUM_NID]={ @@ -2122,6 +2123,7 @@ static ASN1_OBJECT nid_objs[NUM_NID]={ {"id-GostR3410-2001-ParamSet-cc", "GOST R 3410-2001 Parameter Set Cryptocom", NID_id_GostR3410_2001_ParamSet_cc,8,&(lvalues[5336]),0}, +{"hmacWithMD5","hmacWithMD5",NID_hmacWithMD5,8,&(lvalues[5344]),0}, }; static ASN1_OBJECT *sn_objs[NUM_SN]={ @@ -2372,6 +2374,7 @@ static ASN1_OBJECT *sn_objs[NUM_SN]={ &(nid_objs[784]),/* "gost89" */ &(nid_objs[757]),/* "gost94" */ &(nid_objs[797]),/* "gost94cc" */ +&(nid_objs[802]),/* "hmacWithMD5" */ &(nid_objs[163]),/* "hmacWithSHA1" */ &(nid_objs[432]),/* "holdInstructionCallIssuer" */ &(nid_objs[430]),/* "holdInstructionCode" */ @@ -3186,6 +3189,7 @@ static ASN1_OBJECT *ln_objs[NUM_LN]={ &(nid_objs[509]),/* "generationQualifier" */ &(nid_objs[601]),/* "generic cryptogram" */ &(nid_objs[99]),/* "givenName" */ +&(nid_objs[802]),/* "hmacWithMD5" */ &(nid_objs[163]),/* "hmacWithSHA1" */ &(nid_objs[486]),/* "homePostalAddress" */ &(nid_objs[473]),/* "homeTelephoneNumber" */ @@ -4094,6 +4098,7 @@ static ASN1_OBJECT *obj_objs[NUM_OBJ]={ &(nid_objs[ 3]),/* OBJ_md2 1 2 840 113549 2 2 */ &(nid_objs[257]),/* OBJ_md4 1 2 840 113549 2 4 */ &(nid_objs[ 4]),/* OBJ_md5 1 2 840 113549 2 5 */ +&(nid_objs[802]),/* OBJ_hmacWithMD5 1 2 840 113549 2 6 */ &(nid_objs[163]),/* OBJ_hmacWithSHA1 1 2 840 113549 2 7 */ &(nid_objs[37]),/* OBJ_rc2_cbc 1 2 840 113549 3 2 */ &(nid_objs[ 5]),/* OBJ_rc4 1 2 840 113549 3 4 */ diff --git a/crypto/objects/obj_mac.h b/crypto/objects/obj_mac.h index 44c2166a34..93ca25323b 100644 --- a/crypto/objects/obj_mac.h +++ b/crypto/objects/obj_mac.h @@ -1075,6 +1075,10 @@ #define LN_md5_sha1 "md5-sha1" #define NID_md5_sha1 114 +#define LN_hmacWithMD5 "hmacWithMD5" +#define NID_hmacWithMD5 802 +#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L + #define LN_hmacWithSHA1 "hmacWithSHA1" #define NID_hmacWithSHA1 163 #define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num index e9e79fffc0..64224881c8 100644 --- a/crypto/objects/obj_mac.num +++ b/crypto/objects/obj_mac.num @@ -799,3 +799,4 @@ id_GostR3410_2001_cc 798 id_GostR3411_94_with_GostR3410_94_cc 799 id_GostR3411_94_with_GostR3410_2001_cc 800 id_GostR3410_2001_ParamSet_cc 801 +hmacWithMD5 802 diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt index 62c5bbe4ac..0aef7edd57 100644 --- a/crypto/objects/objects.txt +++ b/crypto/objects/objects.txt @@ -338,6 +338,7 @@ rsadsi 2 2 : MD2 : md2 rsadsi 2 4 : MD4 : md4 rsadsi 2 5 : MD5 : md5 : MD5-SHA1 : md5-sha1 +rsadsi 2 6 : : hmacWithMD5 rsadsi 2 7 : : hmacWithSHA1 rsadsi 3 2 : RC2-CBC : rc2-cbc : RC2-ECB : rc2-ecb