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

Add support for some broken PKCS#8 formats.

parent eb5a6a55
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4,6 +4,10 @@

 Changes between 0.9.4 and 0.9.5  [xx XXX 2000]

  *) Add support for various broken PKCS#8 formats, and command line
     options to produce them.
     [Steve Henson]

  *) New functions BN_CTX_start(), BN_CTX_get() and BT_CTX_end() to
     get temporary BIGNUMs from a BN_CTX.
     [Ulf Möller]
+15 −4
Original line number Diff line number Diff line
@@ -124,6 +124,8 @@ int MAIN(int argc, char **argv)
		else if (!strcmp (*args, "-noiter")) iter = 1;
		else if (!strcmp (*args, "-nocrypt")) nocrypt = 1;
		else if (!strcmp (*args, "-nooct")) p8_broken = PKCS8_NO_OCTET;
		else if (!strcmp (*args, "-nsdb")) p8_broken = PKCS8_NS_DB;
		else if (!strcmp (*args, "-embed")) p8_broken = PKCS8_EMBEDDED_PARAM;
		else if (!strcmp(*args,"-passin"))
			{
			if (!args[1]) goto bad;
@@ -183,7 +185,9 @@ int MAIN(int argc, char **argv)
		BIO_printf(bio_err, "-passout arg    input file pass phrase\n");
		BIO_printf(bio_err, "-envpassout arg environment variable containing input file pass phrase\n");
		BIO_printf(bio_err, "-topk8     output PKCS8 file\n");
		BIO_printf(bio_err, "-nooct     use (broken) no octet form\n");
		BIO_printf(bio_err, "-nooct     use (nonstandard) no octet format\n");
		BIO_printf(bio_err, "-embed     use (nonstandard) embedded DSA parameters format\n");
		BIO_printf(bio_err, "-nsdb      use (nonstandard) DSA Netscape DB format\n");
		BIO_printf(bio_err, "-noiter    use 1 as iteration count\n");
		BIO_printf(bio_err, "-nocrypt   use or expect unencrypted private key\n");
		BIO_printf(bio_err, "-v2 alg    use PKCS#5 v2.0 and cipher \"alg\"\n");
@@ -224,12 +228,11 @@ int MAIN(int argc, char **argv)
			return (1);
		}
		BIO_free(in);
		if (!(p8inf = EVP_PKEY2PKCS8(pkey))) {
		if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, p8_broken))) {
			BIO_printf(bio_err, "Error converting key\n", outfile);
			ERR_print_errors(bio_err);
			return (1);
		}
		PKCS8_set_broken(p8inf, p8_broken);
		if(nocrypt) {
			if(outformat == FORMAT_PEM) 
				PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf);
@@ -316,7 +319,15 @@ int MAIN(int argc, char **argv)
		BIO_printf(bio_err, "Warning: broken key encoding: ");
		switch (p8inf->broken) {
			case PKCS8_NO_OCTET:
			BIO_printf(bio_err, "No Octet String\n");
			BIO_printf(bio_err, "No Octet String in PrivateKey\n");
			break;

			case PKCS8_EMBEDDED_PARAM:
			BIO_printf(bio_err, "DSA parameters included in PrivateKey\n");
			break;

			case PKCS8_NS_DB:
			BIO_printf(bio_err, "DSA public key include in PrivateKey\n");
			break;

			default:
+0 −2
Original line number Diff line number Diff line
@@ -109,8 +109,6 @@ PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO(PKCS8_PRIV_KEY_INFO **a,
	M_ASN1_D2I_get_IMP_set_opt_type(X509_ATTRIBUTE, ret->attributes,
					d2i_X509_ATTRIBUTE,
					X509_ATTRIBUTE_free, 0);
	if (ASN1_TYPE_get(ret->pkey) == V_ASN1_SEQUENCE) 
						ret->broken = PKCS8_NO_OCTET;
	M_ASN1_D2I_Finish(a, PKCS8_PRIV_KEY_INFO_free, ASN1_F_D2I_PKCS8_PRIV_KEY_INFO);
}

+181 −80
Original line number Diff line number Diff line
@@ -62,19 +62,22 @@
#include <openssl/x509.h>
#include <openssl/rand.h>

static int dsa_pkey2pkcs8(PKCS8_PRIV_KEY_INFO *p8inf, EVP_PKEY *pkey);

/* Extract a private key from a PKCS8 structure */

EVP_PKEY *EVP_PKCS82PKEY (PKCS8_PRIV_KEY_INFO *p8)
{
	EVP_PKEY *pkey;
	EVP_PKEY *pkey = NULL;
#ifndef NO_RSA
	RSA *rsa;
	RSA *rsa = NULL;
#endif
#ifndef NO_DSA
	DSA *dsa;
	ASN1_INTEGER *dsapriv;
	STACK *ndsa;
	BN_CTX *ctx;
	DSA *dsa = NULL;
	ASN1_INTEGER *privkey;
	ASN1_TYPE *t1, *t2, *param = NULL;
	STACK *ndsa = NULL;
	BN_CTX *ctx = NULL;
	int plen;
#endif
	X509_ALGOR *a;
@@ -82,21 +85,14 @@ EVP_PKEY *EVP_PKCS82PKEY (PKCS8_PRIV_KEY_INFO *p8)
	int pkeylen;
	char obj_tmp[80];

	switch (p8->broken) {
		case PKCS8_OK:
	if(p8->pkey->type == V_ASN1_OCTET_STRING) {
		p8->broken = PKCS8_OK;
		p = p8->pkey->value.octet_string->data;
		pkeylen = p8->pkey->value.octet_string->length;
		break;

		case PKCS8_NO_OCTET:
	} else {
		p8->broken = PKCS8_NO_OCTET;
		p = p8->pkey->value.sequence->data;
		pkeylen = p8->pkey->value.sequence->length;
		break;

		default:
		EVPerr(EVP_F_EVP_PKCS82PKEY,EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE);
		return NULL;
		break;
	}
	if (!(pkey = EVP_PKEY_new())) {
		EVPerr(EVP_F_EVP_PKCS82PKEY,ERR_R_MALLOC_FAILURE);
@@ -121,65 +117,83 @@ EVP_PKEY *EVP_PKCS82PKEY (PKCS8_PRIV_KEY_INFO *p8)
		 * be recalculated.
		 */
	
		/* Check for broken Netscape Database DSA PKCS#8, UGH! */
		/* Check for broken DSA PKCS#8, UGH! */
		if(*p == (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED)) {
		    if(!(ndsa = ASN1_seq_unpack(p, pkeylen, 
					(char *(*)())d2i_ASN1_INTEGER,
							 ASN1_STRING_free))) {
					(char *(*)())d2i_ASN1_TYPE,
							 ASN1_TYPE_free))) {
			EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_DECODE_ERROR);
			return NULL;
			goto dsaerr;
		    }
		    if(sk_num(ndsa) != 2 ) {
			EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_DECODE_ERROR);
			sk_pop_free(ndsa, ASN1_STRING_free);
			return NULL;
			goto dsaerr;
		    }
		    dsapriv = (ASN1_INTEGER *) sk_pop(ndsa);
		    sk_pop_free(ndsa, ASN1_STRING_free);
		} else if (!(dsapriv=d2i_ASN1_INTEGER (NULL, &p, pkeylen))) {
		    /* Handle Two broken types:
		     * SEQUENCE {parameters, priv_key}
		     * SEQUENCE {pub_key, priv_key}
		     */
                     
		    t1 = (ASN1_TYPE *)sk_value(ndsa, 0);
		    t2 = (ASN1_TYPE *)sk_value(ndsa, 1);
		    if(t1->type == V_ASN1_SEQUENCE) {
			p8->broken = PKCS8_EMBEDDED_PARAM;
			param = t1;
		    } else if(a->parameter->type == V_ASN1_SEQUENCE) {
			p8->broken = PKCS8_NS_DB;
			param = a->parameter;
		    } else {
			EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_DECODE_ERROR);
			return NULL;
			goto dsaerr;
		    }
		/* Retrieve parameters */
		if (a->parameter->type != V_ASN1_SEQUENCE) {
			EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_NO_DSA_PARAMETERS);
			return NULL;

		    if(t2->type != V_ASN1_INTEGER) {
			EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_DECODE_ERROR);
			goto dsaerr;
		    }
		    privkey = t2->value.integer;
		} else if (!(privkey=d2i_ASN1_INTEGER (NULL, &p, pkeylen))) {
			EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_DECODE_ERROR);
			goto dsaerr;
		}
		p = a->parameter->value.sequence->data;
		plen = a->parameter->value.sequence->length;
		p = param->value.sequence->data;
		plen = param->value.sequence->length;
		if (!(dsa = d2i_DSAparams (NULL, &p, plen))) {
			EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_DECODE_ERROR);
			return NULL;
			goto dsaerr;
		}
		/* We have parameters now set private key */
		if (!(dsa->priv_key = ASN1_INTEGER_to_BN(dsapriv, NULL))) {
		if (!(dsa->priv_key = ASN1_INTEGER_to_BN(privkey, NULL))) {
			EVPerr(EVP_F_EVP_PKCS82PKEY,EVP_R_BN_DECODE_ERROR);
			DSA_free (dsa);
			return NULL;
			goto dsaerr;
		}
		/* Calculate public key (ouch!) */
		if (!(dsa->pub_key = BN_new())) {
			EVPerr(EVP_F_EVP_PKCS82PKEY,ERR_R_MALLOC_FAILURE);
			DSA_free (dsa);
			return NULL;
			goto dsaerr;
		}
		if (!(ctx = BN_CTX_new())) {
			EVPerr(EVP_F_EVP_PKCS82PKEY,ERR_R_MALLOC_FAILURE);
			DSA_free (dsa);
			return NULL;
			goto dsaerr;
		}
			
		if (!BN_mod_exp(dsa->pub_key, dsa->g,
						 dsa->priv_key, dsa->p, ctx)) {
			
			EVPerr(EVP_F_EVP_PKCS82PKEY,EVP_R_BN_PUBKEY_ERROR);
			BN_CTX_free (ctx);
			DSA_free (dsa);
			return NULL;
			goto dsaerr;
		}

		EVP_PKEY_assign_DSA(pkey, dsa);
		BN_CTX_free (ctx);
		sk_pop_free(ndsa, ASN1_TYPE_free);
		break;
		dsaerr:
		BN_CTX_free (ctx);
		sk_pop_free(ndsa, ASN1_TYPE_free);
		DSA_free(dsa);
		EVP_PKEY_free(pkey);
		return NULL;
		break;
#endif
		default:
@@ -193,30 +207,35 @@ EVP_PKEY *EVP_PKCS82PKEY (PKCS8_PRIV_KEY_INFO *p8)
	return pkey;
}

PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey)
{
	return EVP_PKEY2PKCS8_broken(pkey, PKCS8_OK);
}

/* Turn a private key into a PKCS8 structure */

PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey)
PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken)
{
	PKCS8_PRIV_KEY_INFO *p8;
#ifndef NO_DSA
	ASN1_INTEGER *dpkey;
	unsigned char *p, *q;
	int len;
#endif

	if (!(p8 = PKCS8_PRIV_KEY_INFO_new())) {	
		EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
		return NULL;
	}
	p8->broken = broken;
	ASN1_INTEGER_set (p8->version, 0);
	if (!(p8->pkeyalg->parameter = ASN1_TYPE_new ())) {
		EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
		PKCS8_PRIV_KEY_INFO_free (p8);
		return NULL;
	}
	p8->pkey->type = V_ASN1_OCTET_STRING;
	switch (EVP_PKEY_type(pkey->type)) {
#ifndef NO_RSA
		case EVP_PKEY_RSA:

		if(p8->broken == PKCS8_NO_OCTET) p8->pkey->type = V_ASN1_SEQUENCE;

		p8->pkeyalg->algorithm = OBJ_nid2obj(NID_rsaEncryption);
		p8->pkeyalg->parameter->type = V_ASN1_NULL;
		if (!ASN1_pack_string ((char *)pkey, i2d_PrivateKey,
@@ -229,36 +248,11 @@ PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey)
#endif
#ifndef NO_DSA
		case EVP_PKEY_DSA:
		p8->pkeyalg->algorithm = OBJ_nid2obj(NID_dsa);

		/* get parameters and place in AlgorithmIdentifier */
		len = i2d_DSAparams (pkey->pkey.dsa, NULL);
		if (!(p = Malloc(len))) {
			EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
			PKCS8_PRIV_KEY_INFO_free (p8);
			return NULL;
		}
		q = p;
		i2d_DSAparams (pkey->pkey.dsa, &q);
		p8->pkeyalg->parameter->type = V_ASN1_SEQUENCE;
		p8->pkeyalg->parameter->value.sequence = ASN1_STRING_new();
		ASN1_STRING_set(p8->pkeyalg->parameter->value.sequence, p, len);
		Free(p);
		/* Get private key into an integer and pack */
		if (!(dpkey = BN_to_ASN1_INTEGER (pkey->pkey.dsa->priv_key, NULL))) {
			EVPerr(EVP_F_EVP_PKEY2PKCS8,EVP_R_ENCODE_ERROR);
		if(!dsa_pkey2pkcs8(p8, pkey)) {
			PKCS8_PRIV_KEY_INFO_free (p8);
			return NULL;
		}

		if (!ASN1_pack_string((char *)dpkey, i2d_ASN1_INTEGER,
					 &p8->pkey->value.octet_string)) {
			EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
			M_ASN1_INTEGER_free (dpkey);
			PKCS8_PRIV_KEY_INFO_free (p8);
			return NULL;
		}
		M_ASN1_INTEGER_free (dpkey);
		break;
#endif
		default:
@@ -266,7 +260,6 @@ PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey)
		PKCS8_PRIV_KEY_INFO_free (p8);
		return NULL;
	}
	p8->pkey->type = V_ASN1_OCTET_STRING;
	RAND_add(p8->pkey->value.octet_string->data,
		 p8->pkey->value.octet_string->length, 0);
	return p8;
@@ -295,4 +288,112 @@ PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken)
	}
}

#ifndef NO_DSA
static int dsa_pkey2pkcs8(PKCS8_PRIV_KEY_INFO *p8, EVP_PKEY *pkey)
{
	ASN1_STRING *params;
	ASN1_INTEGER *prkey;
	ASN1_TYPE *ttmp;
	STACK *ndsa;
	unsigned char *p, *q;
	int len;
	p8->pkeyalg->algorithm = OBJ_nid2obj(NID_dsa);
	len = i2d_DSAparams (pkey->pkey.dsa, NULL);
	if (!(p = Malloc(len))) {
		EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
		PKCS8_PRIV_KEY_INFO_free (p8);
		return 0;
	}
	q = p;
	i2d_DSAparams (pkey->pkey.dsa, &q);
	params = ASN1_STRING_new();
	ASN1_STRING_set(params, p, len);
	Free(p);
	/* Get private key into integer */
	if (!(prkey = BN_to_ASN1_INTEGER (pkey->pkey.dsa->priv_key, NULL))) {
		EVPerr(EVP_F_EVP_PKEY2PKCS8,EVP_R_ENCODE_ERROR);
		return 0;
	}

	switch(p8->broken) {

		case PKCS8_OK:
		case PKCS8_NO_OCTET:

		if (!ASN1_pack_string((char *)prkey, i2d_ASN1_INTEGER,
					 &p8->pkey->value.octet_string)) {
			EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
			M_ASN1_INTEGER_free (prkey);
			return 0;
		}

		M_ASN1_INTEGER_free (prkey);
		p8->pkeyalg->parameter->value.sequence = params;
		p8->pkeyalg->parameter->type = V_ASN1_SEQUENCE;

		break;

		case PKCS8_NS_DB:

		p8->pkeyalg->parameter->value.sequence = params;
		p8->pkeyalg->parameter->type = V_ASN1_SEQUENCE;
		ndsa = sk_new_null();
		ttmp = ASN1_TYPE_new();
		if (!(ttmp->value.integer = BN_to_ASN1_INTEGER (pkey->pkey.dsa->pub_key, NULL))) {
			EVPerr(EVP_F_EVP_PKEY2PKCS8,EVP_R_ENCODE_ERROR);
			PKCS8_PRIV_KEY_INFO_free(p8);
			return 0;
		}
		ttmp->type = V_ASN1_INTEGER;
		sk_push(ndsa, (char *)ttmp);

		ttmp = ASN1_TYPE_new();
		ttmp->value.integer = prkey;
		ttmp->type = V_ASN1_INTEGER;
		sk_push(ndsa, (char *)ttmp);

		p8->pkey->value.octet_string = ASN1_OCTET_STRING_new();

		if (!ASN1_seq_pack(ndsa, i2d_ASN1_TYPE,
					 &p8->pkey->value.octet_string->data,
					 &p8->pkey->value.octet_string->length)) {

			EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
			sk_pop_free(ndsa, ASN1_TYPE_free);
			M_ASN1_INTEGER_free(prkey);
			return 0;
		}
		sk_pop_free(ndsa, ASN1_TYPE_free);
		break;

		case PKCS8_EMBEDDED_PARAM:

		p8->pkeyalg->parameter->type = V_ASN1_NULL;
		ndsa = sk_new_null();
		ttmp = ASN1_TYPE_new();
		ttmp->value.sequence = params;
		ttmp->type = V_ASN1_SEQUENCE;
		sk_push(ndsa, (char *)ttmp);

		ttmp = ASN1_TYPE_new();
		ttmp->value.integer = prkey;
		ttmp->type = V_ASN1_INTEGER;
		sk_push(ndsa, (char *)ttmp);

		p8->pkey->value.octet_string = ASN1_OCTET_STRING_new();

		if (!ASN1_seq_pack(ndsa, i2d_ASN1_TYPE,
					 &p8->pkey->value.octet_string->data,
					 &p8->pkey->value.octet_string->length)) {

			EVPerr(EVP_F_EVP_PKEY2PKCS8,ERR_R_MALLOC_FAILURE);
			sk_pop_free(ndsa, ASN1_TYPE_free);
			M_ASN1_INTEGER_free (prkey);
			return 0;
		}
		sk_pop_free(ndsa, ASN1_TYPE_free);
		break;
	}
	return 1;
}
#endif
+5 −2
Original line number Diff line number Diff line
@@ -435,6 +435,8 @@ typedef struct pkcs8_priv_key_info_st
        int broken;     /* Flag for various broken formats */
#define PKCS8_OK		0
#define PKCS8_NO_OCTET		1
#define PKCS8_EMBEDDED_PARAM	2
#define PKCS8_NS_DB		3
        ASN1_INTEGER *version;
        X509_ALGOR *pkeyalg;
        ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */
@@ -1105,6 +1107,7 @@ void PKCS8_PRIV_KEY_INFO_free(PKCS8_PRIV_KEY_INFO *a);

EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8);
PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey);
PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken);
PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken);

int X509_check_trust(X509 *x, int id, int flags);
Loading