From afb14cda8c70d18b97bbf3419bd308ba5b65f3b9 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 7 Dec 2011 00:32:34 +0000 Subject: Initial experimental support for X9.42 DH parameter format to handle RFC5114 parameters and X9.42 DH public and private keys. --- crypto/dh/dh.h | 11 ++++++ crypto/dh/dh_ameth.c | 98 +++++++++++++++++++++++++++++++++++++++-------- crypto/dh/dh_asn1.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ crypto/dh/dh_pmeth.c | 80 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 277 insertions(+), 17 deletions(-) (limited to 'crypto/dh') diff --git a/crypto/dh/dh.h b/crypto/dh/dh.h index 9b90197acf..ce5fee9c79 100644 --- a/crypto/dh/dh.h +++ b/crypto/dh/dh.h @@ -223,6 +223,8 @@ int DH_compute_key(unsigned char *key,const BIGNUM *pub_key,DH *dh); int DH_compute_key_padded(unsigned char *key,const BIGNUM *pub_key,DH *dh); DH * d2i_DHparams(DH **a,const unsigned char **pp, long length); int i2d_DHparams(const DH *a,unsigned char **pp); +DH * d2i_DHxparams(DH **a,const unsigned char **pp, long length); +int i2d_DHxparams(const DH *a,unsigned char **pp); #ifndef OPENSSL_NO_FP_API int DHparams_print_fp(FILE *fp, const DH *x); #endif @@ -245,8 +247,17 @@ DH *DH_get_2048_256(void); EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \ EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR, gen, NULL) +#define EVP_PKEY_CTX_set_dh_rfc5114(ctx, gen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_RFC5114, gen, NULL) + +#define EVP_PKEY_CTX_set_dhx_rfc5114(ctx, gen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_RFC5114, gen, NULL) + #define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN (EVP_PKEY_ALG_CTRL + 1) #define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR (EVP_PKEY_ALG_CTRL + 2) +#define EVP_PKEY_CTRL_DH_RFC5114 (EVP_PKEY_ALG_CTRL + 3) /* BEGIN ERROR CODES */ diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c index f3e910e105..8d0fe2e3f7 100644 --- a/crypto/dh/dh_ameth.c +++ b/crypto/dh/dh_ameth.c @@ -63,6 +63,26 @@ #include #include "asn1_locl.h" +extern const EVP_PKEY_ASN1_METHOD dhx_asn1_meth; + +/* i2d/d2i like DH parameter functions which use the appropriate routine + * for PKCS#3 DH or X9.42 DH. + */ + +static DH * d2i_dhp(const EVP_PKEY *pkey, const unsigned char **pp, long length) + { + if (pkey->ameth == &dhx_asn1_meth) + return d2i_DHxparams(NULL, pp, length); + return d2i_DHparams(NULL, pp, length); + } + +static int i2d_dhp(const EVP_PKEY *pkey, const DH *a, unsigned char **pp) + { + if (pkey->ameth == &dhx_asn1_meth) + return i2d_DHxparams(a, pp); + return i2d_DHparams(a, pp); + } + static void int_dh_free(EVP_PKEY *pkey) { DH_free(pkey->pkey.dh); @@ -94,7 +114,7 @@ static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) pm = pstr->data; pmlen = pstr->length; - if (!(dh = d2i_DHparams(NULL, &pm, pmlen))) + if (!(dh = d2i_dhp(pkey, &pm, pmlen))) { DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR); goto err; @@ -114,7 +134,7 @@ static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) } ASN1_INTEGER_free(public_key); - EVP_PKEY_assign_DH(pkey, dh); + EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh); return 1; err: @@ -139,7 +159,7 @@ static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) dh=pkey->pkey.dh; str = ASN1_STRING_new(); - str->length = i2d_DHparams(dh, &str->data); + str->length = i2d_dhp(pkey, dh, &str->data); if (str->length <= 0) { DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE); @@ -162,7 +182,7 @@ static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) goto err; } - if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DH), + if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(pkey->ameth->pkey_id), ptype, pval, penc, penclen)) return 1; @@ -208,7 +228,7 @@ static int dh_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) pstr = pval; pm = pstr->data; pmlen = pstr->length; - if (!(dh = d2i_DHparams(NULL, &pm, pmlen))) + if (!(dh = d2i_dhp(pkey, &pm, pmlen))) goto decerr; /* We have parameters now set private key */ if (!(dh->priv_key = ASN1_INTEGER_to_BN(privkey, NULL))) @@ -220,7 +240,7 @@ static int dh_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) if (!DH_generate_key(dh)) goto dherr; - EVP_PKEY_assign_DH(pkey, dh); + EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh); ASN1_INTEGER_free(privkey); @@ -248,7 +268,7 @@ static int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) goto err; } - params->length = i2d_DHparams(pkey->pkey.dh, ¶ms->data); + params->length = i2d_dhp(pkey, pkey->pkey.dh, ¶ms->data); if (params->length <= 0) { DHerr(DH_F_DH_PRIV_ENCODE,ERR_R_MALLOC_FAILURE); @@ -269,7 +289,7 @@ static int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) ASN1_INTEGER_free(prkey); - if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_dhKeyAgreement), 0, + if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0, V_ASN1_SEQUENCE, params, dp, dplen)) goto err; @@ -299,18 +319,18 @@ static int dh_param_decode(EVP_PKEY *pkey, const unsigned char **pder, int derlen) { DH *dh; - if (!(dh = d2i_DHparams(NULL, pder, derlen))) + if (!(dh = d2i_dhp(pkey, pder, derlen))) { DHerr(DH_F_DH_PARAM_DECODE, ERR_R_DH_LIB); return 0; } - EVP_PKEY_assign_DH(pkey, dh); + EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh); return 1; } static int dh_param_encode(const EVP_PKEY *pkey, unsigned char **pder) { - return i2d_DHparams(pkey->pkey.dh, pder); + return i2d_dhp(pkey, pkey->pkey.dh, pder); } static int do_dh_print(BIO *bp, const DH *x, int indent, @@ -348,11 +368,11 @@ static int do_dh_print(BIO *bp, const DH *x, int indent, update_buflen(priv_key, &buf_len); if (ptype == 2) - ktype = "PKCS#3 DH Private-Key"; + ktype = "DH Private-Key"; else if (ptype == 1) - ktype = "PKCS#3 DH Public-Key"; + ktype = "DH Public-Key"; else - ktype = "PKCS#3 DH Parameters"; + ktype = "DH Parameters"; m= OPENSSL_malloc(buf_len+10); if (m == NULL) @@ -405,8 +425,12 @@ static int dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) if ( BN_cmp(a->pkey.dh->p,b->pkey.dh->p) || BN_cmp(a->pkey.dh->g,b->pkey.dh->g)) return 0; - else - return 1; + else if (a->ameth == &dhx_asn1_meth) + { + if (BN_cmp(a->pkey.dh->q,b->pkey.dh->q)) + return 0; + } + return 1; } static int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) @@ -424,6 +448,15 @@ static int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) if (to->pkey.dh->g != NULL) BN_free(to->pkey.dh->g); to->pkey.dh->g=a; + if (from->ameth == &dhx_asn1_meth) + { + a = BN_dup(from->pkey.dh->q); + if (!a) + return 0; + if (to->pkey.dh->q) + BN_free(to->pkey.dh->q); + to->pkey.dh->q = a; + } return 1; } @@ -501,3 +534,36 @@ const EVP_PKEY_ASN1_METHOD dh_asn1_meth = 0 }; +const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = + { + EVP_PKEY_DHX, + EVP_PKEY_DHX, + 0, + + "X9.42 DH", + "OpenSSL X9.42 DH method", + + dh_pub_decode, + dh_pub_encode, + dh_pub_cmp, + dh_public_print, + + dh_priv_decode, + dh_priv_encode, + dh_private_print, + + int_dh_size, + dh_bits, + + dh_param_decode, + dh_param_encode, + dh_missing_parameters, + dh_copy_parameters, + dh_cmp_parameters, + dh_param_print, + 0, + + int_dh_free, + 0 + }; + diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c index 0b4357d605..6de297f17e 100644 --- a/crypto/dh/dh_asn1.c +++ b/crypto/dh/dh_asn1.c @@ -91,3 +91,108 @@ DH *DHparams_dup(DH *dh) { return ASN1_item_dup(ASN1_ITEM_rptr(DHparams), dh); } + +/* Internal only structures for handling X9.42 DH: this gets translated + * to or from a DH structure straight away. + */ + +typedef struct + { + ASN1_BIT_STRING *seed; + BIGNUM *counter; + } int_dhvparams; + +typedef struct + { + BIGNUM *p; + BIGNUM *q; + BIGNUM *g; + BIGNUM *j; + int_dhvparams *vparams; + } int_dhx942_dh; + +ASN1_SEQUENCE(DHvparams) = { + ASN1_SIMPLE(int_dhvparams, seed, ASN1_BIT_STRING), + ASN1_SIMPLE(int_dhvparams, counter, BIGNUM) +} ASN1_SEQUENCE_END_name(int_dhvparams, DHvparams) + +ASN1_SEQUENCE(DHxparams) = { + ASN1_SIMPLE(int_dhx942_dh, p, BIGNUM), + ASN1_SIMPLE(int_dhx942_dh, g, BIGNUM), + ASN1_SIMPLE(int_dhx942_dh, q, BIGNUM), + ASN1_OPT(int_dhx942_dh, j, BIGNUM), + ASN1_OPT(int_dhx942_dh, vparams, DHvparams), +} ASN1_SEQUENCE_END_name(int_dhx942_dh, DHxparams) + +int_dhx942_dh * d2i_int_dhx(int_dhx942_dh **a, + const unsigned char **pp, long length); +int i2d_int_dhx(const int_dhx942_dh *a,unsigned char **pp); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(int_dhx942_dh, DHxparams, int_dhx) + +/* Application leve function: read in X9.42 DH parameters into DH structure */ + +DH * d2i_DHxparams(DH **a,const unsigned char **pp, long length) + { + int_dhx942_dh *dhx = NULL; + DH *dh = NULL; + dh = DH_new(); + if (!dh) + return NULL; + dhx = d2i_int_dhx(NULL, pp, length); + if (!dhx) + { + DH_free(dh); + return NULL; + } + + if (a) + { + if (*a) + DH_free(*a); + *a = dh; + } + + dh->p = dhx->p; + dh->q = dhx->q; + dh->g = dhx->g; + dh->j = dhx->j; + + if (dhx->vparams) + { + dh->seed = dhx->vparams->seed->data; + dh->seedlen = dhx->vparams->seed->length; + dh->counter = dhx->vparams->counter; + dhx->vparams->seed->data = NULL; + ASN1_BIT_STRING_free(dhx->vparams->seed); + OPENSSL_free(dhx->vparams); + dhx->vparams = NULL; + } + + OPENSSL_free(dhx); + return dh; + } + +int i2d_DHxparams(const DH *dh,unsigned char **pp) + { + int_dhx942_dh dhx; + int_dhvparams dhv; + ASN1_BIT_STRING bs; + dhx.p = dh->p; + dhx.g = dh->g; + dhx.q = dh->q; + dhx.j = dh->j; + if (dh->counter && dh->seed && dh->seedlen > 0) + { + bs.flags = ASN1_STRING_FLAG_BITS_LEFT; + bs.data = dh->seed; + bs.length = dh->seedlen; + dhv.seed = &bs; + dhv.counter = dh->counter; + dhx.vparams = &dhv; + } + else + dhx.vparams = NULL; + + return i2d_int_dhx(&dhx, pp); + } diff --git a/crypto/dh/dh_pmeth.c b/crypto/dh/dh_pmeth.c index 5ae72b7d4c..58283132c7 100644 --- a/crypto/dh/dh_pmeth.c +++ b/crypto/dh/dh_pmeth.c @@ -72,6 +72,7 @@ typedef struct int prime_len; int generator; int use_dsa; + int rfc5114_param; /* Keygen callback info */ int gentmp[2]; /* message digest */ @@ -86,6 +87,7 @@ static int pkey_dh_init(EVP_PKEY_CTX *ctx) dctx->prime_len = 1024; dctx->generator = 2; dctx->use_dsa = 0; + dctx->rfc5114_param = 0; ctx->data = dctx; ctx->keygen_info = dctx->gentmp; @@ -104,6 +106,7 @@ static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) dctx->prime_len = sctx->prime_len; dctx->generator = sctx->generator; dctx->use_dsa = sctx->use_dsa; + dctx->rfc5114_param = sctx->rfc5114_param; return 1; } @@ -129,6 +132,12 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) dctx->generator = p1; return 1; + case EVP_PKEY_CTRL_DH_RFC5114: + if (p1 < 1 || p1 > 3) + return -2; + dctx->rfc5114_param = p1; + return 1; + case EVP_PKEY_CTRL_PEER_KEY: /* Default behaviour is OK */ return 1; @@ -149,6 +158,16 @@ static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, len = atoi(value); return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len); } + if (!strcmp(type, "dh_rfc5114")) + { + DH_PKEY_CTX *dctx = ctx->data; + int len; + len = atoi(value); + if (len < 0 || len > 3) + return -2; + dctx->rfc5114_param = len; + return 1; + } if (!strcmp(type, "dh_paramgen_generator")) { int len; @@ -164,6 +183,29 @@ static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) DH_PKEY_CTX *dctx = ctx->data; BN_GENCB *pcb, cb; int ret; + if (dctx->rfc5114_param) + { + switch (dctx->rfc5114_param) + { + case 1: + dh = DH_get_1024_160(); + break; + + case 2: + dh = DH_get_2048_224(); + break; + + case 3: + dh = DH_get_2048_256(); + break; + + default: + return -2; + } + EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh); + return 1; + } + if (ctx->pkey_gencb) { pcb = &cb; @@ -194,7 +236,7 @@ static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) dh = DH_new(); if (!dh) return 0; - EVP_PKEY_assign_DH(pkey, dh); + EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, dh); /* Note: if error return, pkey is freed by parent routine */ if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) return 0; @@ -252,3 +294,39 @@ const EVP_PKEY_METHOD dh_pkey_meth = pkey_dh_ctrl_str }; + +const EVP_PKEY_METHOD dhx_pkey_meth = + { + EVP_PKEY_DHX, + EVP_PKEY_FLAG_AUTOARGLEN, + pkey_dh_init, + pkey_dh_copy, + pkey_dh_cleanup, + + 0, + pkey_dh_paramgen, + + 0, + pkey_dh_keygen, + + 0, + 0, + + 0, + 0, + + 0,0, + + 0,0,0,0, + + 0,0, + + 0,0, + + 0, + pkey_dh_derive, + + pkey_dh_ctrl, + pkey_dh_ctrl_str + + }; -- cgit v1.2.3