Browse Source

Implement new SPKI parsers.

Many consumers need SPKI support (X.509, TLS, QUIC, WebCrypto), each
with different ways to set signature parameters. SPKIs themselves can
get complex with id-RSASSA-PSS keys which come with various constraints
in the key parameters. This suggests we want a common in-library
representation of an SPKI.

This adds two new functions EVP_parse_public_key and
EVP_marshal_public_key which converts EVP_PKEY to and from SPKI and
implements X509_PUBKEY functions with them. EVP_PKEY seems to have been
intended to be able to express the supported SPKI types with
full-fidelity, so these APIs will continue this.

This means future support for id-RSASSA-PSS would *not* repurpose
EVP_PKEY_RSA. I'm worried about code assuming EVP_PKEY_RSA implies
acting on the RSA* is legal. Instead, it'd add an EVP_PKEY_RSA_PSS and
the data pointer would be some (exposed, so the caller may still check
key size, etc.) RSA_PSS_KEY struct. Internally, the EVP_PKEY_CTX
implementation would enforce the key constraints. If RSA_PSS_KEY would
later need its own API, that code would move there, but that seems
unlikely.

Ideally we'd have a 1:1 correspondence with key OID, although we may
have to fudge things if mistakes happen in standardization. (Whether or
not X.509 reuses id-ecPublicKey for Ed25519, we'll give it a separate
EVP_PKEY type.)

DSA parsing hooks are still implemented, missing parameters and all for
now. This isn't any worse than before.

Decoupling from the giant crypto/obj OID table will be a later task.

BUG=522228

Change-Id: I0e3964edf20cb795a18b0991d17e5ca8bce3e28c
Reviewed-on: https://boringssl-review.googlesource.com/6861
Reviewed-by: Adam Langley <agl@google.com>
kris/onging/CECPQ3_patch15
David Benjamin 8 years ago
committed by Adam Langley
parent
commit
68772b31b0
11 changed files with 332 additions and 212 deletions
  1. +1
    -0
      crypto/err/evp.errordata
  2. +50
    -0
      crypto/evp/evp_asn1.c
  3. +66
    -0
      crypto/evp/evp_test.cc
  4. +47
    -3
      crypto/evp/evp_tests.txt
  5. +13
    -2
      crypto/evp/internal.h
  6. +37
    -85
      crypto/evp/p_dsa_asn1.c
  7. +40
    -56
      crypto/evp/p_ec_asn1.c
  8. +24
    -19
      crypto/evp/p_rsa_asn1.c
  9. +1
    -1
      crypto/test/file_test.h
  10. +38
    -46
      crypto/x509/x_pubkey.c
  11. +15
    -0
      include/openssl/evp.h

+ 1
- 0
crypto/err/evp.errordata View File

@@ -6,6 +6,7 @@ EVP,143,DECODE_ERROR
EVP,104,DIFFERENT_KEY_TYPES
EVP,105,DIFFERENT_PARAMETERS
EVP,147,DIGEST_AND_KEY_TYPE_NOT_SUPPORTED
EVP,155,ENCODE_ERROR
EVP,107,EXPECTING_AN_EC_KEY_KEY
EVP,141,EXPECTING_AN_RSA_KEY
EVP,109,EXPECTING_A_DH_KEY


+ 50
- 0
crypto/evp/evp_asn1.c View File

@@ -57,6 +57,7 @@
#include <openssl/evp.h>

#include <openssl/asn1.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/obj.h>
#include <openssl/x509.h>
@@ -64,6 +65,55 @@
#include "internal.h"


EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
/* Parse the SubjectPublicKeyInfo. */
CBS spki, algorithm, oid, key;
uint8_t padding;
if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBS_get_asn1(&spki, &key, CBS_ASN1_BITSTRING) ||
CBS_len(&spki) != 0 ||
/* Every key type defined encodes the key as a byte string with the same
* conversion to BIT STRING. */
!CBS_get_u8(&key, &padding) ||
padding != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}

/* Set up an |EVP_PKEY| of the appropriate type. */
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL ||
!EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) {
goto err;
}

/* Call into the type-specific SPKI decoding function. */
if (ret->ameth->pub_decode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
goto err;
}
if (!ret->ameth->pub_decode(ret, &algorithm, &key)) {
goto err;
}

return ret;

err:
EVP_PKEY_free(ret);
return NULL;
}

int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) {
if (key->ameth->pub_encode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}

return key->ameth->pub_encode(cbb, key);
}

EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
long len) {
EVP_PKEY *ret;


+ 66
- 0
crypto/evp/evp_test.cc View File

@@ -71,6 +71,7 @@
#endif

#include <openssl/bio.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/digest.h>
#include <openssl/err.h>
@@ -104,6 +105,20 @@ static const EVP_MD *GetDigest(FileTest *t, const std::string &name) {
return nullptr;
}

static int GetKeyType(FileTest *t, const std::string &name) {
if (name == "RSA") {
return EVP_PKEY_RSA;
}
if (name == "EC") {
return EVP_PKEY_EC;
}
if (name == "DSA") {
return EVP_PKEY_DSA;
}
t->PrintLine("Unknown key type: '%s'", name.c_str());
return EVP_PKEY_NONE;
}

using KeyMap = std::map<std::string, ScopedEVP_PKEY>;

// ImportPrivateKey evaluates a PrivateKey test in |t| and writes the resulting
@@ -128,12 +143,63 @@ static bool ImportPrivateKey(FileTest *t, KeyMap *key_map) {
return true;
}

static bool ImportPublicKey(FileTest *t, KeyMap *key_map) {
std::vector<uint8_t> input;
if (!t->GetBytes(&input, "Input")) {
return false;
}

CBS cbs;
CBS_init(&cbs, input.data(), input.size());
ScopedEVP_PKEY pkey(EVP_parse_public_key(&cbs));
if (!pkey) {
return false;
}

std::string key_type;
if (!t->GetAttribute(&key_type, "Type")) {
return false;
}
if (EVP_PKEY_id(pkey.get()) != GetKeyType(t, key_type)) {
t->PrintLine("Bad key type.");
return false;
}

// The encoding must round-trip.
ScopedCBB cbb;
uint8_t *spki;
size_t spki_len;
if (!CBB_init(cbb.get(), 0) ||
!EVP_marshal_public_key(cbb.get(), pkey.get()) ||
!CBB_finish(cbb.get(), &spki, &spki_len)) {
return false;
}
ScopedOpenSSLBytes free_spki(spki);
if (!t->ExpectBytesEqual(input.data(), input.size(), spki, spki_len)) {
t->PrintLine("Re-encoding the SPKI did not match.");
return false;
}

// Save the key for future tests.
const std::string &key_name = t->GetParameter();
if (key_map->count(key_name) > 0) {
t->PrintLine("Duplicate key '%s'.", key_name.c_str());
return false;
}
(*key_map)[key_name] = std::move(pkey);
return true;
}

static bool TestEVP(FileTest *t, void *arg) {
KeyMap *key_map = reinterpret_cast<KeyMap*>(arg);
if (t->GetType() == "PrivateKey") {
return ImportPrivateKey(t, key_map);
}

if (t->GetType() == "PublicKey") {
return ImportPublicKey(t, key_map);
}

int (*key_op_init)(EVP_PKEY_CTX *ctx);
int (*key_op)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
const uint8_t *in, size_t in_len);


+ 47
- 3
crypto/evp/evp_tests.txt View File

@@ -1,9 +1,8 @@
# Public key algorithm tests

# Private keys used for PKEY operations.
# Keys used for PKEY operations.

# RSA 2048 bit key.

PrivateKey = RSA-2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDNAIHqeyrh6gbV
@@ -34,8 +33,22 @@ SOamA2hu2OJWCl9q8fLCT69KqWDjghhvFe7c6aJJGucwaA3Uz3eLcPqoaCarMiNH
fMkTd7GabVourqIZdgvu1Q==
-----END PRIVATE KEY-----

# EC P-256 key
# The public half of the same key encoded as a SubjectPublicKeyInfo.
PublicKey = RSA-2048-SPKI
Type = RSA
Input = 30820122300d06092a864886f70d01010105000382010f003082010a0282010100cd0081ea7b2ae1ea06d59f7c73d9ffb94a09615c2e4ba7c636cef08dd3533ec3185525b015c769b99a77d6725bf9c3532a9b6e5f6627d5fb85160768d3dda9cbd35974511717dc3d309d2fc47ee41f97e32adb7f9dd864a1c4767a666ecd71bc1aacf5e7517f4b38594fea9b05e42d5ada9912008013e45316a4d9bb8ed086b88d28758bacaf922d46a868b485d239c9baeb0e2b64592710f42b2d1ea0a4b4802c0becab328f8a68b0073bdb546feea9809d2849912b390c1532bc7e29c7658f8175fae46f34332ff87bcab3e40649b98577869da0ea718353f0722754886913648760d122be676e0fc483dd20ffc31bda96a31966c9aa2e75ad03de47e1c44f0203010001

# The same key but with missing parameters rather than a NULL.
PublicKey = RSA-2048-SPKI-Invalid
Input = 30820120300b06092a864886f70d0101010382010f003082010a0282010100cd0081ea7b2ae1ea06d59f7c73d9ffb94a09615c2e4ba7c636cef08dd3533ec3185525b015c769b99a77d6725bf9c3532a9b6e5f6627d5fb85160768d3dda9cbd35974511717dc3d309d2fc47ee41f97e32adb7f9dd864a1c4767a666ecd71bc1aacf5e7517f4b38594fea9b05e42d5ada9912008013e45316a4d9bb8ed086b88d28758bacaf922d46a868b485d239c9baeb0e2b64592710f42b2d1ea0a4b4802c0becab328f8a68b0073bdb546feea9809d2849912b390c1532bc7e29c7658f8175fae46f34332ff87bcab3e40649b98577869da0ea718353f0722754886913648760d122be676e0fc483dd20ffc31bda96a31966c9aa2e75ad03de47e1c44f0203010001
Error = DECODE_ERROR

# The same key but with an incorrectly-encoded length prefix.
PublicKey = RSA-2048-SPKI-Invalid2
Input = 3083000122300d06092a864886f70d01010105000382010f003082010a0282010100cd0081ea7b2ae1ea06d59f7c73d9ffb94a09615c2e4ba7c636cef08dd3533ec3185525b015c769b99a77d6725bf9c3532a9b6e5f6627d5fb85160768d3dda9cbd35974511717dc3d309d2fc47ee41f97e32adb7f9dd864a1c4767a666ecd71bc1aacf5e7517f4b38594fea9b05e42d5ada9912008013e45316a4d9bb8ed086b88d28758bacaf922d46a868b485d239c9baeb0e2b64592710f42b2d1ea0a4b4802c0becab328f8a68b0073bdb546feea9809d2849912b390c1532bc7e29c7658f8175fae46f34332ff87bcab3e40649b98577869da0ea718353f0722754886913648760d122be676e0fc483dd20ffc31bda96a31966c9aa2e75ad03de47e1c44f0203010001
Error = DECODE_ERROR

# EC P-256 key
PrivateKey = P-256
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiocvtiiTxNH/xbnw
@@ -43,6 +56,27 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiocvtiiTxNH/xbnw
+JQkBywnGX14szuSDpXNtmTpkNzwz+oNlOKo5q+dDlgFbmUxBJJbn+bJ
-----END PRIVATE KEY-----

# The public half of the same key encoded as a PublicKey.
PublicKey = P-256-SPKI
Type = EC
Input = 3059301306072a8648ce3d020106082a8648ce3d030107034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9

# The same as above, but with the curve explicitly spelled out.
PublicKey = P-256-SPKI
Input = 3082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551020101034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
Error = DECODE_ERROR

# A DSA key.
PublicKey = DSA-1024
Type = DSA
Input = 308201b73082012c06072a8648ce3804013082011f02818100b3429b8b128c9079f9b72e86857e98d265e5d91661ed8b5f4cc56e5eed1e571da30186983a9dd76297eab73ee13a1db841f8800d04a7cab478af6cde2ea4a2868531af169a24858c6268efa39ceb7ed0d4227eb5bbb01124a2a5a26038c7bcfb8cc827f68f5202345166e4718596799b65c9def82828ce44e62e38e41a0d24b1021500c5a56c81ddd87f47e676546c56d05706421624cf0281810094de40d27314fe929e47ff9b1ac65cfc73ef38c4d381c890be6217b15039ae18190e6b421af8c0bda35a5cfd050f58ae2644adce83e68c8e5ba11729df56bbb21e227a60b816cc033fa799a38fe1ba5b4aa1801b6f841ce3df99feb3b4fb96950c960af13fa2ce920aabc12dd24ad2044a35063ea0e25f67f560f4cfbdc5598303818400028180258c30ebbb7f34fdc873ce679f6cea373c7886d75d4421b90920db034daedd292c64d8edd8cdbdd7f3ad23d74cfa2135247d0cef6ecf2e14f99e19d22a8c1266bd8fb8719c0e5667c716c45c7adbdabe548085bdad2dfee636f8d52fd6adb2193df6c4f0520fbd171b91882e0e4f321f8250ffecf4dbea00e114427d3ef96c1a

# The same key as above, but without the parameters.
PublicKey = DSA-1024-No-Params
Type = DSA
Input = 308192300906072a8648ce38040103818400028180258c30ebbb7f34fdc873ce679f6cea373c7886d75d4421b90920db034daedd292c64d8edd8cdbdd7f3ad23d74cfa2135247d0cef6ecf2e14f99e19d22a8c1266bd8fb8719c0e5667c716c45c7adbdabe548085bdad2dfee636f8d52fd6adb2193df6c4f0520fbd171b91882e0e4f321f8250ffecf4dbea00e114427d3ef96c1a


# RSA tests

Sign = RSA-2048
@@ -55,6 +89,11 @@ Digest = SHA1
Input = "0123456789ABCDEF1234"
Output = c09d402423cbf233d26cae21f954547bc43fe80fd41360a0336cfdbe9aedad05bef6fd2eaee6cd60089a52482d4809a238149520df3bdde4cb9e23d9307b05c0a6f327052325a29adf2cc95b66523be7024e2a585c3d4db15dfbe146efe0ecdc0402e33fe5d40324ee96c5c3edd374a15cdc0f5d84aa243c0f07e188c6518fbfceae158a9943be398e31097da81b62074f626eff738be6160741d5a26957a482b3251fd85d8df78b98148459de10aa93305dbb4a5230aa1da291a9b0e481918f99b7638d72bb687f97661d304ae145d64a474437a4ef39d7b8059332ddeb07e92bf6e0e3acaf8afedc93795e4511737ec1e7aab6d5bc9466afc950c1c17b48ad

Verify = RSA-2048-SPKI
Digest = SHA1
Input = "0123456789ABCDEF1234"
Output = c09d402423cbf233d26cae21f954547bc43fe80fd41360a0336cfdbe9aedad05bef6fd2eaee6cd60089a52482d4809a238149520df3bdde4cb9e23d9307b05c0a6f327052325a29adf2cc95b66523be7024e2a585c3d4db15dfbe146efe0ecdc0402e33fe5d40324ee96c5c3edd374a15cdc0f5d84aa243c0f07e188c6518fbfceae158a9943be398e31097da81b62074f626eff738be6160741d5a26957a482b3251fd85d8df78b98148459de10aa93305dbb4a5230aa1da291a9b0e481918f99b7638d72bb687f97661d304ae145d64a474437a4ef39d7b8059332ddeb07e92bf6e0e3acaf8afedc93795e4511737ec1e7aab6d5bc9466afc950c1c17b48ad

# Digest too long
Sign = RSA-2048
Digest = SHA1
@@ -125,6 +164,11 @@ Digest = SHA1
Input = "0123456789ABCDEF1234"
Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8

Verify = P-256-SPKI
Digest = SHA1
Input = "0123456789ABCDEF1234"
Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8

# Digest too long
Verify = P-256
Digest = SHA1


+ 13
- 2
crypto/evp/internal.h View File

@@ -90,8 +90,19 @@ struct evp_pkey_asn1_method_st {

const char *pem_str;

int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub);
int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk);
/* pub_decode decodes |params| and |key| as a SubjectPublicKeyInfo
* and writes the result into |out|. It returns one on success and zero on
* error. |params| is the AlgorithmIdentifier after the OBJECT IDENTIFIER
* type field, and |key| is the contents of the subjectPublicKey with the
* leading padding byte checked and removed. Although X.509 uses BIT STRINGs
* to represent SubjectPublicKeyInfo, every key type defined encodes the key
* as a byte string with the same conversion to BIT STRING. */
int (*pub_decode)(EVP_PKEY *out, CBS *params, CBS *key);

/* pub_encode encodes |key| as a SubjectPublicKeyInfo and appends the result
* to |out|. It returns one on success and zero on error. */
int (*pub_encode)(CBB *out, const EVP_PKEY *key);

int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx);



+ 37
- 85
crypto/evp/p_dsa_asn1.c View File

@@ -55,6 +55,8 @@

#include <openssl/evp.h>

#include <limits.h>

#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/digest.h>
@@ -67,113 +69,63 @@
#include "internal.h"


static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
const uint8_t *p, *pm;
int pklen, pmlen;
int ptype;
void *pval;
ASN1_STRING *pstr;
X509_ALGOR *palg;
ASN1_INTEGER *public_key = NULL;

DSA *dsa = NULL;

if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) {
return 0;
}
X509_ALGOR_get0(NULL, &ptype, &pval, palg);

if (ptype == V_ASN1_SEQUENCE) {
pstr = pval;
pm = pstr->data;
pmlen = pstr->length;
static int dsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
/* See RFC 3279, section 2.3.2. */

dsa = d2i_DSAparams(NULL, &pm, pmlen);
if (dsa == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
} else if (ptype == V_ASN1_NULL || ptype == V_ASN1_UNDEF) {
/* Parameters may or may not be present. */
DSA *dsa;
if (CBS_len(params) == 0) {
dsa = DSA_new();
if (dsa == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
goto err;
return 0;
}
} else {
OPENSSL_PUT_ERROR(EVP, EVP_R_PARAMETER_ENCODING_ERROR);
goto err;
dsa = DSA_parse_parameters(params);
if (dsa == NULL || CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
}

public_key = d2i_ASN1_INTEGER(NULL, &p, pklen);
if (public_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
dsa->pub_key = BN_new();
if (dsa->pub_key == NULL) {
goto err;
}

dsa->pub_key = ASN1_INTEGER_to_BN(public_key, NULL);
if (dsa->pub_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BN_DECODE_ERROR);
if (!BN_parse_asn1_unsigned(key, dsa->pub_key) ||
CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}

ASN1_INTEGER_free(public_key);
EVP_PKEY_assign_DSA(pkey, dsa);
EVP_PKEY_assign_DSA(out, dsa);
return 1;

err:
ASN1_INTEGER_free(public_key);
DSA_free(dsa);
return 0;
}

static int dsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) {
DSA *dsa;
ASN1_STRING *pval = NULL;
uint8_t *penc = NULL;
int penclen;

dsa = pkey->pkey.dsa;

int ptype;
if (dsa->p && dsa->q && dsa->g) {
pval = ASN1_STRING_new();
if (!pval) {
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
goto err;
}
pval->length = i2d_DSAparams(dsa, &pval->data);
if (pval->length <= 0) {
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
goto err;
}
ptype = V_ASN1_SEQUENCE;
} else {
ptype = V_ASN1_UNDEF;
}

ASN1_INTEGER *pubint = BN_to_ASN1_INTEGER(dsa->pub_key, NULL);
if (pubint == NULL) {
goto err;
}

penclen = i2d_ASN1_INTEGER(pubint, &penc);
ASN1_INTEGER_free(pubint);

if (penclen <= 0) {
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
goto err;
}

if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DSA), ptype, pval,
penc, penclen)) {
return 1;
static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) {
const DSA *dsa = key->pkey.dsa;
const int has_params = dsa->p != NULL && dsa->q != NULL && dsa->g != NULL;

/* See RFC 5480, section 2. */
CBB spki, algorithm, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!OBJ_nid2cbb(&algorithm, NID_dsa) ||
(has_params &&
!DSA_marshal_parameters(&algorithm, dsa)) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!BN_marshal_asn1(&key_bitstring, dsa->pub_key) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}

err:
OPENSSL_free(penc);
ASN1_STRING_free(pval);

return 0;
return 1;
}

static int dsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {


+ 40
- 56
crypto/evp/p_ec_asn1.c View File

@@ -57,6 +57,7 @@

#include <openssl/asn1t.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
@@ -86,82 +87,65 @@ static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) {
return 1;
}

static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) {
EC_KEY *ec_key = pkey->pkey.ec;
void *pval = NULL;
int ptype;
uint8_t *penc = NULL, *p;
int penclen;

if (!eckey_param2type(&ptype, &pval, ec_key)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) {
const EC_KEY *ec_key = key->pkey.ec;
const EC_GROUP *group = EC_KEY_get0_group(ec_key);
int curve_nid = EC_GROUP_get_curve_name(group);
if (curve_nid == NID_undef) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
return 0;
}
penclen = i2o_ECPublicKey(ec_key, NULL);
if (penclen <= 0) {
goto err;
}
penc = OPENSSL_malloc(penclen);
if (!penc) {
goto err;
}
p = penc;
penclen = i2o_ECPublicKey(ec_key, &p);
if (penclen <= 0) {
goto err;
}
if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC), ptype, pval, penc,
penclen)) {
return 1;
const EC_POINT *public_key = EC_KEY_get0_public_key(ec_key);

/* See RFC 5480, section 2. */
CBB spki, algorithm, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) ||
!OBJ_nid2cbb(&algorithm, curve_nid) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!EC_POINT_point2cbb(&key_bitstring, group, public_key,
POINT_CONVERSION_UNCOMPRESSED, NULL) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}

err:
if (ptype == V_ASN1_OBJECT) {
ASN1_OBJECT_free(pval);
} else {
ASN1_STRING_free(pval);
}
if (penc) {
OPENSSL_free(penc);
}
return 0;
return 1;
}

static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
const uint8_t *p = NULL;
void *pval;
int ptype, pklen;
EC_KEY *eckey = NULL;
X509_ALGOR *palg;
static int eckey_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
/* See RFC 5480, section 2. */

if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) {
return 0;
}
X509_ALGOR_get0(NULL, &ptype, &pval, palg);

if (ptype != V_ASN1_OBJECT) {
/* The parameters are a named curve. */
CBS named_curve;
if (!CBS_get_asn1(params, &named_curve, CBS_ASN1_OBJECT) ||
CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
eckey = EC_KEY_new_by_curve_name(OBJ_obj2nid((ASN1_OBJECT *)pval));

EC_KEY *eckey = EC_KEY_new_by_curve_name(OBJ_cbs2nid(&named_curve));
if (eckey == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
return 0;
}

/* We have parameters now set public key */
if (!o2i_ECPublicKey(&eckey, &p, pklen)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(eckey));
if (point == NULL ||
!EC_POINT_oct2point(EC_KEY_get0_group(eckey), point, CBS_data(key),
CBS_len(key), NULL) ||
!EC_KEY_set_public_key(eckey, point)) {
goto err;
}

EVP_PKEY_assign_EC_KEY(pkey, eckey);
EC_POINT_free(point);
EVP_PKEY_assign_EC_KEY(out, eckey);
return 1;

err:
if (eckey) {
EC_KEY_free(eckey);
}
EC_POINT_free(point);
EC_KEY_free(eckey);
return 0;
}



+ 24
- 19
crypto/evp/p_rsa_asn1.c View File

@@ -69,26 +69,33 @@
#include "internal.h"


static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) {
uint8_t *encoded;
size_t encoded_len;
if (!RSA_public_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) {
return 0;
}

if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA), V_ASN1_NULL, NULL,
encoded, encoded_len)) {
OPENSSL_free(encoded);
static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
/* See RFC 3279, section 2.3.1. */
CBB spki, algorithm, null, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!OBJ_nid2cbb(&algorithm, NID_rsaEncryption) ||
!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!RSA_marshal_public_key(&key_bitstring, key->pkey.rsa) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}

return 1;
}

static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
const uint8_t *p;
int pklen;
if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey)) {
static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
/* See RFC 3279, section 2.3.1. */

/* The parameters must be NULL. */
CBS null;
if (!CBS_get_asn1(params, &null, CBS_ASN1_NULL) ||
CBS_len(&null) != 0 ||
CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}

@@ -98,16 +105,14 @@ static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
* TODO(davidben): Switch this to the strict version in March 2016 or when
* Chromium can force client certificates down a different codepath, whichever
* comes first. */
CBS cbs;
CBS_init(&cbs, p, pklen);
RSA *rsa = RSA_parse_public_key_buggy(&cbs);
if (rsa == NULL || CBS_len(&cbs) != 0) {
RSA *rsa = RSA_parse_public_key_buggy(key);
if (rsa == NULL || CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSA_free(rsa);
return 0;
}

EVP_PKEY_assign_RSA(pkey, rsa);
EVP_PKEY_assign_RSA(out, rsa);
return 1;
}



+ 1
- 1
crypto/test/file_test.h View File

@@ -111,7 +111,7 @@ class FileTest {
bool GetAttribute(std::string *out_value, const std::string &key);

// GetAttributeOrDie looks up the attribute with key |key| and aborts if it is
// missing. It only be used after a |HasAttribute| call.
// missing. It should only be used after a |HasAttribute| call.
const std::string &GetAttributeOrDie(const std::string &key);

// GetBytes looks up the attribute with key |key| and decodes it as a byte


+ 38
- 46
crypto/x509/x_pubkey.c View File

@@ -54,8 +54,11 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */

#include <limits.h>

#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
@@ -63,7 +66,6 @@
#include <openssl/thread.h>
#include <openssl/x509.h>

#include "../evp/internal.h"
#include "../internal.h"

/* Minor tweak to operation: free up EVP_PKEY */
@@ -87,51 +89,50 @@ IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY)
int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
{
X509_PUBKEY *pk = NULL;
uint8_t *spki = NULL;
size_t spki_len;

if (x == NULL)
return (0);

if ((pk = X509_PUBKEY_new()) == NULL)
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!EVP_marshal_public_key(&cbb, pkey) ||
!CBB_finish(&cbb, &spki, &spki_len) ||
spki_len > LONG_MAX) {
CBB_cleanup(&cbb);
OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_ENCODE_ERROR);
goto error;
}

if (pkey->ameth) {
if (pkey->ameth->pub_encode) {
if (!pkey->ameth->pub_encode(pk, pkey)) {
OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_ENCODE_ERROR);
goto error;
}
} else {
OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED);
goto error;
}
} else {
OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM);
const uint8_t *p = spki;
pk = d2i_X509_PUBKEY(NULL, &p, (long)spki_len);
if (pk == NULL || p != spki + spki_len) {
OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_ERROR);
goto error;
}

if (*x != NULL)
X509_PUBKEY_free(*x);

OPENSSL_free(spki);
X509_PUBKEY_free(*x);
*x = pk;

return 1;
error:
if (pk != NULL)
X509_PUBKEY_free(pk);
X509_PUBKEY_free(pk);
OPENSSL_free(spki);
return 0;
}

/*
* g_pubkey_lock is used to protect the initialisation of the |pkey| member
* of |X509_PUBKEY| objects. Really |X509_PUBKEY| should have a
* |CRYPTO_once_t| inside it for this, but |CRYPTO_once_t| is private and
* |X509_PUBKEY| is not.
*/
/* g_pubkey_lock is used to protect the initialisation of the |pkey| member of
* |X509_PUBKEY| objects. Really |X509_PUBKEY| should have a |CRYPTO_once_t|
* inside it for this, but |CRYPTO_once_t| is private and |X509_PUBKEY| is
* not. */
static struct CRYPTO_STATIC_MUTEX g_pubkey_lock = CRYPTO_STATIC_MUTEX_INIT;

EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
{
EVP_PKEY *ret = NULL;
uint8_t *spki = NULL;

if (key == NULL)
goto error;
@@ -143,26 +144,16 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
}
CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);

if (key->public_key == NULL)
goto error;

if ((ret = EVP_PKEY_new()) == NULL) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
/* Re-encode the |X509_PUBKEY| to DER and parse it. */
int spki_len = i2d_X509_PUBKEY(key, &spki);
if (spki_len < 0) {
goto error;
}

if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm))) {
OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM);
goto error;
}

if (ret->ameth->pub_decode) {
if (!ret->ameth->pub_decode(ret, key)) {
OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_ERROR);
goto error;
}
} else {
OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED);
CBS cbs;
CBS_init(&cbs, spki, (size_t)spki_len);
ret = EVP_parse_public_key(&cbs);
if (ret == NULL || CBS_len(&cbs) != 0) {
OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_ERROR);
goto error;
}

@@ -177,12 +168,13 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);
}

OPENSSL_free(spki);
return EVP_PKEY_up_ref(ret);

error:
if (ret != NULL)
EVP_PKEY_free(ret);
return (NULL);
OPENSSL_free(spki);
EVP_PKEY_free(ret);
return NULL;
}

/*


+ 15
- 0
include/openssl/evp.h View File

@@ -188,6 +188,20 @@ OPENSSL_EXPORT int EVP_PKEY_cmp_parameters(const EVP_PKEY *a,

/* ASN.1 functions */

/* EVP_parse_public_key decodes a DER-encoded SubjectPublicKeyInfo structure
* (RFC 5280) from |cbs| and advances |cbs|. It returns a newly-allocated
* |EVP_PKEY| or NULL on error.
*
* The caller must check the type of the parsed public key to ensure it is
* suitable and validate other desired key properties such as RSA modulus size
* or EC curve. */
OPENSSL_EXPORT EVP_PKEY *EVP_parse_public_key(CBS *cbs);

/* EVP_marshal_public_key marshals |key| as a DER-encoded SubjectPublicKeyInfo
* structure (RFC 5280) and appends the result to |cbb|. It returns one on
* success and zero on error. */
OPENSSL_EXPORT int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key);

/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at
* |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in
* |*out|. If |*out| is already non-NULL on entry then the result is written
@@ -780,5 +794,6 @@ struct evp_pkey_st {
#define EVP_R_PARAMETER_ENCODING_ERROR 152
#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 153
#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 154
#define EVP_R_ENCODE_ERROR 155

#endif /* OPENSSL_HEADER_EVP_H */

Loading…
Cancel
Save