From 3d63b3966fc2d6913ba859e9a24c4d3a23387234 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 25 Nov 2009 22:01:06 +0000 Subject: [PATCH] Split PBES2 into cipher and PBKDF2 versions. This tidies the code somewhat and is a pre-requisite to adding password based CMS support. --- CHANGES | 22 ++++--- crypto/asn1/asn1.h | 1 + crypto/asn1/asn1_err.c | 1 + crypto/asn1/p5_pbev2.c | 140 ++++++++++++++++++++++++++--------------- crypto/evp/evp.h | 1 + crypto/evp/evp_err.c | 1 + crypto/evp/evp_locl.h | 4 ++ crypto/evp/evp_pbe.c | 5 ++ crypto/evp/p5_crpt2.c | 81 +++++++++++++----------- 9 files changed, 165 insertions(+), 91 deletions(-) diff --git a/CHANGES b/CHANGES index 46803f33d8..3b5d9ded48 100644 --- a/CHANGES +++ b/CHANGES @@ -2,14 +2,12 @@ OpenSSL CHANGES _______________ - Changes between 0.9.8l and 1.0 [xx XXX xxxx] + Changes between 1.0 and 1.1 [xx XXX xxxx] - *) Add load_crls() function to apps tidying load_certs() too. Add option - to verify utility to allow additional CRLs to be included. - [Steve Henson] - - *) Update OCSP request code to permit adding custom headers to the request: - some responders need this. + *) Split password based encryption into PBES2 and PBKDF2 functions. This + neatly separates the code into cipher and PBE sections and is required + for some algorithms that split PBES2 into separate pieces (such as + password based CMS). [Steve Henson] *) Extensive audit of libcrypto with DEBUG_UNUSED. Fix many cases where @@ -25,6 +23,16 @@ whose return value is often ignored. [Steve Henson] + Changes between 0.9.8l and 1.0 [xx XXX xxxx] + + *) Add load_crls() function to apps tidying load_certs() too. Add option + to verify utility to allow additional CRLs to be included. + [Steve Henson] + + *) Update OCSP request code to permit adding custom headers to the request: + some responders need this. + [Steve Henson] + *) The function EVP_PKEY_sign() returns <=0 on error: check return code correctly. [Julia Lawall ] diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index f7718b5a94..4f9f7f605f 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -1266,6 +1266,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_PKCS5_PBE2_SET_IV 167 #define ASN1_F_PKCS5_PBE_SET 202 #define ASN1_F_PKCS5_PBE_SET0_ALGOR 215 +#define ASN1_F_PKCS5_PBKDF2_SET 219 #define ASN1_F_SMIME_READ_ASN1 212 #define ASN1_F_SMIME_TEXT 213 #define ASN1_F_X509_CINF_NEW 168 diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 6e04d08f31..570ec38f7a 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -179,6 +179,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_FUNC(ASN1_F_PKCS5_PBE2_SET_IV), "PKCS5_pbe2_set_iv"}, {ERR_FUNC(ASN1_F_PKCS5_PBE_SET), "PKCS5_pbe_set"}, {ERR_FUNC(ASN1_F_PKCS5_PBE_SET0_ALGOR), "PKCS5_pbe_set0_algor"}, +{ERR_FUNC(ASN1_F_PKCS5_PBKDF2_SET), "PKCS5_pbkdf2_set"}, {ERR_FUNC(ASN1_F_SMIME_READ_ASN1), "SMIME_read_ASN1"}, {ERR_FUNC(ASN1_F_SMIME_TEXT), "SMIME_text"}, {ERR_FUNC(ASN1_F_X509_CINF_NEW), "X509_CINF_NEW"}, diff --git a/crypto/asn1/p5_pbev2.c b/crypto/asn1/p5_pbev2.c index 377edaffc9..b053a6efc0 100644 --- a/crypto/asn1/p5_pbev2.c +++ b/crypto/asn1/p5_pbev2.c @@ -91,12 +91,10 @@ X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, unsigned char *aiv, int prf_nid) { X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL; - int alg_nid; + int alg_nid, keylen; EVP_CIPHER_CTX ctx; unsigned char iv[EVP_MAX_IV_LENGTH]; - PBKDF2PARAM *kdf = NULL; PBE2PARAM *pbe2 = NULL; - ASN1_OCTET_STRING *osalt = NULL; ASN1_OBJECT *obj; alg_nid = EVP_CIPHER_type(cipher); @@ -146,55 +144,19 @@ X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, } EVP_CIPHER_CTX_cleanup(&ctx); - if(!(kdf = PBKDF2PARAM_new())) goto merr; - if(!(osalt = M_ASN1_OCTET_STRING_new())) goto merr; - - if (!saltlen) saltlen = PKCS5_SALT_LEN; - if (!(osalt->data = OPENSSL_malloc (saltlen))) goto merr; - osalt->length = saltlen; - if (salt) memcpy (osalt->data, salt, saltlen); - else if (RAND_pseudo_bytes (osalt->data, saltlen) < 0) goto merr; - - if(iter <= 0) iter = PKCS5_DEFAULT_ITER; - if(!ASN1_INTEGER_set(kdf->iter, iter)) goto merr; - - /* Now include salt in kdf structure */ - kdf->salt->value.octet_string = osalt; - kdf->salt->type = V_ASN1_OCTET_STRING; - osalt = NULL; - /* If its RC2 then we'd better setup the key length */ - if(alg_nid == NID_rc2_cbc) { - if(!(kdf->keylength = M_ASN1_INTEGER_new())) goto merr; - if(!ASN1_INTEGER_set (kdf->keylength, - EVP_CIPHER_key_length(cipher))) goto merr; - } - - /* prf can stay NULL if we are using hmacWithSHA1 */ - if (prf_nid != NID_hmacWithSHA1) - { - kdf->prf = X509_ALGOR_new(); - if (!kdf->prf) - goto merr; - X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid), - V_ASN1_NULL, NULL); - } - - /* Now setup the PBE2PARAM keyfunc structure */ + if(alg_nid == NID_rc2_cbc) + keylen = EVP_CIPHER_key_length(cipher); + else + keylen = -1; - pbe2->keyfunc->algorithm = OBJ_nid2obj(NID_id_pbkdf2); + /* Setup keyfunc */ - /* Encode PBKDF2PARAM into parameter of pbe2 */ + pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen); - if(!(pbe2->keyfunc->parameter = ASN1_TYPE_new())) goto merr; - - if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM), - &pbe2->keyfunc->parameter->value.sequence)) goto merr; - pbe2->keyfunc->parameter->type = V_ASN1_SEQUENCE; - - PBKDF2PARAM_free(kdf); - kdf = NULL; + if (!pbe2->keyfunc) + goto merr; /* Now set up top level AlgorithmIdentifier */ @@ -220,8 +182,6 @@ X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, err: PBE2PARAM_free(pbe2); /* Note 'scheme' is freed as part of pbe2 */ - M_ASN1_OCTET_STRING_free(osalt); - PBKDF2PARAM_free(kdf); X509_ALGOR_free(kalg); X509_ALGOR_free(ret); @@ -234,3 +194,85 @@ X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, { return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1); } + +X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, + int prf_nid, int keylen) + { + X509_ALGOR *keyfunc = NULL; + PBKDF2PARAM *kdf = NULL; + ASN1_OCTET_STRING *osalt = NULL; + + if(!(kdf = PBKDF2PARAM_new())) + goto merr; + if(!(osalt = M_ASN1_OCTET_STRING_new())) + goto merr; + + kdf->salt->value.octet_string = osalt; + kdf->salt->type = V_ASN1_OCTET_STRING; + + if (!saltlen) + saltlen = PKCS5_SALT_LEN; + if (!(osalt->data = OPENSSL_malloc (saltlen))) + goto merr; + + osalt->length = saltlen; + + if (salt) + memcpy (osalt->data, salt, saltlen); + else if (RAND_pseudo_bytes (osalt->data, saltlen) < 0) + goto merr; + + if(iter <= 0) + iter = PKCS5_DEFAULT_ITER; + + if(!ASN1_INTEGER_set(kdf->iter, iter)) + goto merr; + + /* If have a key len set it up */ + + if(keylen > 0) + { + if(!(kdf->keylength = M_ASN1_INTEGER_new())) + goto merr; + if(!ASN1_INTEGER_set (kdf->keylength, keylen)) + goto merr; + } + + /* prf can stay NULL if we are using hmacWithSHA1 */ + if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1) + { + kdf->prf = X509_ALGOR_new(); + if (!kdf->prf) + goto merr; + X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid), + V_ASN1_NULL, NULL); + } + + /* Finally setup the keyfunc structure */ + + keyfunc = X509_ALGOR_new(); + if (!keyfunc) + goto merr; + + keyfunc->algorithm = OBJ_nid2obj(NID_id_pbkdf2); + + /* Encode PBKDF2PARAM into parameter of pbe2 */ + + if(!(keyfunc->parameter = ASN1_TYPE_new())) + goto merr; + + if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM), + &keyfunc->parameter->value.sequence)) + goto merr; + keyfunc->parameter->type = V_ASN1_SEQUENCE; + + PBKDF2PARAM_free(kdf); + return keyfunc; + + merr: + ASN1err(ASN1_F_PKCS5_PBKDF2_SET,ERR_R_MALLOC_FAILURE); + PBKDF2PARAM_free(kdf); + X509_ALGOR_free(keyfunc); + return NULL; + } + diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index cac090ebe4..b8aa8b3ce2 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -1236,6 +1236,7 @@ void ERR_load_EVP_strings(void); #define EVP_F_INT_CTX_NEW 157 #define EVP_F_PKCS5_PBE_KEYIVGEN 117 #define EVP_F_PKCS5_V2_PBE_KEYIVGEN 118 +#define EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN 164 #define EVP_F_PKCS8_SET_BROKEN 112 #define EVP_F_PKEY_SET_TYPE 158 #define EVP_F_RC2_MAGIC_TO_METH 109 diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index 49ddbcf630..b8b2557951 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -129,6 +129,7 @@ static ERR_STRING_DATA EVP_str_functs[]= {ERR_FUNC(EVP_F_INT_CTX_NEW), "INT_CTX_NEW"}, {ERR_FUNC(EVP_F_PKCS5_PBE_KEYIVGEN), "PKCS5_PBE_keyivgen"}, {ERR_FUNC(EVP_F_PKCS5_V2_PBE_KEYIVGEN), "PKCS5_v2_PBE_keyivgen"}, +{ERR_FUNC(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN), "PKCS5_V2_PBKDF2_KEYIVGEN"}, {ERR_FUNC(EVP_F_PKCS8_SET_BROKEN), "PKCS8_set_broken"}, {ERR_FUNC(EVP_F_PKEY_SET_TYPE), "PKEY_SET_TYPE"}, {ERR_FUNC(EVP_F_RC2_MAGIC_TO_METH), "RC2_MAGIC_TO_METH"}, diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index 34e4a65af6..4cb80fbde0 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -343,3 +343,7 @@ struct evp_pkey_method_st } /* EVP_PKEY_METHOD */; void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx); + +int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, + const EVP_CIPHER *c, const EVP_MD *md, int en_de); diff --git a/crypto/evp/evp_pbe.c b/crypto/evp/evp_pbe.c index cd6e40dcaa..92bd7ca066 100644 --- a/crypto/evp/evp_pbe.c +++ b/crypto/evp/evp_pbe.c @@ -61,6 +61,7 @@ #include #include #include +#include "evp_locl.h" /* Password based encryption (PBE) functions */ @@ -87,6 +88,10 @@ static const EVP_PBE_CTL builtin_pbe[] = {EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndRC2_CBC, NID_rc2_64_cbc, NID_sha1, PKCS5_PBE_keyivgen}, +#ifndef OPENSSL_NO_HMAC + {EVP_PBE_TYPE_OUTER, NID_id_pbkdf2, -1, -1, PKCS5_v2_PBKDF2_keyivgen}, +#endif + {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And128BitRC4, NID_rc4, NID_sha1, PKCS12_PBE_keyivgen}, {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And40BitRC4, diff --git a/crypto/evp/p5_crpt2.c b/crypto/evp/p5_crpt2.c index 01b6b50cf7..176e93eabc 100644 --- a/crypto/evp/p5_crpt2.c +++ b/crypto/evp/p5_crpt2.c @@ -62,6 +62,7 @@ #include #include #include +#include "evp_locl.h" /* set this to print out info about the keygen algorithm */ /* #define DEBUG_PKCS5V2 */ @@ -172,27 +173,24 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *c, const EVP_MD *md, int en_de) { - unsigned char *salt, key[EVP_MAX_KEY_LENGTH]; const unsigned char *pbuf; - int saltlen, iter, plen; - unsigned int keylen; + int plen; PBE2PARAM *pbe2 = NULL; const EVP_CIPHER *cipher; - PBKDF2PARAM *kdf = NULL; - const EVP_MD *prfmd; - int prf_nid, hmac_md_nid; + + int rv = 0; if (param == NULL || param->type != V_ASN1_SEQUENCE || param->value.sequence == NULL) { EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); - return 0; + goto err; } pbuf = param->value.sequence->data; plen = param->value.sequence->length; if(!(pbe2 = d2i_PBE2PARAM(NULL, &pbuf, plen))) { EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); - return 0; + goto err; } /* See if we recognise the key derivation function */ @@ -216,41 +214,62 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, /* Fixup cipher based on AlgorithmIdentifier */ if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de)) - { - EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, ERR_R_EVP_LIB); goto err; - } if(EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) { EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_CIPHER_PARAMETER_ERROR); goto err; } + rv = PKCS5_v2_PBKDF2_keyivgen(ctx, pass, passlen, + pbe2->keyfunc->parameter, c, md, en_de); + err: + PBE2PARAM_free(pbe2); + return rv; +} + +int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, + const EVP_CIPHER *c, const EVP_MD *md, int en_de) +{ + unsigned char *salt, key[EVP_MAX_KEY_LENGTH]; + const unsigned char *pbuf; + int saltlen, iter, plen; + int rv = 0; + unsigned int keylen; + int prf_nid, hmac_md_nid; + PBKDF2PARAM *kdf = NULL; + const EVP_MD *prfmd; + + if (EVP_CIPHER_CTX_cipher(ctx) == NULL) + { + EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,EVP_R_NO_CIPHER_SET); + goto err; + } keylen = EVP_CIPHER_CTX_key_length(ctx); OPENSSL_assert(keylen <= sizeof key); - /* Now decode key derivation function */ + /* Decode parameter */ - if(!pbe2->keyfunc->parameter || - (pbe2->keyfunc->parameter->type != V_ASN1_SEQUENCE)) + if(!param || (param->type != V_ASN1_SEQUENCE)) { - EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); + EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,EVP_R_DECODE_ERROR); goto err; } - pbuf = pbe2->keyfunc->parameter->value.sequence->data; - plen = pbe2->keyfunc->parameter->value.sequence->length; + pbuf = param->value.sequence->data; + plen = param->value.sequence->length; + if(!(kdf = d2i_PBKDF2PARAM(NULL, &pbuf, plen)) ) { - EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); + EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,EVP_R_DECODE_ERROR); goto err; } - PBE2PARAM_free(pbe2); - pbe2 = NULL; + keylen = EVP_CIPHER_CTX_key_length(ctx); /* Now check the parameters of the kdf */ if(kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)){ - EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, + EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_KEYLENGTH); goto err; } @@ -262,19 +281,19 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, 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); + EVPerr(EVP_F_PKCS5_V2_PBKDF2_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); + EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); goto err; } if(kdf->salt->type != V_ASN1_OCTET_STRING) { - EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, + EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_SALT_TYPE); goto err; } @@ -286,19 +305,11 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, if(!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd, keylen, key)) goto err; - if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de)) - { - EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, ERR_R_EVP_LIB); - goto err; - } - OPENSSL_cleanse(key, keylen); - PBKDF2PARAM_free(kdf); - return 1; - + rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de); err: - PBE2PARAM_free(pbe2); + OPENSSL_cleanse(key, keylen); PBKDF2PARAM_free(kdf); - return 0; + return rv; } #ifdef DEBUG_PKCS5V2 -- GitLab