summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortb <>2024-10-18 17:27:07 +0000
committertb <>2024-10-18 17:27:07 +0000
commitd0a0731baa6c11e828c6eaf5bad6b696b7970bcc (patch)
tree21c2d8d99a6ad3f5138b72666bb9a53810ea3608 /src
parentff67d4fbe3dfed9b7d4e988f959ca076ed5b87ec (diff)
downloadopenbsd-d0a0731baa6c11e828c6eaf5bad6b696b7970bcc.tar.gz
openbsd-d0a0731baa6c11e828c6eaf5bad6b696b7970bcc.tar.bz2
openbsd-d0a0731baa6c11e828c6eaf5bad6b696b7970bcc.zip
Enforce that EC Parameters correspond to a builtin curve
EC parameters are very general. While there are some minimal sanity checks, for the parameters due to DoS risks found in the last decade, the elliptic curve code is poorly written and a target rich environment for NULL dereferences, busy loops, expensive computations and whatever other nastiness you can think of. It is not too hard to come up with parameters that reach very ugly code. While we have removed for the worst of it (the "fast" nist code and GF2m come to mind), the code very much resembles the Augean Stables. Unfortunately, curve parameters are still in use - even mandatory in some contexts - for example in machine-readable travel documents signed by ICAO country signing certification authorities (see ICAO Doc 9303). To avoid many of these DoS vectors, start enforcing that we know what the curve parameters are about, namely that they correspond to a builtin curve. This way we know that the parameters are at least as good as the standards we implement and checking this is cheap: Translate curve parameters into the ad hoc representation in the builtin curve code and check there's a match. That's very cheap since most curves are distinguished by cofactor and parameter length and we need to use an actual parameter comparison for at most half a dozen curves, usually only one or two. ok jsing
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/ec/ec_asn1.c4
-rw-r--r--src/lib/libcrypto/ec/ec_curve.c222
-rw-r--r--src/lib/libcrypto/ec/ec_local.h4
3 files changed, 227 insertions, 3 deletions
diff --git a/src/lib/libcrypto/ec/ec_asn1.c b/src/lib/libcrypto/ec/ec_asn1.c
index 289bc3b271..548afb2d1a 100644
--- a/src/lib/libcrypto/ec/ec_asn1.c
+++ b/src/lib/libcrypto/ec/ec_asn1.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ec_asn1.c,v 1.74 2024/10/17 14:34:06 tb Exp $ */ 1/* $OpenBSD: ec_asn1.c,v 1.75 2024/10/18 17:27:07 tb Exp $ */
2/* 2/*
3 * Written by Nils Larsch for the OpenSSL project. 3 * Written by Nils Larsch for the OpenSSL project.
4 */ 4 */
@@ -993,6 +993,8 @@ ec_asn1_parameters2group(const ECPARAMETERS *params)
993 993
994 if (!ec_asn1_parameters_extract_prime_group(params, &group)) 994 if (!ec_asn1_parameters_extract_prime_group(params, &group))
995 goto err; 995 goto err;
996 if (!ec_group_is_builtin_curve(group))
997 goto err;
996 998
997 return group; 999 return group;
998 1000
diff --git a/src/lib/libcrypto/ec/ec_curve.c b/src/lib/libcrypto/ec/ec_curve.c
index dc7779358d..2529229ba5 100644
--- a/src/lib/libcrypto/ec/ec_curve.c
+++ b/src/lib/libcrypto/ec/ec_curve.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ec_curve.c,v 1.43 2024/03/24 06:05:41 tb Exp $ */ 1/* $OpenBSD: ec_curve.c,v 1.44 2024/10/18 17:27:07 tb Exp $ */
2/* 2/*
3 * Written by Nils Larsch for the OpenSSL project. 3 * Written by Nils Larsch for the OpenSSL project.
4 */ 4 */
@@ -69,6 +69,7 @@
69 * 69 *
70 */ 70 */
71 71
72#include <limits.h>
72#include <string.h> 73#include <string.h>
73 74
74#include <openssl/opensslconf.h> 75#include <openssl/opensslconf.h>
@@ -2457,6 +2458,225 @@ EC_GROUP_new_by_curve_name(int nid)
2457} 2458}
2458LCRYPTO_ALIAS(EC_GROUP_new_by_curve_name); 2459LCRYPTO_ALIAS(EC_GROUP_new_by_curve_name);
2459 2460
2461static void
2462ec_list_element_free(struct ec_list_element *curve)
2463{
2464 if (curve == NULL)
2465 return;
2466
2467 /* PERM UGLY CASTS */
2468 free((uint8_t *)curve->seed);
2469 free((uint8_t *)curve->p);
2470 free((uint8_t *)curve->a);
2471 free((uint8_t *)curve->b);
2472 free((uint8_t *)curve->x);
2473 free((uint8_t *)curve->y);
2474 free((uint8_t *)curve->order);
2475
2476 free(curve);
2477}
2478
2479static int
2480ec_list_element_encode_parameter(const BIGNUM *bn, int param_len,
2481 const uint8_t **out_param)
2482{
2483 uint8_t *buf = NULL;
2484 int ret = 0;
2485
2486 if (out_param == NULL || *out_param != NULL)
2487 goto err;
2488
2489 if ((buf = calloc(1, param_len)) == NULL)
2490 goto err;
2491 if (BN_bn2binpad(bn, buf, param_len) != param_len)
2492 goto err;
2493
2494 *out_param = buf;
2495 buf = NULL;
2496
2497 ret = 1;
2498
2499 err:
2500 free(buf);
2501
2502 return ret;
2503}
2504
2505static struct ec_list_element *
2506ec_list_element_from_group(const EC_GROUP *group)
2507{
2508 struct ec_list_element *curve = NULL;
2509 BN_CTX *ctx;
2510 BIGNUM *p, *a, *b, *x, *y;
2511 const EC_POINT *generator = NULL;
2512 const BIGNUM *order, *cofactor;
2513 size_t seed_len;
2514
2515 if ((ctx = BN_CTX_new()) == NULL)
2516 goto err;
2517 BN_CTX_start(ctx);
2518
2519 if ((p = BN_CTX_get(ctx)) == NULL)
2520 goto err;
2521 if ((a = BN_CTX_get(ctx)) == NULL)
2522 goto err;
2523 if ((b = BN_CTX_get(ctx)) == NULL)
2524 goto err;
2525 if ((x = BN_CTX_get(ctx)) == NULL)
2526 goto err;
2527 if ((y = BN_CTX_get(ctx)) == NULL)
2528 goto err;
2529
2530 if (!EC_GROUP_get_curve(group, p, a, b, ctx))
2531 goto err;
2532 if ((generator = EC_GROUP_get0_generator(group)) == NULL)
2533 goto err;
2534 if (!EC_POINT_get_affine_coordinates(group, generator, x, y, ctx))
2535 goto err;
2536 if ((order = EC_GROUP_get0_order(group)) == NULL)
2537 goto err;
2538
2539 if ((curve = calloc(1, sizeof(*curve))) == NULL)
2540 goto err;
2541
2542 curve->param_len = BN_num_bytes(p);
2543 if (BN_num_bytes(order) > curve->param_len)
2544 curve->param_len = BN_num_bytes(order);
2545
2546 if (!ec_list_element_encode_parameter(p, curve->param_len, &curve->p))
2547 goto err;
2548 if (!ec_list_element_encode_parameter(a, curve->param_len, &curve->a))
2549 goto err;
2550 if (!ec_list_element_encode_parameter(b, curve->param_len, &curve->b))
2551 goto err;
2552 if (!ec_list_element_encode_parameter(x, curve->param_len, &curve->x))
2553 goto err;
2554 if (!ec_list_element_encode_parameter(y, curve->param_len, &curve->y))
2555 goto err;
2556 if (!ec_list_element_encode_parameter(order, curve->param_len, &curve->order))
2557 goto err;
2558
2559 if ((cofactor = EC_GROUP_get0_cofactor(group)) != NULL) {
2560 BN_ULONG cofactor_word;
2561
2562 if ((cofactor_word = BN_get_word(cofactor)) == BN_MASK2)
2563 goto err;
2564 if (cofactor_word > INT_MAX)
2565 goto err;
2566
2567 curve->cofactor = cofactor_word;
2568 }
2569
2570 if ((seed_len = EC_GROUP_get_seed_len(group)) > 0) {
2571 uint8_t *seed;
2572
2573 if (seed_len > INT_MAX)
2574 goto err;
2575 if ((seed = calloc(1, seed_len)) == NULL)
2576 goto err;
2577 memcpy(seed, EC_GROUP_get0_seed(group), seed_len);
2578
2579 curve->seed = seed;
2580 curve->seed_len = seed_len;
2581 }
2582
2583 BN_CTX_end(ctx);
2584 BN_CTX_free(ctx);
2585
2586 return curve;
2587
2588 err:
2589 BN_CTX_end(ctx);
2590 BN_CTX_free(ctx);
2591
2592 ec_list_element_free(curve);
2593
2594 return NULL;
2595}
2596
2597static int
2598ec_list_element_cmp(const struct ec_list_element *a, const struct ec_list_element *b)
2599{
2600 int cmp;
2601
2602 /* Treat nid as optional. The OID isn't part of EC parameters. */
2603 if (a->nid != NID_undef && b->nid != NID_undef) {
2604 if (a->nid < b->nid)
2605 return -1;
2606 if (a->nid > b->nid)
2607 return 1;
2608 }
2609
2610 if (a->cofactor < b->cofactor)
2611 return -1;
2612 if (a->cofactor > b->cofactor)
2613 return 1;
2614 if (a->param_len < b->param_len)
2615 return -1;
2616 if (a->param_len > b->param_len)
2617 return 1;
2618
2619 if ((cmp = memcmp(a->p, b->p, a->param_len)) != 0)
2620 return cmp;
2621 if ((cmp = memcmp(a->a, b->a, a->param_len)) != 0)
2622 return cmp;
2623 if ((cmp = memcmp(a->b, b->b, a->param_len)) != 0)
2624 return cmp;
2625 if ((cmp = memcmp(a->x, b->x, a->param_len)) != 0)
2626 return cmp;
2627 if ((cmp = memcmp(a->y, b->y, a->param_len)) != 0)
2628 return cmp;
2629 if ((cmp = memcmp(a->order, b->order, a->param_len)) != 0)
2630 return cmp;
2631
2632 /* Seed is optional, not used for computation. Must match if present. */
2633 if (a->seed_len != 0 && b->seed_len != 0) {
2634 if (a->seed_len < b->seed_len)
2635 return -1;
2636 if (a->seed_len > b->seed_len)
2637 return 1;
2638 if (a->seed != NULL && b->seed != NULL) {
2639 if ((cmp = memcmp(a->seed, b->seed, a->seed_len)) != 0)
2640 return cmp;
2641 }
2642 }
2643
2644 return 0;
2645}
2646
2647static int
2648ec_group_nid_from_curve(const struct ec_list_element *curve)
2649{
2650 size_t i;
2651
2652 for (i = 0; i < CURVE_LIST_LENGTH; i++) {
2653 if (ec_list_element_cmp(curve, &curve_list[i]) == 0)
2654 return curve_list[i].nid;
2655 }
2656
2657 return NID_undef;
2658}
2659
2660int
2661ec_group_is_builtin_curve(const EC_GROUP *group)
2662{
2663 struct ec_list_element *curve;
2664 int ret = 0;
2665
2666 if ((curve = ec_list_element_from_group(group)) == NULL)
2667 goto err;
2668
2669 if (ec_group_nid_from_curve(curve) == NID_undef)
2670 goto err;
2671
2672 ret = 1;
2673
2674 err:
2675 ec_list_element_free(curve);
2676
2677 return ret;
2678}
2679
2460size_t 2680size_t
2461EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems) 2681EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems)
2462{ 2682{
diff --git a/src/lib/libcrypto/ec/ec_local.h b/src/lib/libcrypto/ec/ec_local.h
index ca55770ba8..b837e291f7 100644
--- a/src/lib/libcrypto/ec/ec_local.h
+++ b/src/lib/libcrypto/ec/ec_local.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ec_local.h,v 1.29 2024/10/15 06:27:43 tb Exp $ */ 1/* $OpenBSD: ec_local.h,v 1.30 2024/10/18 17:27:07 tb Exp $ */
2/* 2/*
3 * Originally written by Bodo Moeller for the OpenSSL project. 3 * Originally written by Bodo Moeller for the OpenSSL project.
4 */ 4 */
@@ -355,6 +355,8 @@ int EC_POINT_set_Jprojective_coordinates(const EC_GROUP *group, EC_POINT *p,
355int EC_POINT_get_Jprojective_coordinates(const EC_GROUP *group, 355int EC_POINT_get_Jprojective_coordinates(const EC_GROUP *group,
356 const EC_POINT *p, BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx); 356 const EC_POINT *p, BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx);
357 357
358int ec_group_is_builtin_curve(const EC_GROUP *group);
359
358/* Public API in OpenSSL */ 360/* Public API in OpenSSL */
359const BIGNUM *EC_GROUP_get0_cofactor(const EC_GROUP *group); 361const BIGNUM *EC_GROUP_get0_cofactor(const EC_GROUP *group);
360const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group); 362const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group);