Reimplement d2i_AutoPrivateKey with the new ASN.1 stack.
This is kind of a ridiculous function. It would be nice to lose it, but SSL_use_PrivateKey_file actually calls into it (by way of d2i_PrivateKey_bio). BUG=499653 Change-Id: I83634f6982b15f4b877e29f6793b7e00a1c10450 Reviewed-on: https://boringssl-review.googlesource.com/7026 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
8ebc0f55a0
commit
6d3387d9c1
@ -56,10 +56,12 @@
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/obj.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "internal.h"
|
||||
@ -219,50 +221,61 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* num_elements parses one SEQUENCE from |in| and returns the number of elements
|
||||
* in it. On parse error, it returns zero. */
|
||||
static size_t num_elements(const uint8_t *in, size_t in_len) {
|
||||
CBS cbs, sequence;
|
||||
CBS_init(&cbs, in, (size_t)in_len);
|
||||
|
||||
if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
while (CBS_len(&sequence) > 0) {
|
||||
if (!CBS_get_any_asn1_element(&sequence, NULL, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) {
|
||||
STACK_OF(ASN1_TYPE) *inkey;
|
||||
const uint8_t *p;
|
||||
int keytype;
|
||||
p = *inp;
|
||||
|
||||
/* Dirty trick: read in the ASN1 data into out STACK_OF(ASN1_TYPE):
|
||||
* by analyzing it we can determine the passed structure: this
|
||||
* assumes the input is surrounded by an ASN1 SEQUENCE. */
|
||||
inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, len);
|
||||
/* Since we only need to discern "traditional format" RSA and DSA
|
||||
* keys we can just count the elements. */
|
||||
if (sk_ASN1_TYPE_num(inkey) == 6) {
|
||||
keytype = EVP_PKEY_DSA;
|
||||
} else if (sk_ASN1_TYPE_num(inkey) == 4) {
|
||||
keytype = EVP_PKEY_EC;
|
||||
} else if (sk_ASN1_TYPE_num(inkey) == 3) {
|
||||
/* This seems to be PKCS8, not traditional format */
|
||||
p = *inp;
|
||||
PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len);
|
||||
EVP_PKEY *ret;
|
||||
|
||||
sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
|
||||
if (!p8) {
|
||||
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
|
||||
if (len < 0) {
|
||||
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
ret = EVP_PKCS82PKEY(p8);
|
||||
PKCS8_PRIV_KEY_INFO_free(p8);
|
||||
|
||||
/* Count the elements to determine the format. */
|
||||
switch (num_elements(*inp, (size_t)len)) {
|
||||
case 3: {
|
||||
/* Parse the input as a PKCS#8 PrivateKeyInfo. */
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, *inp, (size_t)len);
|
||||
EVP_PKEY *ret = EVP_parse_private_key(&cbs);
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*inp = p;
|
||||
if (out) {
|
||||
if (out != NULL) {
|
||||
EVP_PKEY_free(*out);
|
||||
*out = ret;
|
||||
}
|
||||
*inp = CBS_data(&cbs);
|
||||
return ret;
|
||||
} else {
|
||||
keytype = EVP_PKEY_RSA;
|
||||
}
|
||||
|
||||
sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
|
||||
return d2i_PrivateKey(keytype, out, inp, len);
|
||||
case 4:
|
||||
return d2i_PrivateKey(EVP_PKEY_EC, out, inp, len);
|
||||
|
||||
case 6:
|
||||
return d2i_PrivateKey(EVP_PKEY_DSA, out, inp, len);
|
||||
|
||||
default:
|
||||
return d2i_PrivateKey(EVP_PKEY_RSA, out, inp, len);
|
||||
}
|
||||
}
|
||||
|
||||
int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) {
|
||||
|
Loading…
Reference in New Issue
Block a user