Skip to content

Commit b0ef87e

Browse files
davidbenBoringssl LUCI CQ
authored andcommitted
Set an EVP_PKEY's algorithm and data together
We internally half-initialize EVP_PKEYs everywhere, but there are very few places where we actually need to half-initialize them. This changes most of the EVP_PKEY_ASN1_METHOD callbacks so that output EVP_PKEYs are not half-initialized with the method first. Rather, the callback is expected to fill in the method and contents together. EVP_PKEY_copy_parameters remains as a goofy exception because it's an in-out parameter. In principle, it is possible to have a goofy parameter-less, key-only DSA object, and we need to fill in the parameters later. This was due to how DSA was embedded into X.509. But we don't support DSA in X.509 and we removed this parameterless state from the parser, so we probably can remove this now. (I've left it as-is for now.) Bug: 42290409 Change-Id: I2a576571d75ce755fd7e963be467aa5d94f20466 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/81550 Auto-Submit: David Benjamin <davidben@google.com> Reviewed-by: Lily Chen <chlily@google.com> Commit-Queue: Lily Chen <chlily@google.com>
1 parent 5b7171f commit b0ef87e

File tree

11 files changed

+43
-87
lines changed

11 files changed

+43
-87
lines changed

crypto/evp/evp.cc

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,6 @@ EVP_PKEY *EVP_PKEY_new(void) {
4545
return ret;
4646
}
4747

48-
static void free_it(EVP_PKEY *pkey) {
49-
if (pkey->ameth && pkey->ameth->pkey_free) {
50-
pkey->ameth->pkey_free(pkey);
51-
}
52-
pkey->pkey = nullptr;
53-
pkey->ameth = nullptr;
54-
}
55-
5648
void EVP_PKEY_free(EVP_PKEY *pkey) {
5749
if (pkey == NULL) {
5850
return;
@@ -62,7 +54,7 @@ void EVP_PKEY_free(EVP_PKEY *pkey) {
6254
return;
6355
}
6456

65-
free_it(pkey);
57+
evp_pkey_set0(pkey, nullptr, nullptr);
6658
OPENSSL_free(pkey);
6759
}
6860

@@ -103,7 +95,11 @@ int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
10395

10496
int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
10597
if (EVP_PKEY_id(to) == EVP_PKEY_NONE) {
106-
evp_pkey_set_method(to, from->ameth);
98+
// TODO(crbug.com/42290409): This shouldn't leave |to| in a half-empty state
99+
// on error. The complexity here largely comes from parameterless DSA keys,
100+
// which we no longer support, so this function can probably be trimmed
101+
// down.
102+
evp_pkey_set0(to, from->ameth, nullptr);
107103
} else if (EVP_PKEY_id(to) != EVP_PKEY_id(from)) {
108104
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
109105
return 0;
@@ -127,8 +123,9 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
127123
return from->ameth->param_copy(to, from);
128124
}
129125

130-
// TODO(https://crbug.com/boringssl/536): If the algorithm takes no
131-
// parameters, copying them should vacuously succeed.
126+
// TODO(https://crbug.com/42290406): If the algorithm takes no parameters,
127+
// copying them should vacuously succeed. Better yet, simplify this whole
128+
// notion of parameter copying above.
132129
return 0;
133130
}
134131

@@ -157,9 +154,13 @@ int EVP_PKEY_id(const EVP_PKEY *pkey) {
157154
return pkey->ameth != nullptr ? pkey->ameth->pkey_id : EVP_PKEY_NONE;
158155
}
159156

160-
void evp_pkey_set_method(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method) {
161-
free_it(pkey);
157+
void evp_pkey_set0(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method,
158+
void *pkey_data) {
159+
if (pkey->ameth && pkey->ameth->pkey_free) {
160+
pkey->ameth->pkey_free(pkey);
161+
}
162162
pkey->ameth = method;
163+
pkey->pkey = pkey_data;
163164
}
164165

165166
int EVP_PKEY_type(int nid) {
@@ -192,7 +193,7 @@ int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
192193
if (pkey && pkey->pkey) {
193194
// Some callers rely on |pkey| getting cleared even if |type| is
194195
// unsupported, usually setting |type| to |EVP_PKEY_NONE|.
195-
free_it(pkey);
196+
evp_pkey_set0(pkey, nullptr, nullptr);
196197
}
197198

198199
// This function broadly isn't useful. It initializes |EVP_PKEY| for a type,
@@ -209,7 +210,7 @@ int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
209210
}
210211

211212
if (pkey) {
212-
evp_pkey_set_method(pkey, ameth);
213+
evp_pkey_set0(pkey, ameth, nullptr);
213214
}
214215

215216
return 1;
@@ -233,12 +234,8 @@ EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *unused,
233234
}
234235

235236
bssl::UniquePtr<EVP_PKEY> ret(EVP_PKEY_new());
236-
if (ret == nullptr) {
237-
return nullptr;
238-
}
239-
evp_pkey_set_method(ret.get(), method);
240-
241-
if (!ret->ameth->set_priv_raw(ret.get(), in, len)) {
237+
if (ret == nullptr || //
238+
!method->set_priv_raw(ret.get(), in, len)) {
242239
return nullptr;
243240
}
244241

@@ -263,12 +260,8 @@ EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *unused,
263260
}
264261

265262
bssl::UniquePtr<EVP_PKEY> ret(EVP_PKEY_new());
266-
if (ret == nullptr) {
267-
return nullptr;
268-
}
269-
evp_pkey_set_method(ret.get(), method);
270-
271-
if (!ret->ameth->set_pub_raw(ret.get(), in, len)) {
263+
if (ret == nullptr || //
264+
!method->set_pub_raw(ret.get(), in, len)) {
272265
return nullptr;
273266
}
274267

crypto/evp/evp_asn1.cc

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -65,31 +65,19 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
6565
return nullptr;
6666
}
6767
const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm);
68-
if (method == nullptr) {
68+
if (method == nullptr || method->pub_decode == nullptr) {
6969
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
7070
return nullptr;
7171
}
72-
if (// Every key type defined encodes the key as a byte string with the same
73-
// conversion to BIT STRING.
74-
!CBS_get_u8(&key, &padding) ||
75-
padding != 0) {
72+
// Every key type defined encodes the key as a byte string with the same
73+
// conversion to BIT STRING, so perform that common conversion ahead of time.
74+
if (!CBS_get_u8(&key, &padding) || padding != 0) {
7675
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
7776
return nullptr;
7877
}
7978

80-
// Set up an |EVP_PKEY| of the appropriate type.
8179
bssl::UniquePtr<EVP_PKEY> ret(EVP_PKEY_new());
82-
if (ret == nullptr) {
83-
return nullptr;
84-
}
85-
evp_pkey_set_method(ret.get(), method);
86-
87-
// Call into the type-specific SPKI decoding function.
88-
if (ret->ameth->pub_decode == nullptr) {
89-
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
90-
return nullptr;
91-
}
92-
if (!ret->ameth->pub_decode(ret.get(), &algorithm, &key)) {
80+
if (ret == nullptr || !method->pub_decode(ret.get(), &algorithm, &key)) {
9381
return nullptr;
9482
}
9583

@@ -118,7 +106,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
118106
return nullptr;
119107
}
120108
const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm);
121-
if (method == nullptr) {
109+
if (method == nullptr || method->priv_decode == nullptr) {
122110
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
123111
return nullptr;
124112
}
@@ -127,17 +115,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
127115

128116
// Set up an |EVP_PKEY| of the appropriate type.
129117
bssl::UniquePtr<EVP_PKEY> ret(EVP_PKEY_new());
130-
if (ret == nullptr) {
131-
return nullptr;
132-
}
133-
evp_pkey_set_method(ret.get(), method);
134-
135-
// Call into the type-specific PrivateKeyInfo decoding function.
136-
if (ret->ameth->priv_decode == nullptr) {
137-
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
138-
return nullptr;
139-
}
140-
if (!ret->ameth->priv_decode(ret.get(), &algorithm, &key)) {
118+
if (ret == nullptr || !method->priv_decode(ret.get(), &algorithm, &key)) {
141119
return nullptr;
142120
}
143121

crypto/evp/internal.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,11 @@ extern const EVP_PKEY_CTX_METHOD x25519_pkey_meth;
259259
extern const EVP_PKEY_CTX_METHOD hkdf_pkey_meth;
260260
extern const EVP_PKEY_CTX_METHOD dh_pkey_meth;
261261

262-
// evp_pkey_set_method behaves like |EVP_PKEY_set_type|, but takes a pointer to
263-
// a method table. This avoids depending on every |EVP_PKEY_ASN1_METHOD|.
264-
void evp_pkey_set_method(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method);
262+
// evp_pkey_set0 sets |pkey|'s method to |method| and data to |pkey_data|,
263+
// freeing any key that may previously have been configured. This function takes
264+
// ownership of |pkey_data|, which must be of the type expected by |method|.
265+
void evp_pkey_set0(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method,
266+
void *pkey_data);
265267

266268

267269
#if defined(__cplusplus)

crypto/evp/p_dh_asn1.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) {
123123
if (key == nullptr) {
124124
return 0;
125125
}
126-
evp_pkey_set_method(pkey, &dh_asn1_meth);
127-
pkey->pkey = key;
126+
evp_pkey_set0(pkey, &dh_asn1_meth, key);
128127
return 1;
129128
}
130129

crypto/evp/p_dsa_asn1.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,7 @@ int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) {
254254
if (key == nullptr) {
255255
return 0;
256256
}
257-
evp_pkey_set_method(pkey, &dsa_asn1_meth);
258-
pkey->pkey = key;
257+
evp_pkey_set0(pkey, &dsa_asn1_meth, key);
259258
return 1;
260259
}
261260

crypto/evp/p_ec_asn1.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
268268
if (key == nullptr) {
269269
return 0;
270270
}
271-
evp_pkey_set_method(pkey, &ec_asn1_meth);
272-
pkey->pkey = key;
271+
evp_pkey_set0(pkey, &ec_asn1_meth, key);
273272
return 1;
274273
}
275274

crypto/evp/p_ed25519.cc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,11 @@ static int pkey_ed25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
3131
return 0;
3232
}
3333

34-
evp_pkey_set_method(pkey, &ed25519_asn1_meth);
35-
3634
uint8_t pubkey_unused[32];
3735
ED25519_keypair(pubkey_unused, key->key);
3836
key->has_private = 1;
3937

40-
OPENSSL_free(pkey->pkey);
41-
pkey->pkey = key;
38+
evp_pkey_set0(pkey, &ed25519_asn1_meth, key);
4239
return 1;
4340
}
4441

crypto/evp/p_ed25519_asn1.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,7 @@ static int ed25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
4545
uint8_t pubkey_unused[32];
4646
ED25519_keypair_from_seed(pubkey_unused, key->key, in);
4747
key->has_private = 1;
48-
49-
ed25519_free(pkey);
50-
pkey->pkey = key;
48+
evp_pkey_set0(pkey, &ed25519_asn1_meth, key);
5149
return 1;
5250
}
5351

@@ -65,9 +63,7 @@ static int ed25519_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
6563

6664
OPENSSL_memcpy(key->key + ED25519_PUBLIC_KEY_OFFSET, in, 32);
6765
key->has_private = 0;
68-
69-
ed25519_free(pkey);
70-
pkey->pkey = key;
66+
evp_pkey_set0(pkey, &ed25519_asn1_meth, key);
7167
return 1;
7268
}
7369

crypto/evp/p_rsa_asn1.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,7 @@ int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) {
179179
if (key == nullptr) {
180180
return 0;
181181
}
182-
evp_pkey_set_method(pkey, &rsa_asn1_meth);
183-
pkey->pkey = key;
182+
evp_pkey_set0(pkey, &rsa_asn1_meth, key);
184183
return 1;
185184
}
186185

crypto/evp/p_x25519.cc

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,9 @@ static int pkey_x25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
3131
return 0;
3232
}
3333

34-
evp_pkey_set_method(pkey, &x25519_asn1_meth);
35-
3634
X25519_keypair(key->pub, key->priv);
3735
key->has_private = 1;
38-
39-
OPENSSL_free(pkey->pkey);
40-
pkey->pkey = key;
36+
evp_pkey_set0(pkey, &x25519_asn1_meth, key);
4137
return 1;
4238
}
4339

0 commit comments

Comments
 (0)