1*ee657da9Stb /* $OpenBSD: ec_point_conversion.c,v 1.17 2024/10/23 15:06:46 tb Exp $ */ 232c67bd1Stb /* 332c67bd1Stb * Copyright (c) 2021 Theo Buehler <tb@openbsd.org> 432c67bd1Stb * Copyright (c) 2021 Joel Sing <jsing@openbsd.org> 532c67bd1Stb * 632c67bd1Stb * Permission to use, copy, modify, and distribute this software for any 732c67bd1Stb * purpose with or without fee is hereby granted, provided that the above 832c67bd1Stb * copyright notice and this permission notice appear in all copies. 932c67bd1Stb * 1032c67bd1Stb * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1132c67bd1Stb * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1232c67bd1Stb * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1332c67bd1Stb * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1432c67bd1Stb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1532c67bd1Stb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1632c67bd1Stb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1732c67bd1Stb */ 1832c67bd1Stb 1932c67bd1Stb #include <err.h> 2032c67bd1Stb #include <stdio.h> 2132c67bd1Stb #include <stdlib.h> 22850a9c24Stb #include <string.h> 2332c67bd1Stb 247cba3b5bStb #include <openssl/bn.h> 2532c67bd1Stb #include <openssl/ec.h> 2632c67bd1Stb #include <openssl/objects.h> 2732c67bd1Stb 2832c67bd1Stb int forms[] = { 2932c67bd1Stb POINT_CONVERSION_COMPRESSED, 3032c67bd1Stb POINT_CONVERSION_UNCOMPRESSED, 3132c67bd1Stb POINT_CONVERSION_HYBRID, 3232c67bd1Stb }; 3332c67bd1Stb 3432c67bd1Stb static const size_t N_FORMS = sizeof(forms) / sizeof(forms[0]); 3532c67bd1Stb #define N_RANDOM_POINTS 10 3632c67bd1Stb 3732c67bd1Stb static const char * 3832c67bd1Stb form2str(int form) 3932c67bd1Stb { 4032c67bd1Stb switch (form) { 4132c67bd1Stb case POINT_CONVERSION_COMPRESSED: 4232c67bd1Stb return "compressed form"; 4332c67bd1Stb case POINT_CONVERSION_UNCOMPRESSED: 4432c67bd1Stb return "uncompressed form"; 4532c67bd1Stb case POINT_CONVERSION_HYBRID: 4632c67bd1Stb return "hybrid form"; 4732c67bd1Stb default: 4832c67bd1Stb return "unknown form"; 4932c67bd1Stb } 5032c67bd1Stb } 5132c67bd1Stb 5232c67bd1Stb static void 5332c67bd1Stb hexdump(const unsigned char *buf, size_t len) 5432c67bd1Stb { 5532c67bd1Stb size_t i; 5632c67bd1Stb 5732c67bd1Stb for (i = 1; i <= len; i++) 5832c67bd1Stb fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); 5932c67bd1Stb if (len % 8) 6032c67bd1Stb fprintf(stderr, "\n"); 6132c67bd1Stb } 6232c67bd1Stb 6332c67bd1Stb static int 6432c67bd1Stb roundtrip(EC_GROUP *group, EC_POINT *point, int form, BIGNUM *x, BIGNUM *y) 6532c67bd1Stb { 6632c67bd1Stb BIGNUM *x_out = NULL, *y_out = NULL; 6732c67bd1Stb size_t len; 6832c67bd1Stb uint8_t *buf = NULL; 6932c67bd1Stb int failed = 1; 7032c67bd1Stb 7132c67bd1Stb if ((len = EC_POINT_point2oct(group, point, form, NULL, 0, NULL)) == 0) 7232c67bd1Stb errx(1, "point2oct"); 7332c67bd1Stb if ((buf = malloc(len)) == NULL) 7432c67bd1Stb errx(1, "malloc"); 7532c67bd1Stb if (EC_POINT_point2oct(group, point, form, buf, len, NULL) != len) 7632c67bd1Stb errx(1, "point2oct"); 7732c67bd1Stb 7832c67bd1Stb if (!EC_POINT_oct2point(group, point, buf, len, NULL)) 7932c67bd1Stb errx(1, "%s oct2point", form2str(form)); 8032c67bd1Stb 8132c67bd1Stb if ((x_out = BN_new()) == NULL) 8232c67bd1Stb errx(1, "new x_out"); 8332c67bd1Stb if ((y_out = BN_new()) == NULL) 8432c67bd1Stb errx(1, "new y_out"); 8532c67bd1Stb 8632c67bd1Stb if (!EC_POINT_get_affine_coordinates(group, point, x_out, y_out, NULL)) 8732c67bd1Stb errx(1, "get affine"); 8832c67bd1Stb 8932c67bd1Stb if (BN_cmp(x, x_out) != 0) { 9032c67bd1Stb warnx("%s: x", form2str(form)); 9132c67bd1Stb goto err; 9232c67bd1Stb } 9332c67bd1Stb if (BN_cmp(y, y_out) != 0) { 9432c67bd1Stb warnx("%s: y", form2str(form)); 9532c67bd1Stb goto err; 9632c67bd1Stb } 9732c67bd1Stb 9832c67bd1Stb failed = 0; 9932c67bd1Stb 10032c67bd1Stb err: 10132c67bd1Stb if (failed) 10232c67bd1Stb hexdump(buf, len); 10332c67bd1Stb 10432c67bd1Stb free(buf); 10532c67bd1Stb BN_free(x_out); 10632c67bd1Stb BN_free(y_out); 10732c67bd1Stb 10832c67bd1Stb return failed; 10932c67bd1Stb } 11032c67bd1Stb 11132c67bd1Stb /* XXX This only tests multiples of the generator for now... */ 11232c67bd1Stb static int 11332c67bd1Stb test_random_points_on_curve(EC_builtin_curve *curve) 11432c67bd1Stb { 11532c67bd1Stb EC_GROUP *group; 11632c67bd1Stb BIGNUM *order = NULL; 11732c67bd1Stb BIGNUM *random; 11832c67bd1Stb BIGNUM *x, *y; 11932c67bd1Stb size_t i, j; 12032c67bd1Stb int failed = 0; 12132c67bd1Stb 12232c67bd1Stb if ((group = EC_GROUP_new_by_curve_name(curve->nid)) == NULL) 123c9d1fabeStb errx(1, "EC_GROUP_new_by_curve_name(%s)", 124c9d1fabeStb OBJ_nid2sn(curve->nid)); 12532c67bd1Stb 12632c67bd1Stb if ((order = BN_new()) == NULL) 12732c67bd1Stb errx(1, "BN_new order"); 12832c67bd1Stb if ((random = BN_new()) == NULL) 12932c67bd1Stb errx(1, "BN_new random"); 13032c67bd1Stb if ((x = BN_new()) == NULL) 13132c67bd1Stb errx(1, "BN_new x"); 13232c67bd1Stb if ((y = BN_new()) == NULL) 13332c67bd1Stb errx(1, "BN_new y"); 13432c67bd1Stb 13532c67bd1Stb if (!EC_GROUP_get_order(group, order, NULL)) 13632c67bd1Stb errx(1, "EC_group_get_order"); 13732c67bd1Stb 13832c67bd1Stb for (i = 0; i < N_RANDOM_POINTS; i++) { 13932c67bd1Stb EC_POINT *random_point; 14032c67bd1Stb 1414bec30b6Stb do { 1424bec30b6Stb if (!BN_rand_range(random, order)) 1434bec30b6Stb errx(1, "BN_rand_range"); 1444bec30b6Stb } while (BN_is_zero(random)); 14532c67bd1Stb 14632c67bd1Stb if ((random_point = EC_POINT_new(group)) == NULL) 14732c67bd1Stb errx(1, "EC_POINT_new"); 14832c67bd1Stb 14932c67bd1Stb if (!EC_POINT_mul(group, random_point, random, NULL, NULL, NULL)) 15032c67bd1Stb errx(1, "EC_POINT_mul"); 15132c67bd1Stb 15232c67bd1Stb if (EC_POINT_is_at_infinity(group, random_point)) { 15332c67bd1Stb EC_POINT_free(random_point); 15432c67bd1Stb 15532c67bd1Stb warnx("info: got infinity"); 15632c67bd1Stb fprintf(stderr, "random = "); 15732c67bd1Stb BN_print_fp(stderr, random); 15832c67bd1Stb fprintf(stderr, "\n"); 15932c67bd1Stb 16032c67bd1Stb continue; 16132c67bd1Stb } 16232c67bd1Stb 16332c67bd1Stb if (!EC_POINT_get_affine_coordinates(group, random_point, 16432c67bd1Stb x, y, NULL)) 16532c67bd1Stb errx(1, "EC_POINT_get_affine_coordinates"); 16632c67bd1Stb 16732c67bd1Stb for (j = 0; j < N_FORMS; j++) 16832c67bd1Stb failed |= roundtrip(group, random_point, forms[j], x, y); 16932c67bd1Stb 17032c67bd1Stb EC_POINT_free(random_point); 17132c67bd1Stb } 17232c67bd1Stb 17332c67bd1Stb BN_free(order); 17432c67bd1Stb BN_free(random); 17532c67bd1Stb BN_free(x); 17632c67bd1Stb BN_free(y); 17732c67bd1Stb EC_GROUP_free(group); 17832c67bd1Stb 17932c67bd1Stb return failed; 18032c67bd1Stb } 18132c67bd1Stb 18232c67bd1Stb static int 18332c67bd1Stb test_random_points(void) 18432c67bd1Stb { 18532c67bd1Stb EC_builtin_curve *all_curves = NULL; 18632c67bd1Stb size_t ncurves = 0; 18732c67bd1Stb size_t curve_id; 18832c67bd1Stb int failed = 0; 18932c67bd1Stb 19032c67bd1Stb ncurves = EC_get_builtin_curves(NULL, 0); 19132c67bd1Stb if ((all_curves = calloc(ncurves, sizeof(EC_builtin_curve))) == NULL) 19232c67bd1Stb err(1, "calloc builtin curves"); 19332c67bd1Stb EC_get_builtin_curves(all_curves, ncurves); 19432c67bd1Stb 19532c67bd1Stb for (curve_id = 0; curve_id < ncurves; curve_id++) 19678a67f35Stb failed |= test_random_points_on_curve(&all_curves[curve_id]); 19732c67bd1Stb 198f49eea4eStb fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); 19932c67bd1Stb 20032c67bd1Stb free(all_curves); 20132c67bd1Stb return failed; 20232c67bd1Stb } 20332c67bd1Stb 204ac1153bcStb static const struct point_conversion { 205ac1153bcStb const char *description; 206ac1153bcStb int nid; 207ac1153bcStb uint8_t octets[256]; 208850a9c24Stb size_t octets_len; 209ac1153bcStb int valid; 210850a9c24Stb int point_at_infinity; 211ac1153bcStb } point_conversions[] = { 212fa4ae9b2Stb /* XXX - now that sect571 is no longer tested, add another test? */ 213b04110faStb { 214b04110faStb .description = "point at infinity on secp256r1", 215b04110faStb .nid = NID_X9_62_prime256v1, 216b04110faStb .octets = { 0x00 }, 217b04110faStb .octets_len = 1, 218b04110faStb .valid = 1, 219850a9c24Stb .point_at_infinity = 1, 220b04110faStb }, 221b04110faStb { 222b04110faStb .description = "point at infinity on secp256r1 (flipped y_bit)", 223b04110faStb .nid = NID_X9_62_prime256v1, 224b04110faStb .octets = { 0x01 }, 225b04110faStb .octets_len = 1, 226b04110faStb .valid = 0, 227850a9c24Stb .point_at_infinity = 1, 228b04110faStb }, 229b04110faStb { 230b04110faStb .description = "zero x compressed point on secp256r1", 231b04110faStb .nid = NID_X9_62_prime256v1, 232b04110faStb .octets = { 233b04110faStb 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 234b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 235b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 236b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 237b04110faStb 0x00, 238b04110faStb }, 239b04110faStb .octets_len = 33, 240b04110faStb .valid = 1, 241b04110faStb }, 242b04110faStb { 243b04110faStb .description = 244b04110faStb "zero x compressed point on secp256r1 (flipped y_bit)", 245b04110faStb .nid = NID_X9_62_prime256v1, 246b04110faStb .octets = { 247b04110faStb 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 248b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 249b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 250b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 251b04110faStb 0x00, 252b04110faStb }, 253b04110faStb .octets_len = 33, 254b04110faStb .valid = 1, 255b04110faStb }, 256b04110faStb { 257b04110faStb .description = "generic compressed point on secp256r1", 258b04110faStb .nid = NID_X9_62_prime256v1, 259b04110faStb .octets = { 260b04110faStb 0x03, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 261b04110faStb 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 262b04110faStb 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 263b04110faStb 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 264b04110faStb 0xdd, 265b04110faStb }, 266b04110faStb .octets_len = 33, 267b04110faStb .valid = 1, 268b04110faStb }, 269b04110faStb { 270b04110faStb .description = 271b04110faStb "generic compressed point on secp256r1 (flipped y_bit)", 272b04110faStb .nid = NID_X9_62_prime256v1, 273b04110faStb .octets = { 274b04110faStb 0x02, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 275b04110faStb 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 276b04110faStb 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 277b04110faStb 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 278b04110faStb 0xdd, 279b04110faStb }, 280b04110faStb .octets_len = 33, 281b04110faStb .valid = 1, 282b04110faStb }, 283b04110faStb { 284b04110faStb .description = "zero x uncompressed point #1 on secp256r1", 285b04110faStb .nid = NID_X9_62_prime256v1, 286b04110faStb .octets = { 287b04110faStb 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 288b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 289b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 290b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 291b04110faStb 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 292b04110faStb 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 293b04110faStb 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 294b04110faStb 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 295b04110faStb 0xf4, 296b04110faStb }, 297b04110faStb .octets_len = 65, 298b04110faStb .valid = 1, 299b04110faStb }, 300b04110faStb { 301b04110faStb .description = 302b04110faStb "zero x uncompressed point #1 on secp256r1 (flipped y_bit)", 303b04110faStb .nid = NID_X9_62_prime256v1, 304b04110faStb .octets = { 305b04110faStb 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 306b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 307b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 308b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 309b04110faStb 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 310b04110faStb 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 311b04110faStb 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 312b04110faStb 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 313b04110faStb 0xf4, 314b04110faStb }, 315b04110faStb .octets_len = 65, 316b04110faStb .valid = 0, 317b04110faStb }, 318b04110faStb { 319b04110faStb .description = "zero x uncompressed point #2 on secp256r1", 320b04110faStb .nid = NID_X9_62_prime256v1, 321b04110faStb .octets = { 322b04110faStb 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 323b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 324b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 325b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 326b04110faStb 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 327b04110faStb 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 328b04110faStb 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 329b04110faStb 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 330b04110faStb 0x0b, 331b04110faStb }, 332b04110faStb .octets_len = 65, 333b04110faStb .valid = 1, 334b04110faStb }, 335b04110faStb { 336b04110faStb .description = 337b04110faStb "zero x uncompressed point #2 on secp256r1 (flipped y_bit)", 338b04110faStb .nid = NID_X9_62_prime256v1, 339b04110faStb .octets = { 340b04110faStb 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 341b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 342b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 343b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 344b04110faStb 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 345b04110faStb 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 346b04110faStb 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 347b04110faStb 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 348b04110faStb 0x0b, 349b04110faStb }, 350b04110faStb .octets_len = 65, 351b04110faStb .valid = 0, 352b04110faStb }, 353b04110faStb { 354b04110faStb .description = "generic uncompressed point on secp256r1", 355b04110faStb .nid = NID_X9_62_prime256v1, 356b04110faStb .octets = { 357b04110faStb 0x04, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 358b04110faStb 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 359b04110faStb 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 360b04110faStb 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 361b04110faStb 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 362b04110faStb 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 363b04110faStb 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 364b04110faStb 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 365b04110faStb 0x03, 366b04110faStb }, 367b04110faStb .octets_len = 65, 368b04110faStb .valid = 1, 369b04110faStb }, 370b04110faStb { 371b04110faStb .description = 372b04110faStb "generic uncompressed point on secp256r1 (flipped y_bit)", 373b04110faStb .nid = NID_X9_62_prime256v1, 374b04110faStb .octets = { 375b04110faStb 0x05, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 376b04110faStb 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 377b04110faStb 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 378b04110faStb 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 379b04110faStb 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 380b04110faStb 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 381b04110faStb 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 382b04110faStb 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 383b04110faStb 0x03, 384b04110faStb }, 385b04110faStb .octets_len = 65, 386b04110faStb .valid = 0, 387b04110faStb }, 388b04110faStb { 389b04110faStb .description = "zero x hybrid point #1 on secp256r1", 390b04110faStb .nid = NID_X9_62_prime256v1, 391b04110faStb .octets = { 392b04110faStb 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 393b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 394b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 395b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 396b04110faStb 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 397b04110faStb 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 398b04110faStb 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 399b04110faStb 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 400b04110faStb 0xf4, 401b04110faStb }, 402b04110faStb .octets_len = 65, 403b04110faStb .valid = 1, 404b04110faStb }, 405b04110faStb { 406b04110faStb .description = 407b04110faStb "zero x hybrid point #1 on secp256r1 (flipped y_bit)", 408b04110faStb .nid = NID_X9_62_prime256v1, 409b04110faStb .octets = { 410b04110faStb 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 411b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 412b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 413b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 414b04110faStb 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 415b04110faStb 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 416b04110faStb 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 417b04110faStb 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 418b04110faStb 0xf4, 419b04110faStb }, 420b04110faStb .octets_len = 65, 421b04110faStb .valid = 0, 422b04110faStb }, 423b04110faStb { 424b04110faStb .description = "zero x hybrid point #2 on secp256r1", 425b04110faStb .nid = NID_X9_62_prime256v1, 426b04110faStb .octets = { 427b04110faStb 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 428b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 429b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 430b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 431b04110faStb 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 432b04110faStb 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 433b04110faStb 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 434b04110faStb 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 435b04110faStb 0x0b, 436b04110faStb }, 437b04110faStb .octets_len = 65, 438b04110faStb .valid = 1, 439b04110faStb }, 440b04110faStb { 441b04110faStb .description = 442b04110faStb "zero x hybrid point #2 on secp256r1 (flipped y_bit)", 443b04110faStb .nid = NID_X9_62_prime256v1, 444b04110faStb .octets = { 445b04110faStb 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 446b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 447b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 448b04110faStb 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 449b04110faStb 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 450b04110faStb 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 451b04110faStb 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 452b04110faStb 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 453b04110faStb 0x0b, 454b04110faStb }, 455b04110faStb .octets_len = 65, 456b04110faStb .valid = 0, 457b04110faStb }, 458b04110faStb { 459b04110faStb .description = "generic hybrid point on secp256r1", 460b04110faStb .nid = NID_X9_62_prime256v1, 461b04110faStb .octets = { 462b04110faStb 0x07, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 463b04110faStb 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 464b04110faStb 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 465b04110faStb 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 466b04110faStb 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 467b04110faStb 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 468b04110faStb 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 469b04110faStb 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 470b04110faStb 0xc5, 471b04110faStb }, 472b04110faStb .octets_len = 65, 473b04110faStb .valid = 1, 474b04110faStb }, 475b04110faStb { 4767b1db04cStb .description = 4777b1db04cStb "generic hybrid point on secp256r1 (flipped y_bit)", 478b04110faStb .nid = NID_X9_62_prime256v1, 479b04110faStb .octets = { 480b04110faStb 0x06, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 481b04110faStb 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 482b04110faStb 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 483b04110faStb 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 484b04110faStb 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 485b04110faStb 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 486b04110faStb 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 487b04110faStb 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 488b04110faStb 0xc5, 489b04110faStb }, 490b04110faStb .octets_len = 65, 491b04110faStb .valid = 0, 492b04110faStb }, 493ac1153bcStb }; 494ac1153bcStb 495ac1153bcStb static const size_t N_POINT_CONVERSIONS = 496ac1153bcStb sizeof(point_conversions) / sizeof(point_conversions[0]); 497ac1153bcStb 498ac1153bcStb static int 499850a9c24Stb check_point_at_infinity(const EC_GROUP *group, const EC_POINT *point, 500850a9c24Stb const struct point_conversion *test) 501850a9c24Stb { 502850a9c24Stb const uint8_t conversion_forms[4] = { 0x00, 0x02, 0x04, 0x06, }; 503850a9c24Stb uint8_t buf[1]; 504850a9c24Stb uint8_t form; 505850a9c24Stb size_t i, ret; 506850a9c24Stb int failed = 0; 507850a9c24Stb 508850a9c24Stb /* The form for the point at infinity is expected to fail. */ 509850a9c24Stb form = conversion_forms[0]; 510850a9c24Stb 511850a9c24Stb ret = EC_POINT_point2oct(group, point, form, buf, sizeof(buf), NULL); 512850a9c24Stb if (ret != 0) { 513850a9c24Stb fprintf(stderr, "FAIL: %s: expected encoding with form 0x%02x " 514850a9c24Stb "to fail, got %zu\n", test->description, form, ret); 515850a9c24Stb failed |= 1; 516850a9c24Stb } 517850a9c24Stb 518850a9c24Stb /* For all other forms we expect the zero octet. */ 519850a9c24Stb for (i = 1; i < sizeof(conversion_forms); i++) { 520850a9c24Stb form = conversion_forms[i]; 521850a9c24Stb 522850a9c24Stb ret = EC_POINT_point2oct(group, point, form, buf, sizeof(buf), NULL); 523850a9c24Stb if (ret != 1) { 524850a9c24Stb fprintf(stderr, "FAIL: %s: expected success, got %zu\n", 525850a9c24Stb test->description, ret); 526850a9c24Stb failed |= 1; 527850a9c24Stb continue; 528850a9c24Stb } 529850a9c24Stb 530850a9c24Stb if (memcmp(buf, test->octets, test->octets_len) != 0) { 531850a9c24Stb fprintf(stderr, "FAIL: %s: want 0x%02x, got 0x%02x\n", 532850a9c24Stb test->description, test->octets[0], buf[0]); 533850a9c24Stb failed |= 1; 534850a9c24Stb continue; 535850a9c24Stb } 536850a9c24Stb } 537850a9c24Stb 538850a9c24Stb return failed; 539850a9c24Stb } 540850a9c24Stb 541850a9c24Stb static int 542ac1153bcStb point_conversion_form_y_bit(const struct point_conversion *test) 543ac1153bcStb { 544ac1153bcStb EC_GROUP *group = NULL; 545ac1153bcStb EC_POINT *point = NULL; 546ac1153bcStb int ret; 547ac1153bcStb int failed = 0; 548ac1153bcStb 549ac1153bcStb if ((group = EC_GROUP_new_by_curve_name(test->nid)) == NULL) 550ac1153bcStb errx(1, "group"); 551ac1153bcStb if ((point = EC_POINT_new(group)) == NULL) 552ac1153bcStb errx(1, "point"); 553ac1153bcStb 554ac1153bcStb ret = EC_POINT_oct2point(group, point, test->octets, test->octets_len, 555ac1153bcStb NULL); 556ac1153bcStb if (ret != test->valid) { 557ac1153bcStb fprintf(stderr, "%s want %d got %d\n", test->description, 558ac1153bcStb test->valid, ret); 559ac1153bcStb failed |= 1; 560ac1153bcStb } 561ac1153bcStb 562*ee657da9Stb if (test->valid && test->point_at_infinity) { 563850a9c24Stb failed |= check_point_at_infinity(group, point, test); 564*ee657da9Stb } else if (test->valid) { 565850a9c24Stb uint8_t buf[256]; 566850a9c24Stb uint8_t form = test->octets[0] & 0x06; 567850a9c24Stb size_t len; 568850a9c24Stb 569850a9c24Stb len = EC_POINT_point2oct(group, point, form, buf, sizeof(buf), NULL); 570850a9c24Stb 571850a9c24Stb if (len != test->octets_len) { 572850a9c24Stb fprintf(stderr, "%s: EC_POINT_point2oct: want %zu, got %zu\n", 573850a9c24Stb test->description, test->octets_len, len); 574850a9c24Stb failed |= 1; 575850a9c24Stb goto failed; 576850a9c24Stb } 577850a9c24Stb if (memcmp(test->octets, buf, len) != 0) { 578850a9c24Stb fprintf(stderr, "%s: unexpected encoding\nwant:\n", 579850a9c24Stb test->description); 580850a9c24Stb hexdump(test->octets, test->octets_len); 581850a9c24Stb fprintf(stderr, "\ngot:\n"); 582850a9c24Stb hexdump(buf, len); 583850a9c24Stb failed |= 1; 584850a9c24Stb goto failed; 585850a9c24Stb } 586850a9c24Stb } 587850a9c24Stb 588850a9c24Stb failed: 589ac1153bcStb EC_GROUP_free(group); 590ac1153bcStb EC_POINT_free(point); 591ac1153bcStb 592ac1153bcStb return failed; 593ac1153bcStb } 594ac1153bcStb 595ac1153bcStb static int 596ac1153bcStb test_point_conversions(void) 597ac1153bcStb { 598ac1153bcStb size_t i; 599ac1153bcStb int failed = 0; 600ac1153bcStb 601ac1153bcStb for (i = 0; i < N_POINT_CONVERSIONS; i++) 602ac1153bcStb failed |= point_conversion_form_y_bit(&point_conversions[i]); 603ac1153bcStb 604f49eea4eStb fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); 605ac1153bcStb 606ac1153bcStb return failed; 607ac1153bcStb } 608ac1153bcStb 60932c67bd1Stb int 61032c67bd1Stb main(int argc, char **argv) 61132c67bd1Stb { 61232c67bd1Stb int failed = 0; 61332c67bd1Stb 61432c67bd1Stb failed |= test_random_points(); 615ac1153bcStb failed |= test_point_conversions(); 61632c67bd1Stb 61732c67bd1Stb return failed; 61832c67bd1Stb } 619