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>
This commit is contained in:
David Benjamin 2015-12-30 21:40:40 -05:00 committed by Adam Langley
parent 2dc469e066
commit 68772b31b0
11 changed files with 333 additions and 213 deletions

View File

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

View File

@ -57,6 +57,7 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/asn1.h> #include <openssl/asn1.h>
#include <openssl/bytestring.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/obj.h> #include <openssl/obj.h>
#include <openssl/x509.h> #include <openssl/x509.h>
@ -64,6 +65,55 @@
#include "internal.h" #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, EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
long len) { long len) {
EVP_PKEY *ret; EVP_PKEY *ret;

View File

@ -71,6 +71,7 @@
#endif #endif
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <openssl/digest.h> #include <openssl/digest.h>
#include <openssl/err.h> #include <openssl/err.h>
@ -104,6 +105,20 @@ static const EVP_MD *GetDigest(FileTest *t, const std::string &name) {
return nullptr; 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>; using KeyMap = std::map<std::string, ScopedEVP_PKEY>;
// ImportPrivateKey evaluates a PrivateKey test in |t| and writes the resulting // 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; 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) { static bool TestEVP(FileTest *t, void *arg) {
KeyMap *key_map = reinterpret_cast<KeyMap*>(arg); KeyMap *key_map = reinterpret_cast<KeyMap*>(arg);
if (t->GetType() == "PrivateKey") { if (t->GetType() == "PrivateKey") {
return ImportPrivateKey(t, key_map); 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_init)(EVP_PKEY_CTX *ctx);
int (*key_op)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len, int (*key_op)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
const uint8_t *in, size_t in_len); const uint8_t *in, size_t in_len);

View File

@ -1,9 +1,8 @@
# Public key algorithm tests # Public key algorithm tests
# Private keys used for PKEY operations. # Keys used for PKEY operations.
# RSA 2048 bit key. # RSA 2048 bit key.
PrivateKey = RSA-2048 PrivateKey = RSA-2048
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDNAIHqeyrh6gbV MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDNAIHqeyrh6gbV
@ -34,8 +33,22 @@ SOamA2hu2OJWCl9q8fLCT69KqWDjghhvFe7c6aJJGucwaA3Uz3eLcPqoaCarMiNH
fMkTd7GabVourqIZdgvu1Q== fMkTd7GabVourqIZdgvu1Q==
-----END PRIVATE KEY----- -----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 PrivateKey = P-256
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiocvtiiTxNH/xbnw MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiocvtiiTxNH/xbnw
@ -43,6 +56,27 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiocvtiiTxNH/xbnw
+JQkBywnGX14szuSDpXNtmTpkNzwz+oNlOKo5q+dDlgFbmUxBJJbn+bJ +JQkBywnGX14szuSDpXNtmTpkNzwz+oNlOKo5q+dDlgFbmUxBJJbn+bJ
-----END PRIVATE KEY----- -----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 # RSA tests
Sign = RSA-2048 Sign = RSA-2048
@ -55,6 +89,11 @@ Digest = SHA1
Input = "0123456789ABCDEF1234" Input = "0123456789ABCDEF1234"
Output = c09d402423cbf233d26cae21f954547bc43fe80fd41360a0336cfdbe9aedad05bef6fd2eaee6cd60089a52482d4809a238149520df3bdde4cb9e23d9307b05c0a6f327052325a29adf2cc95b66523be7024e2a585c3d4db15dfbe146efe0ecdc0402e33fe5d40324ee96c5c3edd374a15cdc0f5d84aa243c0f07e188c6518fbfceae158a9943be398e31097da81b62074f626eff738be6160741d5a26957a482b3251fd85d8df78b98148459de10aa93305dbb4a5230aa1da291a9b0e481918f99b7638d72bb687f97661d304ae145d64a474437a4ef39d7b8059332ddeb07e92bf6e0e3acaf8afedc93795e4511737ec1e7aab6d5bc9466afc950c1c17b48ad Output = c09d402423cbf233d26cae21f954547bc43fe80fd41360a0336cfdbe9aedad05bef6fd2eaee6cd60089a52482d4809a238149520df3bdde4cb9e23d9307b05c0a6f327052325a29adf2cc95b66523be7024e2a585c3d4db15dfbe146efe0ecdc0402e33fe5d40324ee96c5c3edd374a15cdc0f5d84aa243c0f07e188c6518fbfceae158a9943be398e31097da81b62074f626eff738be6160741d5a26957a482b3251fd85d8df78b98148459de10aa93305dbb4a5230aa1da291a9b0e481918f99b7638d72bb687f97661d304ae145d64a474437a4ef39d7b8059332ddeb07e92bf6e0e3acaf8afedc93795e4511737ec1e7aab6d5bc9466afc950c1c17b48ad
Verify = RSA-2048-SPKI
Digest = SHA1
Input = "0123456789ABCDEF1234"
Output = c09d402423cbf233d26cae21f954547bc43fe80fd41360a0336cfdbe9aedad05bef6fd2eaee6cd60089a52482d4809a238149520df3bdde4cb9e23d9307b05c0a6f327052325a29adf2cc95b66523be7024e2a585c3d4db15dfbe146efe0ecdc0402e33fe5d40324ee96c5c3edd374a15cdc0f5d84aa243c0f07e188c6518fbfceae158a9943be398e31097da81b62074f626eff738be6160741d5a26957a482b3251fd85d8df78b98148459de10aa93305dbb4a5230aa1da291a9b0e481918f99b7638d72bb687f97661d304ae145d64a474437a4ef39d7b8059332ddeb07e92bf6e0e3acaf8afedc93795e4511737ec1e7aab6d5bc9466afc950c1c17b48ad
# Digest too long # Digest too long
Sign = RSA-2048 Sign = RSA-2048
Digest = SHA1 Digest = SHA1
@ -125,6 +164,11 @@ Digest = SHA1
Input = "0123456789ABCDEF1234" Input = "0123456789ABCDEF1234"
Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8 Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8
Verify = P-256-SPKI
Digest = SHA1
Input = "0123456789ABCDEF1234"
Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8
# Digest too long # Digest too long
Verify = P-256 Verify = P-256
Digest = SHA1 Digest = SHA1

View File

@ -90,8 +90,19 @@ struct evp_pkey_asn1_method_st {
const char *pem_str; const char *pem_str;
int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub); /* pub_decode decodes |params| and |key| as a SubjectPublicKeyInfo
int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk); * 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_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx);

View File

@ -55,6 +55,8 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#include <limits.h>
#include <openssl/asn1.h> #include <openssl/asn1.h>
#include <openssl/asn1t.h> #include <openssl/asn1t.h>
#include <openssl/digest.h> #include <openssl/digest.h>
@ -67,113 +69,63 @@
#include "internal.h" #include "internal.h"
static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { static int dsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
const uint8_t *p, *pm; /* See RFC 3279, section 2.3.2. */
int pklen, pmlen;
int ptype;
void *pval;
ASN1_STRING *pstr;
X509_ALGOR *palg;
ASN1_INTEGER *public_key = NULL;
DSA *dsa = NULL; /* Parameters may or may not be present. */
DSA *dsa;
if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) { if (CBS_len(params) == 0) {
return 0; dsa = DSA_new();
}
X509_ALGOR_get0(NULL, &ptype, &pval, palg);
if (ptype == V_ASN1_SEQUENCE) {
pstr = pval;
pm = pstr->data;
pmlen = pstr->length;
dsa = d2i_DSAparams(NULL, &pm, pmlen);
if (dsa == NULL) { if (dsa == NULL) {
return 0;
}
} else {
dsa = DSA_parse_parameters(params);
if (dsa == NULL || CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err; goto err;
} }
} else if (ptype == V_ASN1_NULL || ptype == V_ASN1_UNDEF) { }
dsa = DSA_new();
if (dsa == NULL) { dsa->pub_key = BN_new();
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); if (dsa->pub_key == NULL) {
goto err;
}
} else {
OPENSSL_PUT_ERROR(EVP, EVP_R_PARAMETER_ENCODING_ERROR);
goto err; goto err;
} }
public_key = d2i_ASN1_INTEGER(NULL, &p, pklen); if (!BN_parse_asn1_unsigned(key, dsa->pub_key) ||
if (public_key == NULL) { CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err; goto err;
} }
dsa->pub_key = ASN1_INTEGER_to_BN(public_key, NULL); EVP_PKEY_assign_DSA(out, dsa);
if (dsa->pub_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BN_DECODE_ERROR);
goto err;
}
ASN1_INTEGER_free(public_key);
EVP_PKEY_assign_DSA(pkey, dsa);
return 1; return 1;
err: err:
ASN1_INTEGER_free(public_key);
DSA_free(dsa); DSA_free(dsa);
return 0; return 0;
} }
static int dsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) {
DSA *dsa; const DSA *dsa = key->pkey.dsa;
ASN1_STRING *pval = NULL; const int has_params = dsa->p != NULL && dsa->q != NULL && dsa->g != NULL;
uint8_t *penc = NULL;
int penclen;
dsa = pkey->pkey.dsa; /* See RFC 5480, section 2. */
CBB spki, algorithm, key_bitstring;
int ptype; if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
if (dsa->p && dsa->q && dsa->g) { !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
pval = ASN1_STRING_new(); !OBJ_nid2cbb(&algorithm, NID_dsa) ||
if (!pval) { (has_params &&
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); !DSA_marshal_parameters(&algorithm, dsa)) ||
goto err; !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
} !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
pval->length = i2d_DSAparams(dsa, &pval->data); !BN_marshal_asn1(&key_bitstring, dsa->pub_key) ||
if (pval->length <= 0) { !CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
goto err; return 0;
}
ptype = V_ASN1_SEQUENCE;
} else {
ptype = V_ASN1_UNDEF;
} }
ASN1_INTEGER *pubint = BN_to_ASN1_INTEGER(dsa->pub_key, NULL); return 1;
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;
}
err:
OPENSSL_free(penc);
ASN1_STRING_free(pval);
return 0;
} }
static int dsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { static int dsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {

View File

@ -57,6 +57,7 @@
#include <openssl/asn1t.h> #include <openssl/asn1t.h>
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/ec.h> #include <openssl/ec.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/mem.h> #include <openssl/mem.h>
@ -86,82 +87,65 @@ static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) {
return 1; return 1;
} }
static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) {
EC_KEY *ec_key = pkey->pkey.ec; const EC_KEY *ec_key = key->pkey.ec;
void *pval = NULL; const EC_GROUP *group = EC_KEY_get0_group(ec_key);
int ptype; int curve_nid = EC_GROUP_get_curve_name(group);
uint8_t *penc = NULL, *p; if (curve_nid == NID_undef) {
int penclen; OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
if (!eckey_param2type(&ptype, &pval, ec_key)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
return 0; return 0;
} }
penclen = i2o_ECPublicKey(ec_key, NULL); const EC_POINT *public_key = EC_KEY_get0_public_key(ec_key);
if (penclen <= 0) {
goto err; /* See RFC 5480, section 2. */
} CBB spki, algorithm, key_bitstring;
penc = OPENSSL_malloc(penclen); if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
if (!penc) { !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
goto err; !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) ||
} !OBJ_nid2cbb(&algorithm, curve_nid) ||
p = penc; !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
penclen = i2o_ECPublicKey(ec_key, &p); !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
if (penclen <= 0) { !EC_POINT_point2cbb(&key_bitstring, group, public_key,
goto err; POINT_CONVERSION_UNCOMPRESSED, NULL) ||
} !CBB_flush(out)) {
if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC), ptype, pval, penc, OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
penclen)) { return 0;
return 1;
} }
err: return 1;
if (ptype == V_ASN1_OBJECT) {
ASN1_OBJECT_free(pval);
} else {
ASN1_STRING_free(pval);
}
if (penc) {
OPENSSL_free(penc);
}
return 0;
} }
static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { static int eckey_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
const uint8_t *p = NULL; /* See RFC 5480, section 2. */
void *pval;
int ptype, pklen;
EC_KEY *eckey = NULL;
X509_ALGOR *palg;
if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) { /* The parameters are a named curve. */
return 0; CBS named_curve;
} if (!CBS_get_asn1(params, &named_curve, CBS_ASN1_OBJECT) ||
X509_ALGOR_get0(NULL, &ptype, &pval, palg); CBS_len(params) != 0) {
if (ptype != V_ASN1_OBJECT) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0; 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) { if (eckey == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
return 0; return 0;
} }
/* We have parameters now set public key */ EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(eckey));
if (!o2i_ECPublicKey(&eckey, &p, pklen)) { if (point == NULL ||
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); !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; goto err;
} }
EVP_PKEY_assign_EC_KEY(pkey, eckey); EC_POINT_free(point);
EVP_PKEY_assign_EC_KEY(out, eckey);
return 1; return 1;
err: err:
if (eckey) { EC_POINT_free(point);
EC_KEY_free(eckey); EC_KEY_free(eckey);
}
return 0; return 0;
} }

View File

@ -69,26 +69,33 @@
#include "internal.h" #include "internal.h"
static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
uint8_t *encoded; /* See RFC 3279, section 2.3.1. */
size_t encoded_len; CBB spki, algorithm, null, key_bitstring;
if (!RSA_public_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) { if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
return 0; !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
} !OBJ_nid2cbb(&algorithm, NID_rsaEncryption) ||
!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA), V_ASN1_NULL, NULL, !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
encoded, encoded_len)) { !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
OPENSSL_free(encoded); !RSA_marshal_public_key(&key_bitstring, key->pkey.rsa) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0; return 0;
} }
return 1; return 1;
} }
static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
const uint8_t *p; /* See RFC 3279, section 2.3.1. */
int pklen;
if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey)) { /* 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; 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 * TODO(davidben): Switch this to the strict version in March 2016 or when
* Chromium can force client certificates down a different codepath, whichever * Chromium can force client certificates down a different codepath, whichever
* comes first. */ * comes first. */
CBS cbs; RSA *rsa = RSA_parse_public_key_buggy(key);
CBS_init(&cbs, p, pklen); if (rsa == NULL || CBS_len(key) != 0) {
RSA *rsa = RSA_parse_public_key_buggy(&cbs);
if (rsa == NULL || CBS_len(&cbs) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSA_free(rsa); RSA_free(rsa);
return 0; return 0;
} }
EVP_PKEY_assign_RSA(pkey, rsa); EVP_PKEY_assign_RSA(out, rsa);
return 1; return 1;
} }

View File

@ -111,7 +111,7 @@ class FileTest {
bool GetAttribute(std::string *out_value, const std::string &key); bool GetAttribute(std::string *out_value, const std::string &key);
// GetAttributeOrDie looks up the attribute with key |key| and aborts if it is // 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); const std::string &GetAttributeOrDie(const std::string &key);
// GetBytes looks up the attribute with key |key| and decodes it as a byte // GetBytes looks up the attribute with key |key| and decodes it as a byte

View File

@ -54,8 +54,11 @@
* copied and put under another distribution licence * copied and put under another distribution licence
* [including the GNU Public Licence.] */ * [including the GNU Public Licence.] */
#include <limits.h>
#include <openssl/asn1.h> #include <openssl/asn1.h>
#include <openssl/asn1t.h> #include <openssl/asn1t.h>
#include <openssl/bytestring.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/mem.h> #include <openssl/mem.h>
@ -63,7 +66,6 @@
#include <openssl/thread.h> #include <openssl/thread.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include "../evp/internal.h"
#include "../internal.h" #include "../internal.h"
/* Minor tweak to operation: free up EVP_PKEY */ /* 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) int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
{ {
X509_PUBKEY *pk = NULL; X509_PUBKEY *pk = NULL;
uint8_t *spki = NULL;
size_t spki_len;
if (x == NULL) if (x == NULL)
return (0); return (0);
if ((pk = X509_PUBKEY_new()) == NULL) CBB cbb;
goto error; if (!CBB_init(&cbb, 0) ||
!EVP_marshal_public_key(&cbb, pkey) ||
if (pkey->ameth) { !CBB_finish(&cbb, &spki, &spki_len) ||
if (pkey->ameth->pub_encode) { spki_len > LONG_MAX) {
if (!pkey->ameth->pub_encode(pk, pkey)) { CBB_cleanup(&cbb);
OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_ENCODE_ERROR); 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);
goto error; goto error;
} }
if (*x != NULL) const uint8_t *p = spki;
X509_PUBKEY_free(*x); 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;
}
OPENSSL_free(spki);
X509_PUBKEY_free(*x);
*x = pk; *x = pk;
return 1; return 1;
error: error:
if (pk != NULL) X509_PUBKEY_free(pk);
X509_PUBKEY_free(pk); OPENSSL_free(spki);
return 0; return 0;
} }
/* /* g_pubkey_lock is used to protect the initialisation of the |pkey| member of
* g_pubkey_lock is used to protect the initialisation of the |pkey| member * |X509_PUBKEY| objects. Really |X509_PUBKEY| should have a |CRYPTO_once_t|
* of |X509_PUBKEY| objects. Really |X509_PUBKEY| should have a * inside it for this, but |CRYPTO_once_t| is private and |X509_PUBKEY| is
* |CRYPTO_once_t| inside it for this, but |CRYPTO_once_t| is private and * not. */
* |X509_PUBKEY| is not.
*/
static struct CRYPTO_STATIC_MUTEX g_pubkey_lock = CRYPTO_STATIC_MUTEX_INIT; static struct CRYPTO_STATIC_MUTEX g_pubkey_lock = CRYPTO_STATIC_MUTEX_INIT;
EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
{ {
EVP_PKEY *ret = NULL; EVP_PKEY *ret = NULL;
uint8_t *spki = NULL;
if (key == NULL) if (key == NULL)
goto error; goto error;
@ -143,26 +144,16 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
} }
CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);
if (key->public_key == NULL) /* Re-encode the |X509_PUBKEY| to DER and parse it. */
goto error; int spki_len = i2d_X509_PUBKEY(key, &spki);
if (spki_len < 0) {
if ((ret = EVP_PKEY_new()) == NULL) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
goto error; goto error;
} }
CBS cbs;
if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm))) { CBS_init(&cbs, spki, (size_t)spki_len);
OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM); ret = EVP_parse_public_key(&cbs);
goto error; if (ret == NULL || CBS_len(&cbs) != 0) {
} OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_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);
goto error; goto error;
} }
@ -177,12 +168,13 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);
} }
OPENSSL_free(spki);
return EVP_PKEY_up_ref(ret); return EVP_PKEY_up_ref(ret);
error: error:
if (ret != NULL) OPENSSL_free(spki);
EVP_PKEY_free(ret); EVP_PKEY_free(ret);
return (NULL); return NULL;
} }
/* /*

View File

@ -188,6 +188,20 @@ OPENSSL_EXPORT int EVP_PKEY_cmp_parameters(const EVP_PKEY *a,
/* ASN.1 functions */ /* 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 /* 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 * |*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 * |*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_PARAMETER_ENCODING_ERROR 152
#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 153 #define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 153
#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 154 #define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 154
#define EVP_R_ENCODE_ERROR 155
#endif /* OPENSSL_HEADER_EVP_H */ #endif /* OPENSSL_HEADER_EVP_H */