Skip to content

Commit 8e7e4a5

Browse files
nebeiddavidben
andauthored
BoringSSL: Don't support parameterless DSA keys in SPKIs AND Set an EVP_PKEY's algorithm and data together (#3057)
*Note*: to be rebased on #3056. ### Description of changes: #### BoringSSL commit google/boringssl@1bc58a3: "Don't support parameterless DSA keys in SPKIs" Changes (2 files): - **crypto/evp_extra/p_dsa_asn1.c** — Removed the `CBS_len(params) == 0` branch in `dsa_pub_decode` that created an empty `DSA_new()` without parameters. Parameterless DSA keys in `SubjectPublicKeyInfo` will no longer parse. This does not impact TLS, where we have never supported DSA. - **crypto/evp_extra/evp_tests.txt** — Updated the DSA-1024-SPKI-No-Params test to expect `DECODE_ERROR` instead of successful parsing. #### BoringSSL commit google/boringssl@b0ef87e: "Set an EVP_PKEY's algorithm and data together" Changes (8 files): - **crypto/fipsmodule/evp/evp.c** — Replaced `evp_pkey_set_method` with `evp_pkey_set0(pkey, method, pkey_data)` which sets `method`, `type`, and `data` atomically. Removed `free_it` from `pkey_set_type` (uses `evp_pkey_set0(pkey, NULL, NULL)` instead). `EVP_PKEY_new_raw_*` functions set `method` via `evp_pkey_set0` before calling callbacks. - In `evp_pkey_set0` implementation: BoringSSL doesn't have the `type` field — it derives the `type` from `ameth` at query time via `EVP_PKEY_id()`. AWS-LC stores type as a separate field that must be kept in sync. - **crypto/evp_extra/internal.h** — Updated declaration - **crypto/evp_extra/evp_asn1.c** — Moved `pub_decode`/`priv_decode` NULL checks earlier; set method via `evp_pkey_set0` before calling decode callbacks - **crypto/evp_extra/p_dh_asn1.c**, **crypto/evp_extra/p_x25519.c**, **crypto/fipsmodule/evp/p_ed25519.c** — Use `evp_pkey_set0` in keygen - **crypto/fipsmodule/evp/p_kem.c**, **crypto/fipsmodule/evp/p_pqdsa.c** — Create key first, then `evp_pkey_set0(pkey, method, key)` together ### Adaptations for AWS-LC: ed25519/x25519 set_priv_raw/set_pub_raw callbacks are shared with ed25519ph (AWS-LC specific), so the method must be set by the caller before invoking the callback, not by the callback itself. #### Details crypto/fipsmodule/evp/evp.c: - `EVP_PKEY_new_raw_private_key` — calls `evp_pkey_set0(ret, method, NULL)` then `method->set_priv_raw(...)` - `EVP_PKEY_new_raw_public_key` — calls `evp_pkey_set0(ret, method, NULL)` then `method->set_pub_raw(...)` crypto/evp_extra/evp_asn1.c: - `EVP_parse_public_key` — calls `evp_pkey_set0(ret, method, NULL)` then `method->pub_decode(...)` - `EVP_parse_private_key` — calls `evp_pkey_set0(ret, method, NULL)` then `method->priv_decode(...)` In BoringSSL's version, all four of these just called `method->callback(ret, ...)` directly (no `method` pre-setting), and the callbacks themselves called evp_pkey_set0. We couldn't do that because the ed25519 callbacks are shared with ed25519ph. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --------- Co-authored-by: David Benjamin <davidben@google.com>
1 parent e95148d commit 8e7e4a5

11 files changed

Lines changed: 51 additions & 78 deletions

File tree

crypto/evp_extra/evp_asn1.c

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,31 +77,25 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
7777
CBS oid;
7878

7979
const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm, &oid);
80-
if (method == NULL) {
80+
if (method == NULL || method->pub_decode == NULL) {
8181
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
8282
return NULL;
8383
}
84-
if (// Every key type defined encodes the key as a byte string with the same
85-
// conversion to BIT STRING.
86-
!CBS_get_u8(&key, &padding) ||
84+
// Every key type defined encodes the key as a byte string with the same
85+
// conversion to BIT STRING, so perform that common conversion ahead of time.
86+
if (!CBS_get_u8(&key, &padding) ||
8787
padding != 0) {
8888
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
8989
return NULL;
9090
}
9191

92-
// Set up an |EVP_PKEY| of the appropriate type.
9392
EVP_PKEY *ret = EVP_PKEY_new();
9493
if (ret == NULL) {
9594
goto err;
9695
}
97-
evp_pkey_set_method(ret, method);
96+
evp_pkey_set0(ret, method, NULL);
9897

99-
// Call into the type-specific SPKI decoding function.
100-
if (ret->ameth->pub_decode == NULL) {
101-
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
102-
goto err;
103-
}
104-
if (!ret->ameth->pub_decode(ret, &oid, &algorithm, &key)) {
98+
if (!method->pub_decode(ret, &oid, &algorithm, &key)) {
10599
goto err;
106100
}
107101

@@ -145,7 +139,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
145139
CBS oid;
146140

147141
const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm, &oid);
148-
if (method == NULL) {
142+
if (method == NULL || method->priv_decode == NULL) {
149143
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
150144
return NULL;
151145
}
@@ -177,16 +171,10 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
177171
if (ret == NULL) {
178172
goto err;
179173
}
180-
evp_pkey_set_method(ret, method);
181-
182-
// Call into the type-specific PrivateKeyInfo decoding function.
183-
if (ret->ameth->priv_decode == NULL) {
184-
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
185-
goto err;
186-
}
174+
evp_pkey_set0(ret, method, NULL);
187175

188-
if (!ret->ameth->priv_decode(ret, &oid, &algorithm, &key,
189-
has_pub ? &public_key : NULL)) {
176+
if (!method->priv_decode(ret, &oid, &algorithm, &key,
177+
has_pub ? &public_key : NULL)) {
190178
goto err;
191179
}
192180

crypto/evp_extra/evp_tests.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,11 @@ Input = 308201b73082012c06072a8648ce3804013082011f02818100b3429b8b128c9079f9b72e
208208
ExpectNoRawPrivate
209209
ExpectNoRawPublic
210210

211-
# The same key as above, but without the parameters.
211+
# The same key as above, but without the parameters. Although allowed by
212+
# RFC 3279, we do not support this.
212213
PublicKey = DSA-1024-SPKI-No-Params
213-
Type = DSA
214214
Input = 308192300906072a8648ce38040103818400028180258c30ebbb7f34fdc873ce679f6cea373c7886d75d4421b90920db034daedd292c64d8edd8cdbdd7f3ad23d74cfa2135247d0cef6ecf2e14f99e19d22a8c1266bd8fb8719c0e5667c716c45c7adbdabe548085bdad2dfee636f8d52fd6adb2193df6c4f0520fbd171b91882e0e4f321f8250ffecf4dbea00e114427d3ef96c1a
215-
ExpectNoRawPrivate
216-
ExpectNoRawPublic
215+
Error = DECODE_ERROR
217216

218217
# DSA 1024 PKCS#8 v2 decoding with public key not supported
219218
PrivateKey = DSA-1024-WithPublicKey

crypto/evp_extra/internal.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ extern const EVP_PKEY_METHOD dh_pkey_meth;
4141
extern const EVP_PKEY_METHOD dsa_pkey_meth;
4242
extern const EVP_PKEY_METHOD pqdsa_pkey_meth;
4343

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

4850
// Returns a reference to the list |non_fips_pkey_evp_methods|. The list has
4951
// size |NON_FIPS_EVP_PKEY_METHODS|.

crypto/evp_extra/p_dh_asn1.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,8 @@ int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
180180

181181
int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) {
182182
SET_DIT_AUTO_RESET
183-
if (key == NULL) {
184-
return 0;
185-
}
186-
evp_pkey_set_method(pkey, &dh_asn1_meth);
187-
pkey->pkey.dh = key;
183+
GUARD_PTR(key);
184+
evp_pkey_set0(pkey, &dh_asn1_meth, key);
188185
return 1;
189186
}
190187

crypto/evp_extra/p_dsa_asn1.c

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,12 @@
1616

1717

1818
static int dsa_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
19-
// See RFC 3279, section 2.3.2.
20-
21-
// Parameters may or may not be present.
22-
DSA *dsa;
23-
if (CBS_len(params) == 0) {
24-
dsa = DSA_new();
25-
if (dsa == NULL) {
26-
return 0;
27-
}
28-
} else {
29-
dsa = DSA_parse_parameters(params);
30-
if (dsa == NULL || CBS_len(params) != 0) {
31-
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
32-
goto err;
33-
}
19+
// See RFC 3279, section 2.3.2. Although RFC 3279 allows DSA parameters to be
20+
// omitted, we require them to be present.
21+
DSA *dsa = DSA_parse_parameters(params);
22+
if (dsa == NULL || CBS_len(params) != 0) {
23+
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
24+
goto err;
3425
}
3526

3627
dsa->pub_key = BN_new();

crypto/evp_extra/p_x25519.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,10 @@ static int pkey_x25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
2020
return 0;
2121
}
2222

23-
evp_pkey_set_method(pkey, &x25519_asn1_meth);
24-
2523
X25519_keypair(key->pub, key->priv);
2624
key->has_private = 1;
2725

28-
OPENSSL_free(pkey->pkey.ptr);
29-
pkey->pkey.ptr = key;
26+
evp_pkey_set0(pkey, &x25519_asn1_meth, key);
3027
return 1;
3128
}
3229

crypto/fipsmodule/evp/evp.c

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ int EVP_read_pw_string_min(char *buf, int min_length, int length,
183183
int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
184184
SET_DIT_AUTO_RESET;
185185
if (to->type == EVP_PKEY_NONE) {
186-
evp_pkey_set_method(to, from->ameth);
186+
// TODO(crbug.com/42290409): This shouldn't leave |to| in a half-empty state
187+
// on error. The complexity here largely comes from parameterless DSA keys,
188+
// which we no longer support, so this function can probably be trimmed
189+
// down.
190+
evp_pkey_set0(to, from->ameth, NULL);
187191
} else if (to->type != from->type) {
188192
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
189193
return 0;
@@ -293,18 +297,20 @@ static const EVP_PKEY_ASN1_METHOD *evp_pkey_asn1_find(int nid) {
293297
return NULL;
294298
}
295299

296-
void evp_pkey_set_method(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method) {
300+
void evp_pkey_set0(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method,
301+
void *pkey_data) {
297302
free_it(pkey);
298303
pkey->ameth = method;
299-
pkey->type = pkey->ameth->pkey_id;
304+
pkey->type = method ? method->pkey_id : EVP_PKEY_NONE;
305+
pkey->pkey.ptr = pkey_data;
300306
}
301307

302308
static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) {
303309
if (pkey && pkey->pkey.ptr) {
304310
// This isn't strictly necessary, but historically |EVP_PKEY_set_type| would
305311
// clear |pkey| even if |evp_pkey_asn1_find| failed, so we preserve that
306312
// behavior.
307-
free_it(pkey);
313+
evp_pkey_set0(pkey, NULL, NULL);
308314
}
309315

310316
const EVP_PKEY_ASN1_METHOD *ameth = NULL;
@@ -322,7 +328,7 @@ static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) {
322328
}
323329

324330
if (pkey) {
325-
evp_pkey_set_method(pkey, ameth);
331+
evp_pkey_set0(pkey, ameth, NULL);
326332
}
327333

328334
return 1;
@@ -393,8 +399,7 @@ int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) {
393399
}
394400
const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_RSA);
395401
assert(meth != NULL);
396-
evp_pkey_set_method(pkey, meth);
397-
pkey->pkey.ptr = key;
402+
evp_pkey_set0(pkey, meth, key);
398403
return 1;
399404
}
400405

@@ -432,8 +437,7 @@ int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) {
432437
}
433438
const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_DSA);
434439
assert(meth != NULL);
435-
evp_pkey_set_method(pkey, meth);
436-
pkey->pkey.ptr = key;
440+
evp_pkey_set0(pkey, meth, key);
437441
return 1;
438442
}
439443

@@ -471,8 +475,7 @@ int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
471475
}
472476
const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_EC);
473477
assert(meth != NULL);
474-
evp_pkey_set_method(pkey, meth);
475-
pkey->pkey.ptr = key;
478+
evp_pkey_set0(pkey, meth, key);
476479
return 1;
477480
}
478481

@@ -555,9 +558,9 @@ EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *unused,
555558
if (ret == NULL) {
556559
goto err;
557560
}
558-
evp_pkey_set_method(ret, method);
561+
evp_pkey_set0(ret, method, NULL);
559562

560-
if (!ret->ameth->set_priv_raw(ret, in, len, NULL, 0)) {
563+
if (!method->set_priv_raw(ret, in, len, NULL, 0)) {
561564
goto err;
562565
}
563566

@@ -592,9 +595,9 @@ EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *unused,
592595
if (ret == NULL) {
593596
goto err;
594597
}
595-
evp_pkey_set_method(ret, method);
598+
evp_pkey_set0(ret, method, NULL);
596599

597-
if (!ret->ameth->set_pub_raw(ret, in, len)) {
600+
if (!method->set_pub_raw(ret, in, len)) {
598601
goto err;
599602
}
600603

crypto/fipsmodule/evp/p_ed25519.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <openssl/mem.h>
99

1010
#include "internal.h"
11+
#include "../../evp_extra/internal.h"
1112
#include "../curve25519/internal.h"
1213

1314

@@ -20,14 +21,13 @@ static int pkey_ed25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
2021
return 0;
2122
}
2223

23-
evp_pkey_set_method(pkey, &ed25519_asn1_meth);
24-
2524
uint8_t pubkey_unused[32];
2625
int result = ED25519_keypair_internal(pubkey_unused, key->key);
2726
if (result) {
2827
key->has_private = 1;
29-
OPENSSL_free(pkey->pkey.ptr);
30-
pkey->pkey.ptr = key;
28+
evp_pkey_set0(pkey, &ed25519_asn1_meth, key);
29+
} else {
30+
OPENSSL_free(key);
3131
}
3232

3333
return result;

crypto/fipsmodule/evp/p_kem.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,16 +411,14 @@ int EVP_PKEY_kem_set_params(EVP_PKEY *pkey, int nid) {
411411
return 0;
412412
}
413413

414-
evp_pkey_set_method(pkey, &kem_asn1_meth);
415-
416414
KEM_KEY *key = KEM_KEY_new();
417415
if (key == NULL) {
418416
// KEM_KEY_new sets the appropriate error.
419417
return 0;
420418
}
421419

422420
key->kem = kem;
423-
pkey->pkey.kem_key = key;
421+
evp_pkey_set0(pkey, &kem_asn1_meth, key);
424422

425423
return 1;
426424
}

crypto/fipsmodule/evp/p_pqdsa.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,16 +233,14 @@ int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid) {
233233
return 0;
234234
}
235235

236-
evp_pkey_set_method(pkey, &pqdsa_asn1_meth);
237-
238236
PQDSA_KEY *key = PQDSA_KEY_new();
239237
if (key == NULL) {
240238
// PQDSA_KEY_new sets the appropriate error.
241239
return 0;
242240
}
243241

244242
key->pqdsa = pqdsa;
245-
pkey->pkey.pqdsa_key = key;
243+
evp_pkey_set0(pkey, &pqdsa_asn1_meth, key);
246244

247245
return 1;
248246
}

0 commit comments

Comments
 (0)