Skip to content

Commit

Permalink
Initial experimental support for X9.42 DH parameter format to handle
Browse files Browse the repository at this point in the history
RFC5114 parameters and X9.42 DH public and private keys.
(backport from HEAD)
  • Loading branch information
snhenson committed Apr 7, 2012
1 parent 4e891a1 commit 491734e
Show file tree
Hide file tree
Showing 14 changed files with 313 additions and 24 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

Changes between 1.0.1 and 1.0.2 [xx XXX xxxx]

*) Initial experimental support for X9.42 DH parameter format: mainly
to support use of 'q' parameter for RFC5114 parameters.
[Steve Henson]

*) Add DH parameters from RFC5114 including test data to dhtest.
[Steve Henson]

Expand Down
6 changes: 5 additions & 1 deletion crypto/asn1/ameth_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[];
extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[];
extern const EVP_PKEY_ASN1_METHOD dh_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD dhx_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD eckey_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD cmac_asn1_meth;
Expand All @@ -92,7 +93,10 @@ static const EVP_PKEY_ASN1_METHOD *standard_methods[] =
&eckey_asn1_meth,
#endif
&hmac_asn1_meth,
&cmac_asn1_meth
&cmac_asn1_meth,
#ifndef OPENSSL_NO_DH
&dhx_asn1_meth
#endif
};

typedef int sk_cmp_fn_type(const char * const *a, const char * const *b);
Expand Down
11 changes: 11 additions & 0 deletions crypto/dh/dh.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ int DH_generate_key(DH *dh);
int DH_compute_key(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
Expand All @@ -237,8 +239,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 */
Expand Down
98 changes: 82 additions & 16 deletions crypto/dh/dh_ameth.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,26 @@
#include <openssl/bn.h>
#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);
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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);
Expand All @@ -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;

Expand Down Expand Up @@ -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)))
Expand All @@ -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);

Expand Down Expand Up @@ -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, &params->data);
params->length = i2d_dhp(pkey, pkey->pkey.dh, &params->data);
if (params->length <= 0)
{
DHerr(DH_F_DH_PRIV_ENCODE,ERR_R_MALLOC_FAILURE);
Expand All @@ -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;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -347,11 +367,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)
Expand Down Expand Up @@ -403,8 +423,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)
Expand All @@ -422,6 +446,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;
}
Expand Down Expand Up @@ -499,3 +532,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
};

105 changes: 105 additions & 0 deletions crypto/dh/dh_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 491734e

Please sign in to comment.