/* $OpenBSD: ec_point_conversion.c,v 1.7 2022/12/01 13:49:12 tb Exp $ */ /* * Copyright (c) 2021 Theo Buehler * Copyright (c) 2021 Joel Sing * * 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 #include #include #include #include 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 test_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" : ""); 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++) failed |= test_random_points_on_curve(&all_curves[curve_id]); fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); free(all_curves); return failed; } static const struct point_conversion { const char *description; int nid; uint8_t octets[256]; uint8_t octets_len; int valid; } point_conversions[] = { { .description = "point at infinity on sect571k1", .nid = NID_sect571k1, .octets = { 0x00 }, .octets_len = 1, .valid = 1, }, { .description = "point at infinity on sect571k1 (flipped y_bit)", .nid = NID_sect571k1, .octets = { 0x01 }, .octets_len = 1, .valid = 0, }, { .description = "zero x compressed point on sect571k1", .nid = NID_sect571k1, .octets = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, .octets_len = 73, .valid = 1, }, { .description = "zero x compressed point on sect571k1 (flipped y_bit)", .nid = NID_sect571k1, .octets = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, .octets_len = 73, .valid = 0, }, { .description = "generic compressed point on sect571k1", .nid = NID_sect571k1, .octets = { 0x02, 0x00, 0x5e, 0x33, 0x9f, 0xd6, 0xf1, 0xae, 0x10, 0xbd, 0x48, 0xcf, 0xf1, 0x0d, 0x8e, 0x0e, 0xd7, 0x83, 0xce, 0xf0, 0x3d, 0x14, 0x06, 0x41, 0x29, 0x7d, 0x7e, 0xa3, 0x01, 0xf4, 0x9b, 0xa2, 0x8c, 0xa6, 0xab, 0x24, 0xa0, 0x9e, 0xfd, 0xc4, 0x2d, 0xc2, 0x95, 0xb4, 0xf9, 0xd4, 0xf4, 0x97, 0x53, 0x5d, 0xe9, 0xe3, 0x47, 0xc3, 0xa8, 0x6b, 0xbb, 0x27, 0x74, 0x6b, 0xfb, 0x26, 0xca, 0x96, 0x76, 0x5b, 0x36, 0xe8, 0x87, 0xb5, 0xc5, 0x6a, 0xc5, }, .octets_len = 73, .valid = 1, }, { .description = "generic compressed point on sect571k1 (flipped y_bit)", .nid = NID_sect571k1, .octets = { 0x03, 0x00, 0x5e, 0x33, 0x9f, 0xd6, 0xf1, 0xae, 0x10, 0xbd, 0x48, 0xcf, 0xf1, 0x0d, 0x8e, 0x0e, 0xd7, 0x83, 0xce, 0xf0, 0x3d, 0x14, 0x06, 0x41, 0x29, 0x7d, 0x7e, 0xa3, 0x01, 0xf4, 0x9b, 0xa2, 0x8c, 0xa6, 0xab, 0x24, 0xa0, 0x9e, 0xfd, 0xc4, 0x2d, 0xc2, 0x95, 0xb4, 0xf9, 0xd4, 0xf4, 0x97, 0x53, 0x5d, 0xe9, 0xe3, 0x47, 0xc3, 0xa8, 0x6b, 0xbb, 0x27, 0x74, 0x6b, 0xfb, 0x26, 0xca, 0x96, 0x76, 0x5b, 0x36, 0xe8, 0x87, 0xb5, 0xc5, 0x6a, 0xc5, }, .octets_len = 73, .valid = 1, }, { .description = "zero x uncompressed point on sect571k1", .nid = NID_sect571k1, .octets = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }, .octets_len = 145, .valid = 1, }, { .description = "zero x uncompressed point on sect571k1", .nid = NID_sect571k1, .octets = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }, .octets_len = 145, .valid = 0, }, { .description = "generic uncompressed point on sect571k1", .nid = NID_sect571k1, .octets = { 0x04, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 0x28, }, .octets_len = 145, .valid = 1, }, { .description = "generic uncompressed point on sect571k1 (flipped y_bit)", .nid = NID_sect571k1, .octets = { 0x05, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 0x28, }, .octets_len = 145, .valid = 0, }, { .description = "zero x hybrid point on sect571k1", .nid = NID_sect571k1, .octets = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }, .octets_len = 145, .valid = 1, }, { .description = "zero x hybrid point on sect571k1 (flipped y_bit)", .nid = NID_sect571k1, .octets = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }, .octets_len = 145, .valid = 0, }, { .description = "generic hybrid point on sect571k1", .nid = NID_sect571k1, .octets = { 0x07, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 0x28, }, .octets_len = 145, .valid = 1, }, { .description = "generic hybrid point on sect571k1 (flipped y_bit)", .nid = NID_sect571k1, .octets = { 0x06, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 0x28, }, .octets_len = 145, .valid = 0, }, { .description = "point at infinity on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x00 }, .octets_len = 1, .valid = 1, }, { .description = "point at infinity on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x01 }, .octets_len = 1, .valid = 0, }, { .description = "zero x compressed point on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, .octets_len = 33, .valid = 1, }, { .description = "zero x compressed point on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, .octets_len = 33, .valid = 1, }, { .description = "generic compressed point on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x03, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 0xdd, }, .octets_len = 33, .valid = 1, }, { .description = "generic compressed point on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x02, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 0xdd, }, .octets_len = 33, .valid = 1, }, { .description = "zero x uncompressed point #1 on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 0xf4, }, .octets_len = 65, .valid = 1, }, { .description = "zero x uncompressed point #1 on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 0xf4, }, .octets_len = 65, .valid = 0, }, { .description = "zero x uncompressed point #2 on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 0x0b, }, .octets_len = 65, .valid = 1, }, { .description = "zero x uncompressed point #2 on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 0x0b, }, .octets_len = 65, .valid = 0, }, { .description = "generic uncompressed point on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x04, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 0x03, }, .octets_len = 65, .valid = 1, }, { .description = "generic uncompressed point on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x05, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 0x03, }, .octets_len = 65, .valid = 0, }, { .description = "zero x hybrid point #1 on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 0xf4, }, .octets_len = 65, .valid = 1, }, { .description = "zero x hybrid point #1 on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 0xf4, }, .octets_len = 65, .valid = 0, }, { .description = "zero x hybrid point #2 on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 0x0b, }, .octets_len = 65, .valid = 1, }, { .description = "zero x hybrid point #2 on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 0x0b, }, .octets_len = 65, .valid = 0, }, { .description = "generic hybrid point on secp256r1", .nid = NID_X9_62_prime256v1, .octets = { 0x07, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 0xc5, }, .octets_len = 65, .valid = 1, }, { .description = "generic hybrid point on secp256r1 (flipped y_bit)", .nid = NID_X9_62_prime256v1, .octets = { 0x06, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 0xc5, }, .octets_len = 65, .valid = 0, }, }; static const size_t N_POINT_CONVERSIONS = sizeof(point_conversions) / sizeof(point_conversions[0]); static int point_conversion_form_y_bit(const struct point_conversion *test) { EC_GROUP *group = NULL; EC_POINT *point = NULL; int ret; int failed = 0; if ((group = EC_GROUP_new_by_curve_name(test->nid)) == NULL) errx(1, "group"); if ((point = EC_POINT_new(group)) == NULL) errx(1, "point"); ret = EC_POINT_oct2point(group, point, test->octets, test->octets_len, NULL); if (ret != test->valid) { fprintf(stderr, "%s want %d got %d\n", test->description, test->valid, ret); failed |= 1; } EC_GROUP_free(group); EC_POINT_free(point); return failed; } static int test_point_conversions(void) { size_t i; int failed = 0; for (i = 0; i < N_POINT_CONVERSIONS; i++) failed |= point_conversion_form_y_bit(&point_conversions[i]); fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); return failed; } int main(int argc, char **argv) { int failed = 0; failed |= test_random_points(); failed |= test_hybrid_corner_case(); failed |= test_point_conversions(); return failed; }