diff options
author | Theo Buehler <tb@cvs.openbsd.org> | 2021-04-21 20:15:09 +0000 |
---|---|---|
committer | Theo Buehler <tb@cvs.openbsd.org> | 2021-04-21 20:15:09 +0000 |
commit | ca0ea78defe5a55b440d4886d29eb2ec4b440f51 (patch) | |
tree | 053e09a64c5449442723b2486d3bffa3aeaae443 /regress | |
parent | 0a6bc2560f8f9cf235076abdfc7d657c785d0724 (diff) |
Add a test that roundtrips a bunch of points on all builtin curves
via point2oct and oct2point and that checks the corner case in hybrid
encoding that was fixed in ec2_oct.c r1.13.
Diffstat (limited to 'regress')
-rw-r--r-- | regress/lib/libcrypto/ec/Makefile | 25 | ||||
-rw-r--r-- | regress/lib/libcrypto/ec/ec_point_conversion.c | 249 |
2 files changed, 268 insertions, 6 deletions
diff --git a/regress/lib/libcrypto/ec/Makefile b/regress/lib/libcrypto/ec/Makefile index 76b552fa231..394ac51226f 100644 --- a/regress/lib/libcrypto/ec/Makefile +++ b/regress/lib/libcrypto/ec/Makefile @@ -1,9 +1,22 @@ -# $OpenBSD: Makefile,v 1.4 2021/04/20 17:09:45 tb Exp $ +# $OpenBSD: Makefile,v 1.5 2021/04/21 20:15:08 tb Exp $ -PROG= ectest -LDADD= ${CRYPTO_INT} -DPADD= ${LIBCRYPTO} -WARNINGS= Yes -CFLAGS+= -DLIBRESSL_INTERNAL -Werror +PROGS += ectest +PROGS += ec_point_conversion + +.for t in ${PROGS} +REGRESS_TARGETS += run-$t +.endfor + +LDADD = ${CRYPTO_INT} +DPADD = ${LIBCRYPTO} +WARNINGS = Yes +CFLAGS += -DLIBRESSL_INTERNAL -Wall -Wundef -Werror + +CLEANFILES += ${PROGS} + +.for t in ${PROGS} +run-$t: $t + ./$t +.endfor .include <bsd.regress.mk> diff --git a/regress/lib/libcrypto/ec/ec_point_conversion.c b/regress/lib/libcrypto/ec/ec_point_conversion.c new file mode 100644 index 00000000000..97ba70034de --- /dev/null +++ b/regress/lib/libcrypto/ec/ec_point_conversion.c @@ -0,0 +1,249 @@ +/* $OpenBSD: ec_point_conversion.c,v 1.1 2021/04/21 20:15:08 tb Exp $ */ +/* + * Copyright (c) 2021 Theo Buehler <tb@openbsd.org> + * Copyright (c) 2021 Joel Sing <jsing@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> + +#include <openssl/ec.h> +#include <openssl/objects.h> + +int bn_rand_interval(BIGNUM *, const BIGNUM *, const BIGNUM *); + +int forms[] = { + POINT_CONVERSION_COMPRESSED, + POINT_CONVERSION_UNCOMPRESSED, + POINT_CONVERSION_HYBRID, +}; + +static const size_t N_FORMS = sizeof(forms) / sizeof(forms[0]); +#define N_RANDOM_POINTS 10 + +static const char * +form2str(int form) +{ + switch (form) { + case POINT_CONVERSION_COMPRESSED: + return "compressed form"; + case POINT_CONVERSION_UNCOMPRESSED: + return "uncompressed form"; + case POINT_CONVERSION_HYBRID: + return "hybrid form"; + default: + return "unknown form"; + } +} + +static void +hexdump(const unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 1; i <= len; i++) + fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); + + if (len % 8) + fprintf(stderr, "\n"); +} + +static int +roundtrip(EC_GROUP *group, EC_POINT *point, int form, BIGNUM *x, BIGNUM *y) +{ + BIGNUM *x_out = NULL, *y_out = NULL; + size_t len; + uint8_t *buf = NULL; + int failed = 1; + + if ((len = EC_POINT_point2oct(group, point, form, NULL, 0, NULL)) == 0) + errx(1, "point2oct"); + if ((buf = malloc(len)) == NULL) + errx(1, "malloc"); + if (EC_POINT_point2oct(group, point, form, buf, len, NULL) != len) + errx(1, "point2oct"); + + if (!EC_POINT_oct2point(group, point, buf, len, NULL)) + errx(1, "%s oct2point", form2str(form)); + + if ((x_out = BN_new()) == NULL) + errx(1, "new x_out"); + if ((y_out = BN_new()) == NULL) + errx(1, "new y_out"); + + if (!EC_POINT_get_affine_coordinates(group, point, x_out, y_out, NULL)) + errx(1, "get affine"); + + if (BN_cmp(x, x_out) != 0) { + warnx("%s: x", form2str(form)); + goto err; + } + if (BN_cmp(y, y_out) != 0) { + warnx("%s: y", form2str(form)); + goto err; + } + + failed = 0; + + err: + if (failed) + hexdump(buf, len); + + free(buf); + BN_free(x_out); + BN_free(y_out); + + return failed; +} + +static int +hybrid_corner_case(void) +{ + BIGNUM *x = NULL, *y = NULL; + EC_GROUP *group; + EC_POINT *point; + size_t i; + int failed = 0; + + if (!BN_hex2bn(&x, "0")) + errx(1, "BN_hex2bn x"); + if (!BN_hex2bn(&y, "01")) + errx(1, "BN_hex2bn y"); + + if ((group = EC_GROUP_new_by_curve_name(NID_sect571k1)) == NULL) + errx(1, "group"); + if ((point = EC_POINT_new(group)) == NULL) + errx(1, "point"); + + if (!EC_POINT_set_affine_coordinates(group, point, x, y, NULL)) + errx(1, "set affine"); + + for (i = 0; i < N_FORMS; i++) + failed |= roundtrip(group, point, forms[i], x, y); + + fprintf(stderr, "%s: %s\n", __func__, failed ? "FAILED" : "SUCCESS"); + + EC_GROUP_free(group); + EC_POINT_free(point); + BN_free(x); + BN_free(y); + + return failed; +} + +/* XXX This only tests multiples of the generator for now... */ +static int +test_random_points_on_curve(EC_builtin_curve *curve) +{ + EC_GROUP *group; + BIGNUM *order = NULL; + BIGNUM *random; + BIGNUM *x, *y; + size_t i, j; + int failed = 0; + + fprintf(stderr, "%s\n", OBJ_nid2sn(curve->nid)); + if ((group = EC_GROUP_new_by_curve_name(curve->nid)) == NULL) + errx(1, "EC_GROUP_new_by_curve_name"); + + if ((order = BN_new()) == NULL) + errx(1, "BN_new order"); + if ((random = BN_new()) == NULL) + errx(1, "BN_new random"); + if ((x = BN_new()) == NULL) + errx(1, "BN_new x"); + if ((y = BN_new()) == NULL) + errx(1, "BN_new y"); + + if (!EC_GROUP_get_order(group, order, NULL)) + errx(1, "EC_group_get_order"); + + for (i = 0; i < N_RANDOM_POINTS; i++) { + EC_POINT *random_point; + + if (!bn_rand_interval(random, BN_value_one(), order)) + errx(1, "bn_rand_interval"); + + if ((random_point = EC_POINT_new(group)) == NULL) + errx(1, "EC_POINT_new"); + + if (!EC_POINT_mul(group, random_point, random, NULL, NULL, NULL)) + errx(1, "EC_POINT_mul"); + + if (EC_POINT_is_at_infinity(group, random_point)) { + EC_POINT_free(random_point); + + warnx("info: got infinity"); + fprintf(stderr, "random = "); + BN_print_fp(stderr, random); + fprintf(stderr, "\n"); + + continue; + } + + if (!EC_POINT_get_affine_coordinates(group, random_point, + x, y, NULL)) + errx(1, "EC_POINT_get_affine_coordinates"); + + for (j = 0; j < N_FORMS; j++) + failed |= roundtrip(group, random_point, forms[j], x, y); + + EC_POINT_free(random_point); + } + + BN_free(order); + BN_free(random); + BN_free(x); + BN_free(y); + EC_GROUP_free(group); + + return failed; +} + +static int +test_random_points(void) +{ + EC_builtin_curve *all_curves = NULL; + size_t ncurves = 0; + size_t curve_id; + int failed = 0; + + ncurves = EC_get_builtin_curves(NULL, 0); + if ((all_curves = calloc(ncurves, sizeof(EC_builtin_curve))) == NULL) + err(1, "calloc builtin curves"); + EC_get_builtin_curves(all_curves, ncurves); + + for (curve_id = 0; curve_id < ncurves; curve_id++) + test_random_points_on_curve(&all_curves[curve_id]); + + fprintf(stderr, "%s: %s\n", __func__, failed ? "FAILED" : "SUCCESS"); + + free(all_curves); + return failed; +} + +int +main(int argc, char **argv) +{ + int failed = 0; + + failed |= test_random_points(); + failed |= hybrid_corner_case(); + + fprintf(stderr, "%s\n", failed ? "FAILED" : "SUCCESS"); + + return failed; +} |