From 8e21c14607173ae5b0ea04c5a24b36514f6887f1 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sun, 6 Jun 1999 23:34:44 +0000 Subject: [PATCH] More PKCS#5 v2.0 development. Add a function to setup a PKCS#5 v2.0 AlgorithmIdentifier and make various ASN1 fixes. --- crypto/asn1/asn1.h | 6 +- crypto/asn1/asn1_err.c | 2 + crypto/asn1/asn_pack.c | 4 +- crypto/asn1/p5_pbe.c | 20 +------ crypto/asn1/p5_pbev2.c | 119 +++++++++++++++++++++++++++++++++++++-- crypto/evp/evp.h | 2 + crypto/objects/obj_dat.h | 9 ++- crypto/objects/objects.h | 11 ++-- crypto/x509/x509.h | 4 +- 9 files changed, 141 insertions(+), 36 deletions(-) diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index 3de083984e..f55663e0f0 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -681,8 +681,8 @@ STACK *ASN1_seq_unpack(unsigned char *buf, int len, char *(*d2i)(), void (*free_func)() ); unsigned char *ASN1_seq_pack(STACK *safes, int (*i2d)(), unsigned char **buf, int *len ); -char *ASN1_unpack_string(ASN1_STRING *oct, char *(*d2i)()); -ASN1_STRING *ASN1_pack_string(char *obj, int (*i2d)(), ASN1_OCTET_STRING **oct); +void *ASN1_unpack_string(ASN1_STRING *oct, char *(*d2i)()); +ASN1_STRING *ASN1_pack_string(void *obj, int (*i2d)(), ASN1_OCTET_STRING **oct); /* BEGIN ERROR CODES */ /* The following lines are auto generated by the script mkerr.pl. Any changes @@ -836,6 +836,7 @@ ASN1_STRING *ASN1_pack_string(char *obj, int (*i2d)(), ASN1_OCTET_STRING **oct); #define ASN1_F_PKCS12_MAC_DATA_NEW 259 #define ASN1_F_PKCS12_NEW 260 #define ASN1_F_PKCS12_SAFEBAG_NEW 261 +#define ASN1_F_PKCS5_PBE2_SET 281 #define ASN1_F_PKCS7_DIGEST_NEW 192 #define ASN1_F_PKCS7_ENCRYPT_NEW 193 #define ASN1_F_PKCS7_ENC_CONTENT_NEW 194 @@ -890,6 +891,7 @@ ASN1_STRING *ASN1_pack_string(char *obj, int (*i2d)(), ASN1_OCTET_STRING **oct); #define ASN1_R_DECODING_ERROR 111 #define ASN1_R_ENCODE_ERROR 156 #define ASN1_R_ERROR_PARSING_SET_ELEMENT 112 +#define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 157 #define ASN1_R_EXPECTING_AN_ENUMERATED 154 #define ASN1_R_EXPECTING_AN_INTEGER 113 #define ASN1_R_EXPECTING_AN_OBJECT 114 diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index cc0431b994..900291fb6a 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -209,6 +209,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_PACK(0,ASN1_F_PKCS12_MAC_DATA_NEW,0), "PKCS12_MAC_DATA_new"}, {ERR_PACK(0,ASN1_F_PKCS12_NEW,0), "PKCS12_new"}, {ERR_PACK(0,ASN1_F_PKCS12_SAFEBAG_NEW,0), "PKCS12_SAFEBAG_new"}, +{ERR_PACK(0,ASN1_F_PKCS5_PBE2_SET,0), "PKCS5_PBE2_SET"}, {ERR_PACK(0,ASN1_F_PKCS7_DIGEST_NEW,0), "PKCS7_DIGEST_new"}, {ERR_PACK(0,ASN1_F_PKCS7_ENCRYPT_NEW,0), "PKCS7_ENCRYPT_new"}, {ERR_PACK(0,ASN1_F_PKCS7_ENC_CONTENT_NEW,0), "PKCS7_ENC_CONTENT_new"}, @@ -266,6 +267,7 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ASN1_R_DECODING_ERROR ,"decoding error"}, {ASN1_R_ENCODE_ERROR ,"encode error"}, {ASN1_R_ERROR_PARSING_SET_ELEMENT ,"error parsing set element"}, +{ASN1_R_ERROR_SETTING_CIPHER_PARAMS ,"error setting cipher params"}, {ASN1_R_EXPECTING_AN_ENUMERATED ,"expecting an enumerated"}, {ASN1_R_EXPECTING_AN_INTEGER ,"expecting an integer"}, {ASN1_R_EXPECTING_AN_OBJECT ,"expecting an object"}, diff --git a/crypto/asn1/asn_pack.c b/crypto/asn1/asn_pack.c index 4e846285a8..662a2626a1 100644 --- a/crypto/asn1/asn_pack.c +++ b/crypto/asn1/asn_pack.c @@ -104,7 +104,7 @@ unsigned char *ASN1_seq_pack(STACK *safes, int (*i2d)(), unsigned char **buf, /* Extract an ASN1 object from an ASN1_STRING */ -char *ASN1_unpack_string (ASN1_STRING *oct, char *(*d2i)()) +void *ASN1_unpack_string (ASN1_STRING *oct, char *(*d2i)()) { unsigned char *p; char *ret; @@ -117,7 +117,7 @@ char *ASN1_unpack_string (ASN1_STRING *oct, char *(*d2i)()) /* Pack an ASN1 object into an ASN1_STRING */ -ASN1_STRING *ASN1_pack_string (char *obj, int (*i2d)(), ASN1_STRING **oct) +ASN1_STRING *ASN1_pack_string (void *obj, int (*i2d)(), ASN1_STRING **oct) { unsigned char *p; ASN1_STRING *octmp; diff --git a/crypto/asn1/p5_pbe.c b/crypto/asn1/p5_pbe.c index c7a3ecf9fb..5145c6349e 100644 --- a/crypto/asn1/p5_pbe.c +++ b/crypto/asn1/p5_pbe.c @@ -63,8 +63,6 @@ /* PKCS#5 password based encryption structure */ -#define PKCS5_SALT_LEN 8 - int i2d_PBEPARAM(PBEPARAM *a, unsigned char **pp) { M_ASN1_I2D_vars(a); @@ -112,8 +110,6 @@ void PBEPARAM_free (PBEPARAM *a) X509_ALGOR *PKCS5_pbe_set(int alg, int iter, unsigned char *salt, int saltlen) { - unsigned char *pdata, *ptmp; - int plen; PBEPARAM *pbe; ASN1_OBJECT *al; X509_ALGOR *algor; @@ -132,17 +128,6 @@ X509_ALGOR *PKCS5_pbe_set(int alg, int iter, unsigned char *salt, pbe->salt->length = saltlen; if (salt) memcpy (pbe->salt->data, salt, saltlen); else RAND_bytes (pbe->salt->data, saltlen); - if (!(plen = i2d_PBEPARAM (pbe, NULL))) { - ASN1err(ASN1_F_ASN1_PBE_SET,ASN1_R_ENCODE_ERROR); - return NULL; - } - if (!(pdata = Malloc (plen))) { - ASN1err(ASN1_F_ASN1_PBE_SET,ERR_R_MALLOC_FAILURE); - return NULL; - } - ptmp = pdata; - i2d_PBEPARAM (pbe, &ptmp); - PBEPARAM_free (pbe); if (!(astype = ASN1_TYPE_new())) { ASN1err(ASN1_F_ASN1_PBE_SET,ERR_R_MALLOC_FAILURE); @@ -150,12 +135,11 @@ X509_ALGOR *PKCS5_pbe_set(int alg, int iter, unsigned char *salt, } astype->type = V_ASN1_SEQUENCE; - if (!(astype->value.sequence=ASN1_STRING_new())) { + if(!ASN1_pack_string(pbe, i2d_PBEPARAM, &astype->value.sequence)) { ASN1err(ASN1_F_ASN1_PBE_SET,ERR_R_MALLOC_FAILURE); return NULL; } - ASN1_STRING_set (astype->value.sequence, pdata, plen); - Free (pdata); + PBEPARAM_free (pbe); al = OBJ_nid2obj(alg); /* never need to free al */ if (!(algor = X509_ALGOR_new())) { diff --git a/crypto/asn1/p5_pbev2.c b/crypto/asn1/p5_pbev2.c index ee1ed87d9a..6400c10364 100644 --- a/crypto/asn1/p5_pbev2.c +++ b/crypto/asn1/p5_pbev2.c @@ -109,14 +109,14 @@ void PBE2PARAM_free (PBE2PARAM *a) int i2d_PBKDF2PARAM(PBKDF2PARAM *a, unsigned char **pp) { M_ASN1_I2D_vars(a); - M_ASN1_I2D_len (a->salt, i2d_ASN1_OCTET_STRING); + M_ASN1_I2D_len (a->salt, i2d_ASN1_TYPE); M_ASN1_I2D_len (a->iter, i2d_ASN1_INTEGER); M_ASN1_I2D_len (a->keylength, i2d_ASN1_INTEGER); M_ASN1_I2D_len (a->prf, i2d_X509_ALGOR); M_ASN1_I2D_seq_total (); - M_ASN1_I2D_put (a->salt, i2d_ASN1_OCTET_STRING); + M_ASN1_I2D_put (a->salt, i2d_ASN1_TYPE); M_ASN1_I2D_put (a->iter, i2d_ASN1_INTEGER); M_ASN1_I2D_put (a->keylength, i2d_ASN1_INTEGER); M_ASN1_I2D_put (a->prf, i2d_X509_ALGOR); @@ -129,7 +129,7 @@ PBKDF2PARAM *PBKDF2PARAM_new(void) PBKDF2PARAM *ret=NULL; ASN1_CTX c; M_ASN1_New_Malloc(ret, PBKDF2PARAM); - M_ASN1_New(ret->salt, ASN1_OCTET_STRING_new); + M_ASN1_New(ret->salt, ASN1_TYPE_new); M_ASN1_New(ret->iter, ASN1_INTEGER_new); ret->keylength = NULL; ret->prf = NULL; @@ -143,7 +143,7 @@ PBKDF2PARAM *d2i_PBKDF2PARAM(PBKDF2PARAM **a, unsigned char **pp, M_ASN1_D2I_vars(a,PBKDF2PARAM *,PBKDF2PARAM_new); M_ASN1_D2I_Init(); M_ASN1_D2I_start_sequence(); - M_ASN1_D2I_get (ret->salt, d2i_ASN1_OCTET_STRING); + M_ASN1_D2I_get (ret->salt, d2i_ASN1_TYPE); M_ASN1_D2I_get (ret->iter, d2i_ASN1_INTEGER); M_ASN1_D2I_get_opt (ret->keylength, d2i_ASN1_INTEGER, V_ASN1_INTEGER); M_ASN1_D2I_get_opt (ret->prf, d2i_X509_ALGOR, V_ASN1_SEQUENCE); @@ -160,3 +160,114 @@ void PBKDF2PARAM_free (PBKDF2PARAM *a) Free ((char *)a); } +/* Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm: + * yes I know this is horrible! + */ + +X509_ALGOR *PKCS5_pbe2_set(EVP_CIPHER *cipher, int iter, unsigned char *salt, + int saltlen) +{ + X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL; + int alg_nid; + EVP_CIPHER_CTX ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + PBKDF2PARAM *kdf = NULL; + PBE2PARAM *pbe2 = NULL; + ASN1_OCTET_STRING *osalt = NULL; + + if(!(pbe2 = PBE2PARAM_new())) goto merr; + + /* Setup the AlgorithmIdentifier for the encryption scheme */ + scheme = pbe2->encryption; + + alg_nid = EVP_CIPHER_type(cipher); + + scheme->algorithm = OBJ_nid2obj(alg_nid); + if(!(scheme->parameter = ASN1_TYPE_new())) goto merr; + + /* Create random IV */ + RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)); + + /* Dummy cipherinit to just setup the IV */ + EVP_CipherInit(&ctx, cipher, NULL, iv, 0); + if(EVP_CIPHER_param_to_asn1(&ctx, scheme->parameter) < 0) { + ASN1err(ASN1_F_PKCS5_PBE2_SET, + ASN1_R_ERROR_SETTING_CIPHER_PARAMS); + goto err; + } + EVP_CIPHER_CTX_cleanup(&ctx); + + if(!(kdf = PBKDF2PARAM_new())) goto merr; + if(!(osalt = ASN1_OCTET_STRING_new())) goto merr; + + if (!saltlen) saltlen = PKCS5_SALT_LEN; + if (!(osalt->data = Malloc (saltlen))) goto merr; + osalt->length = saltlen; + if (salt) memcpy (osalt->data, salt, saltlen); + else RAND_bytes (osalt->data, saltlen); + + 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 = ASN1_INTEGER_new())) goto merr; + if(!ASN1_INTEGER_set (kdf->keylength, + EVP_CIPHER_key_length(cipher))) goto merr; + } + + /* prf can stay NULL because we are using hmacWithSHA1 */ + + /* Now setup the PBE2PARAM keyfunc structure */ + + pbe2->keyfunc->algorithm = OBJ_nid2obj(NID_id_pbkdf2); + + /* Encode PBKDF2PARAM into parameter of pbe2 */ + + if(!(pbe2->keyfunc->parameter = ASN1_TYPE_new())) goto merr; + + if(!ASN1_pack_string(kdf, i2d_PBKDF2PARAM, + &pbe2->keyfunc->parameter->value.sequence)) goto merr; + pbe2->keyfunc->parameter->type = V_ASN1_SEQUENCE; + + PBKDF2PARAM_free(kdf); + kdf = NULL; + + /* Now set up top level AlgorithmIdentifier */ + + if(!(ret = X509_ALGOR_new())) goto merr; + if(!(ret->parameter = ASN1_TYPE_new())) goto merr; + + ret->algorithm = OBJ_nid2obj(NID_pbes2); + + /* Encode PBE2PARAM into parameter */ + + if(!ASN1_pack_string(pbe2, i2d_PBE2PARAM, + &ret->parameter->value.sequence)) goto merr; + ret->parameter->type = V_ASN1_SEQUENCE; + + PBE2PARAM_free(pbe2); + pbe2 = NULL; + + return ret; + + merr: + ASN1err(ASN1_F_PKCS5_PBE2_SET,ERR_R_MALLOC_FAILURE); + + err: + PBE2PARAM_free(pbe2); + /* Note 'scheme' is freed as part of pbe2 */ + ASN1_OCTET_STRING_free(osalt); + PBKDF2PARAM_free(kdf); + X509_ALGOR_free(kalg); + X509_ALGOR_free(ret); + + return NULL; + +} + diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index ad02fd33da..417e049620 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -109,6 +109,8 @@ extern "C" { #define EVP_MAX_KEY_LENGTH 24 #define EVP_MAX_IV_LENGTH 8 +#define PKCS5_SALT_LEN 8 + #ifndef NO_RSA #include #endif diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h index 9db7679ccd..95a66c234f 100644 --- a/crypto/objects/obj_dat.h +++ b/crypto/objects/obj_dat.h @@ -123,7 +123,7 @@ static unsigned char lvalues[984]={ 0x2B,0x0E,0x03,0x02,0x0D, /* [364] OBJ_dsaWithSHA */ 0x2B,0x0E,0x03,0x02,0x0C, /* [369] OBJ_dsa_2 */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0B,/* [374] OBJ_pbeWithSHA1AndRC2_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0C,/* [383] OBJ_pbeWithSHA1AndRC4 */ +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0C,/* [383] OBJ_id_pbkdf2 */ 0x2B,0x0E,0x03,0x02,0x1B, /* [392] OBJ_dsaWithSHA1_2 */ 0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,/* [397] OBJ_netscape_cert_type */ 0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x02,/* [406] OBJ_netscape_base_url */ @@ -304,8 +304,7 @@ static ASN1_OBJECT nid_objs[NUM_NID]={ {"DSA-old","dsaEncryption-old",NID_dsa_2,5,&(lvalues[369]),0}, {"pbeWithSHA1AndRC2-CBC","pbeWithSHA1AndRC2-CBC", NID_pbeWithSHA1AndRC2_CBC,9,&(lvalues[374]),0}, -{"pbeWithSHA1AndRC4","pbeWithSHA1AndRC4",NID_pbeWithSHA1AndRC4,9, - &(lvalues[383]),0}, +{"PBKDF2","PBKDF2",NID_id_pbkdf2,9,&(lvalues[383]),0}, {"DSA-SHA1-old","dsaWithSHA1-old",NID_dsaWithSHA1_2,5,&(lvalues[392]),0}, {"nsCertType","Netscape Cert Type",NID_netscape_cert_type,9, &(lvalues[397]),0}, @@ -600,6 +599,7 @@ static ASN1_OBJECT *ln_objs[NUM_LN]={ &(nid_objs[77]),/* "Netscape SSL Server Name" */ &(nid_objs[139]),/* "Netscape Server Gated Crypto" */ &(nid_objs[161]),/* "PBES2" */ +&(nid_objs[69]),/* "PBKDF2" */ &(nid_objs[162]),/* "PBMAC1" */ &(nid_objs[164]),/* "Policy Qualifier CPS" */ &(nid_objs[165]),/* "Policy Qualifier User Notice" */ @@ -694,7 +694,6 @@ static ASN1_OBJECT *ln_objs[NUM_LN]={ &(nid_objs[145]),/* "pbeWithSHA1And40BitRC4" */ &(nid_objs[170]),/* "pbeWithSHA1AndDES-CBC" */ &(nid_objs[68]),/* "pbeWithSHA1AndRC2-CBC" */ -&(nid_objs[69]),/* "pbeWithSHA1AndRC4" */ &(nid_objs[ 2]),/* "pkcs" */ &(nid_objs[27]),/* "pkcs3" */ &(nid_objs[20]),/* "pkcs7" */ @@ -839,7 +838,7 @@ static ASN1_OBJECT *obj_objs[NUM_OBJ]={ &(nid_objs[169]),/* OBJ_pbeWithMD5AndRC2_CBC 1 2 840 113549 1 5 6 */ &(nid_objs[170]),/* OBJ_pbeWithSHA1AndDES_CBC 1 2 840 113549 1 5 10 */ &(nid_objs[68]),/* OBJ_pbeWithSHA1AndRC2_CBC 1 2 840 113549 1 5 11 */ -&(nid_objs[69]),/* OBJ_pbeWithSHA1AndRC4 1 2 840 113549 1 5 12 */ +&(nid_objs[69]),/* OBJ_id_pbkdf2 1 2 840 113549 1 5 12 */ &(nid_objs[161]),/* OBJ_pbes2 1 2 840 113549 1 5 13 */ &(nid_objs[162]),/* OBJ_pbmac1 1 2 840 113549 1 5 14 */ &(nid_objs[21]),/* OBJ_pkcs7_data 1 2 840 113549 1 7 1 */ diff --git a/crypto/objects/objects.h b/crypto/objects/objects.h index fd5c02d313..e0f88f1f03 100644 --- a/crypto/objects/objects.h +++ b/crypto/objects/objects.h @@ -384,10 +384,13 @@ extern "C" { #define NID_pbeWithSHA1AndRC2_CBC 68 #define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs,5L,11L -/* proposed by microsoft to RSA */ -#define LN_pbeWithSHA1AndRC4 "pbeWithSHA1AndRC4" -#define NID_pbeWithSHA1AndRC4 69 -#define OBJ_pbeWithSHA1AndRC4 OBJ_pkcs,5L,12L +/* proposed by microsoft to RSA as pbeWithSHA1AndRC4: it is now + * defined explicitly in PKCS#5 v2.0 as id-PBKDF2 which is something + * completely different. + */ +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 OBJ_pkcs,5L,12L #define SN_dsaWithSHA1_2 "DSA-SHA1-old" #define LN_dsaWithSHA1_2 "dsaWithSHA1-old" diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index 5106f2e592..5030d920e9 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h @@ -364,7 +364,7 @@ X509_ALGOR *encryption; } PBE2PARAM; typedef struct PBKDF2PARAM_st { -ASN1_OCTET_STRING *salt; +ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */ ASN1_INTEGER *iter; ASN1_INTEGER *keylength; X509_ALGOR *prf; @@ -906,6 +906,8 @@ PBEPARAM *PBEPARAM_new(void); PBEPARAM *d2i_PBEPARAM(PBEPARAM **a, unsigned char **pp, long length); void PBEPARAM_free(PBEPARAM *a); X509_ALGOR *PKCS5_pbe_set(int alg, int iter, unsigned char *salt, int saltlen); +X509_ALGOR *PKCS5_pbe2_set(EVP_CIPHER *cipher, int iter, unsigned char *salt, + int saltlen); int i2d_PBKDF2PARAM(PBKDF2PARAM *a, unsigned char **pp); PBKDF2PARAM *PBKDF2PARAM_new(void); -- 2.34.1