Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@chromium.org>2015-12-31 05:40:40 +0300
committerAdam Langley <agl@google.com>2016-02-17 19:28:07 +0300
commit68772b31b07827793827e45ea81e8035269774c1 (patch)
treef9f661c29a375dfd4586e847b2a5ece92733de5f /crypto
parent2dc469e06655be3a761ee25b1d89b4f6ebfc29a4 (diff)
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>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/err/evp.errordata1
-rw-r--r--crypto/evp/evp_asn1.c50
-rw-r--r--crypto/evp/evp_test.cc66
-rw-r--r--crypto/evp/evp_tests.txt50
-rw-r--r--crypto/evp/internal.h15
-rw-r--r--crypto/evp/p_dsa_asn1.c122
-rw-r--r--crypto/evp/p_ec_asn1.c96
-rw-r--r--crypto/evp/p_rsa_asn1.c43
-rw-r--r--crypto/test/file_test.h2
-rw-r--r--crypto/x509/x_pubkey.c84
10 files changed, 317 insertions, 212 deletions
diff --git a/crypto/err/evp.errordata b/crypto/err/evp.errordata
index 8f8dd483..cfb81b15 100644
--- a/crypto/err/evp.errordata
+++ b/crypto/err/evp.errordata
@@ -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
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c
index da25b99a..e90bed5f 100644
--- a/crypto/evp/evp_asn1.c
+++ b/crypto/evp/evp_asn1.c
@@ -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;
diff --git a/crypto/evp/evp_test.cc b/crypto/evp/evp_test.cc
index 83906546..4e7b56e3 100644
--- a/crypto/evp/evp_test.cc
+++ b/crypto/evp/evp_test.cc
@@ -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);
diff --git a/crypto/evp/evp_tests.txt b/crypto/evp/evp_tests.txt
index 97ddaa0e..2320125e 100644
--- a/crypto/evp/evp_tests.txt
+++ b/crypto/evp/evp_tests.txt
@@ -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
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index 67b2a659..f2bad30a 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -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);
diff --git a/crypto/evp/p_dsa_asn1.c b/crypto/evp/p_dsa_asn1.c
index 9f97b163..62f2ac89 100644
--- a/crypto/evp/p_dsa_asn1.c
+++ b/crypto/evp/p_dsa_asn1.c
@@ -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) {
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
index e093c183..2d8d38a2 100644
--- a/crypto/evp/p_ec_asn1.c
+++ b/crypto/evp/p_ec_asn1.c
@@ -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;
}
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index 70f0b763..83da7df4 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -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;
}
diff --git a/crypto/test/file_test.h b/crypto/test/file_test.h
index 8fb7ed22..501375bc 100644
--- a/crypto/test/file_test.h
+++ b/crypto/test/file_test.h
@@ -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
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index e8732a11..47f256c7 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -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;
}
/*