Commit afb14cda authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Initial experimental support for X9.42 DH parameter format to handle

RFC5114 parameters and X9.42 DH public and private keys.
parent df0cdf4c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4,6 +4,10 @@

 Changes between 1.0.1 and 1.1.0  [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]

+5 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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);
+11 −0
Original line number Diff line number Diff line
@@ -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 */
+82 −16
Original line number Diff line number Diff line
@@ -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);
@@ -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, &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);
@@ -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,7 +425,11 @@ 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
	else if (a->ameth == &dhx_asn1_meth)
		{
		if (BN_cmp(a->pkey.dh->q,b->pkey.dh->q))
			return 0;
		}
	return 1;
	}

@@ -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
	};
+105 −0
Original line number Diff line number Diff line
@@ -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);
	}
Loading