提交 66430207 编写于 作者: D Dr. Stephen Henson

Add support for some broken PKCS#8 formats.

上级 eb5a6a55
......@@ -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]
......
......@@ -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:
......
......@@ -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);
}
......
......@@ -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;
}
/* Retrieve parameters */
if (a->parameter->type != V_ASN1_SEQUENCE) {
EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_NO_DSA_PARAMETERS);
return NULL;
goto dsaerr;
}
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);
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);
if(!dsa_pkey2pkcs8(p8, pkey)) {
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);
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
......@@ -433,8 +433,10 @@ X509_ALGOR *prf;
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_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);
......
......@@ -19,6 +19,8 @@ B<openssl> B<pkcs8>
[B<-noiter>]
[B<-nocrypt>]
[B<-nooct>]
[B<-embed>]
[B<-nsdb>]
[B<-v2 alg>]
[B<-v1 alg>]
......@@ -93,11 +95,24 @@ code signing software used unencrypted private keys.
=item B<-nooct>
This option generates private keys in a broken format that some software
This option generates RSA private keys in a broken format that some software
uses. Specifically the private key should be enclosed in a OCTET STRING
but some software just includes the structure itself without the
surrounding OCTET STRING.
=item B<-embed>
This option generates DSA keys in a broken format. The DSA parameters are
embedded inside the PrivateKey structure. In this form the OCTET STRING
contains an ASN1 SEQUENCE consisting of two structures: a SEQUENCE containing
the parameters and an ASN1 INTEGER containing the private key.
=item B<-nsdb>
This option generates DSA keys in a broken format compatible with Netscape
private key databases. The PrivateKey contains a SEQUENCE consisting of
the public and private keys respectively.
=item B<-v2 alg>
This option enables the use of PKCS#5 v2.0 algorithms. Normally PKCS#8
......@@ -202,11 +217,16 @@ Convert a private key from any PKCS#8 format to traditional format:
=head1 STANDARDS
Test vectors from this implementation were posted to the pkcs-tng mailing
list using triple DES, DES and RC2 with high iteration counts, several
people confirmed that they could decrypt the private keys produced and
Therefore it can be assumed that the PKCS#5 v2.0 implementation is
reasonably accurate at least as far as these algorithms are concerned.
Test vectors from this PKCS#5 v2.0 implementation were posted to the
pkcs-tng mailing list using triple DES, DES and RC2 with high iteration
counts, several people confirmed that they could decrypt the private
keys produced and Therefore it can be assumed that the PKCS#5 v2.0
implementation is reasonably accurate at least as far as these
algorithms are concerned.
The format of PKCS#8 DSA (and other) private keys is not well documented:
it is hidden away in PKCS#11 v2.01, section 11.9. OpenSSL's DSA private
key format complies with this standard.
=head1 BUGS
......
......@@ -2216,3 +2216,4 @@ BN_is_prime_fasttest 2240
BN_CTX_end 2241
BN_CTX_start 2242
BN_CTX_get 2243
EVP_PKEY2PKCS8_broken 2244
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册