Procházet zdrojové kódy

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 před 8 roky
committed by Adam Langley
rodič
revize
68772b31b0
11 změnil soubory, kde provedl 332 přidání a 212 odebrání
  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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 Zobrazit soubor

@@ -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 */

Načítá se…
Zrušit
Uložit