1 /* $OpenBSD: ec_point_conversion.c,v 1.5 2021/05/03 14:51:47 tb Exp $ */ 2 /* 3 * Copyright (c) 2021 Theo Buehler <tb@openbsd.org> 4 * Copyright (c) 2021 Joel Sing <jsing@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <err.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 23 #include <openssl/ec.h> 24 #include <openssl/objects.h> 25 26 int bn_rand_interval(BIGNUM *, const BIGNUM *, const BIGNUM *); 27 28 int forms[] = { 29 POINT_CONVERSION_COMPRESSED, 30 POINT_CONVERSION_UNCOMPRESSED, 31 POINT_CONVERSION_HYBRID, 32 }; 33 34 static const size_t N_FORMS = sizeof(forms) / sizeof(forms[0]); 35 #define N_RANDOM_POINTS 10 36 37 static const char * 38 form2str(int form) 39 { 40 switch (form) { 41 case POINT_CONVERSION_COMPRESSED: 42 return "compressed form"; 43 case POINT_CONVERSION_UNCOMPRESSED: 44 return "uncompressed form"; 45 case POINT_CONVERSION_HYBRID: 46 return "hybrid form"; 47 default: 48 return "unknown form"; 49 } 50 } 51 52 static void 53 hexdump(const unsigned char *buf, size_t len) 54 { 55 size_t i; 56 57 for (i = 1; i <= len; i++) 58 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); 59 60 if (len % 8) 61 fprintf(stderr, "\n"); 62 } 63 64 static int 65 roundtrip(EC_GROUP *group, EC_POINT *point, int form, BIGNUM *x, BIGNUM *y) 66 { 67 BIGNUM *x_out = NULL, *y_out = NULL; 68 size_t len; 69 uint8_t *buf = NULL; 70 int failed = 1; 71 72 if ((len = EC_POINT_point2oct(group, point, form, NULL, 0, NULL)) == 0) 73 errx(1, "point2oct"); 74 if ((buf = malloc(len)) == NULL) 75 errx(1, "malloc"); 76 if (EC_POINT_point2oct(group, point, form, buf, len, NULL) != len) 77 errx(1, "point2oct"); 78 79 if (!EC_POINT_oct2point(group, point, buf, len, NULL)) 80 errx(1, "%s oct2point", form2str(form)); 81 82 if ((x_out = BN_new()) == NULL) 83 errx(1, "new x_out"); 84 if ((y_out = BN_new()) == NULL) 85 errx(1, "new y_out"); 86 87 if (!EC_POINT_get_affine_coordinates(group, point, x_out, y_out, NULL)) 88 errx(1, "get affine"); 89 90 if (BN_cmp(x, x_out) != 0) { 91 warnx("%s: x", form2str(form)); 92 goto err; 93 } 94 if (BN_cmp(y, y_out) != 0) { 95 warnx("%s: y", form2str(form)); 96 goto err; 97 } 98 99 failed = 0; 100 101 err: 102 if (failed) 103 hexdump(buf, len); 104 105 free(buf); 106 BN_free(x_out); 107 BN_free(y_out); 108 109 return failed; 110 } 111 112 static int 113 test_hybrid_corner_case(void) 114 { 115 BIGNUM *x = NULL, *y = NULL; 116 EC_GROUP *group; 117 EC_POINT *point; 118 size_t i; 119 int failed = 0; 120 121 if (!BN_hex2bn(&x, "0")) 122 errx(1, "BN_hex2bn x"); 123 if (!BN_hex2bn(&y, "01")) 124 errx(1, "BN_hex2bn y"); 125 126 if ((group = EC_GROUP_new_by_curve_name(NID_sect571k1)) == NULL) 127 errx(1, "group"); 128 if ((point = EC_POINT_new(group)) == NULL) 129 errx(1, "point"); 130 131 if (!EC_POINT_set_affine_coordinates(group, point, x, y, NULL)) 132 errx(1, "set affine"); 133 134 for (i = 0; i < N_FORMS; i++) 135 failed |= roundtrip(group, point, forms[i], x, y); 136 137 fprintf(stderr, "%s: %s\n", __func__, failed ? "FAILED" : "SUCCESS"); 138 139 EC_GROUP_free(group); 140 EC_POINT_free(point); 141 BN_free(x); 142 BN_free(y); 143 144 return failed; 145 } 146 147 /* XXX This only tests multiples of the generator for now... */ 148 static int 149 test_random_points_on_curve(EC_builtin_curve *curve) 150 { 151 EC_GROUP *group; 152 BIGNUM *order = NULL; 153 BIGNUM *random; 154 BIGNUM *x, *y; 155 size_t i, j; 156 int failed = 0; 157 158 fprintf(stderr, "%s\n", OBJ_nid2sn(curve->nid)); 159 if ((group = EC_GROUP_new_by_curve_name(curve->nid)) == NULL) 160 errx(1, "EC_GROUP_new_by_curve_name"); 161 162 if ((order = BN_new()) == NULL) 163 errx(1, "BN_new order"); 164 if ((random = BN_new()) == NULL) 165 errx(1, "BN_new random"); 166 if ((x = BN_new()) == NULL) 167 errx(1, "BN_new x"); 168 if ((y = BN_new()) == NULL) 169 errx(1, "BN_new y"); 170 171 if (!EC_GROUP_get_order(group, order, NULL)) 172 errx(1, "EC_group_get_order"); 173 174 for (i = 0; i < N_RANDOM_POINTS; i++) { 175 EC_POINT *random_point; 176 177 if (!bn_rand_interval(random, BN_value_one(), order)) 178 errx(1, "bn_rand_interval"); 179 180 if ((random_point = EC_POINT_new(group)) == NULL) 181 errx(1, "EC_POINT_new"); 182 183 if (!EC_POINT_mul(group, random_point, random, NULL, NULL, NULL)) 184 errx(1, "EC_POINT_mul"); 185 186 if (EC_POINT_is_at_infinity(group, random_point)) { 187 EC_POINT_free(random_point); 188 189 warnx("info: got infinity"); 190 fprintf(stderr, "random = "); 191 BN_print_fp(stderr, random); 192 fprintf(stderr, "\n"); 193 194 continue; 195 } 196 197 if (!EC_POINT_get_affine_coordinates(group, random_point, 198 x, y, NULL)) 199 errx(1, "EC_POINT_get_affine_coordinates"); 200 201 for (j = 0; j < N_FORMS; j++) 202 failed |= roundtrip(group, random_point, forms[j], x, y); 203 204 EC_POINT_free(random_point); 205 } 206 207 BN_free(order); 208 BN_free(random); 209 BN_free(x); 210 BN_free(y); 211 EC_GROUP_free(group); 212 213 return failed; 214 } 215 216 static int 217 test_random_points(void) 218 { 219 EC_builtin_curve *all_curves = NULL; 220 size_t ncurves = 0; 221 size_t curve_id; 222 int failed = 0; 223 224 ncurves = EC_get_builtin_curves(NULL, 0); 225 if ((all_curves = calloc(ncurves, sizeof(EC_builtin_curve))) == NULL) 226 err(1, "calloc builtin curves"); 227 EC_get_builtin_curves(all_curves, ncurves); 228 229 for (curve_id = 0; curve_id < ncurves; curve_id++) 230 test_random_points_on_curve(&all_curves[curve_id]); 231 232 fprintf(stderr, "%s: %s\n", __func__, failed ? "FAILED" : "SUCCESS"); 233 234 free(all_curves); 235 return failed; 236 } 237 238 static const struct point_conversion { 239 const char *description; 240 int nid; 241 uint8_t octets[256]; 242 uint8_t octets_len; 243 int valid; 244 } point_conversions[] = { 245 { 246 .description = "point at infinity on sect571k1", 247 .nid = NID_sect571k1, 248 .octets = { 0x00 }, 249 .octets_len = 1, 250 .valid = 1, 251 }, 252 { 253 .description = "point at infinity on sect571k1 (flipped y_bit)", 254 .nid = NID_sect571k1, 255 .octets = { 0x01 }, 256 .octets_len = 1, 257 .valid = 0, 258 }, 259 { 260 .description = "zero x compressed point on sect571k1", 261 .nid = NID_sect571k1, 262 .octets = { 263 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 272 0x00, 273 }, 274 .octets_len = 73, 275 .valid = 1, 276 }, 277 { 278 .description = 279 "zero x compressed point on sect571k1 (flipped y_bit)", 280 .nid = NID_sect571k1, 281 .octets = { 282 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 291 0x00, 292 }, 293 .octets_len = 73, 294 .valid = 0, 295 }, 296 { 297 .description = "generic compressed point on sect571k1", 298 .nid = NID_sect571k1, 299 .octets = { 300 0x02, 0x00, 0x5e, 0x33, 0x9f, 0xd6, 0xf1, 0xae, 301 0x10, 0xbd, 0x48, 0xcf, 0xf1, 0x0d, 0x8e, 0x0e, 302 0xd7, 0x83, 0xce, 0xf0, 0x3d, 0x14, 0x06, 0x41, 303 0x29, 0x7d, 0x7e, 0xa3, 0x01, 0xf4, 0x9b, 0xa2, 304 0x8c, 0xa6, 0xab, 0x24, 0xa0, 0x9e, 0xfd, 0xc4, 305 0x2d, 0xc2, 0x95, 0xb4, 0xf9, 0xd4, 0xf4, 0x97, 306 0x53, 0x5d, 0xe9, 0xe3, 0x47, 0xc3, 0xa8, 0x6b, 307 0xbb, 0x27, 0x74, 0x6b, 0xfb, 0x26, 0xca, 0x96, 308 0x76, 0x5b, 0x36, 0xe8, 0x87, 0xb5, 0xc5, 0x6a, 309 0xc5, 310 }, 311 .octets_len = 73, 312 .valid = 1, 313 }, 314 { 315 .description = 316 "generic compressed point on sect571k1 (flipped y_bit)", 317 .nid = NID_sect571k1, 318 .octets = { 319 0x03, 0x00, 0x5e, 0x33, 0x9f, 0xd6, 0xf1, 0xae, 320 0x10, 0xbd, 0x48, 0xcf, 0xf1, 0x0d, 0x8e, 0x0e, 321 0xd7, 0x83, 0xce, 0xf0, 0x3d, 0x14, 0x06, 0x41, 322 0x29, 0x7d, 0x7e, 0xa3, 0x01, 0xf4, 0x9b, 0xa2, 323 0x8c, 0xa6, 0xab, 0x24, 0xa0, 0x9e, 0xfd, 0xc4, 324 0x2d, 0xc2, 0x95, 0xb4, 0xf9, 0xd4, 0xf4, 0x97, 325 0x53, 0x5d, 0xe9, 0xe3, 0x47, 0xc3, 0xa8, 0x6b, 326 0xbb, 0x27, 0x74, 0x6b, 0xfb, 0x26, 0xca, 0x96, 327 0x76, 0x5b, 0x36, 0xe8, 0x87, 0xb5, 0xc5, 0x6a, 328 0xc5, 329 }, 330 .octets_len = 73, 331 .valid = 1, 332 }, 333 { 334 .description = "zero x uncompressed point on sect571k1", 335 .nid = NID_sect571k1, 336 .octets = { 337 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 355 0x01, 356 }, 357 .octets_len = 145, 358 .valid = 1, 359 }, 360 { 361 .description = "zero x uncompressed point on sect571k1", 362 .nid = NID_sect571k1, 363 .octets = { 364 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 371 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 372 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 373 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 374 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 378 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 379 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 382 0x01, 383 }, 384 .octets_len = 145, 385 .valid = 0, 386 }, 387 { 388 .description = "generic uncompressed point on sect571k1", 389 .nid = NID_sect571k1, 390 .octets = { 391 0x04, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 392 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 393 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 394 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 395 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 396 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 397 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 398 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 399 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 400 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 401 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 402 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 403 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 404 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 405 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 406 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 407 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 408 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 409 0x28, 410 }, 411 .octets_len = 145, 412 .valid = 1, 413 }, 414 { 415 .description = 416 "generic uncompressed point on sect571k1 (flipped y_bit)", 417 .nid = NID_sect571k1, 418 .octets = { 419 0x05, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 420 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 421 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 422 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 423 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 424 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 425 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 426 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 427 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 428 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 429 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 430 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 431 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 432 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 433 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 434 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 435 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 436 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 437 0x28, 438 }, 439 .octets_len = 145, 440 .valid = 0, 441 }, 442 { 443 .description = "zero x hybrid point on sect571k1", 444 .nid = NID_sect571k1, 445 .octets = { 446 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 447 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 448 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 449 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 451 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 457 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 464 0x01, 465 }, 466 .octets_len = 145, 467 .valid = 1, 468 }, 469 { 470 .description = 471 "zero x hybrid point on sect571k1 (flipped y_bit)", 472 .nid = NID_sect571k1, 473 .octets = { 474 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 478 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 481 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 482 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 492 0x01, 493 }, 494 .octets_len = 145, 495 .valid = 0, 496 }, 497 { 498 .description = "generic hybrid point on sect571k1", 499 .nid = NID_sect571k1, 500 .octets = { 501 0x07, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 502 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 503 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 504 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 505 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 506 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 507 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 508 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 509 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 510 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 511 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 512 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 513 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 514 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 515 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 516 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 517 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 518 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 519 0x28, 520 }, 521 .octets_len = 145, 522 .valid = 1, 523 }, 524 { 525 .description = 526 "generic hybrid point on sect571k1 (flipped y_bit)", 527 .nid = NID_sect571k1, 528 .octets = { 529 0x06, 0x02, 0x2d, 0xf4, 0x72, 0x38, 0xc2, 0xbe, 530 0x0d, 0xa4, 0xf1, 0xfc, 0xe8, 0x78, 0xe6, 0xad, 531 0x5c, 0xaa, 0xd9, 0x7f, 0x7c, 0xa9, 0x4c, 0xe4, 532 0xd2, 0xae, 0xba, 0xaa, 0x8c, 0x9d, 0x4c, 0xac, 533 0x85, 0x00, 0xe1, 0xfa, 0x33, 0x73, 0x51, 0x52, 534 0x5a, 0x4e, 0x75, 0x67, 0x1d, 0x0a, 0x2a, 0xd2, 535 0x38, 0xb2, 0x9b, 0xe8, 0xec, 0xbe, 0x07, 0x8b, 536 0xc0, 0x95, 0x77, 0xe9, 0x55, 0x0c, 0x6c, 0x0e, 537 0x02, 0x3b, 0x34, 0xe2, 0xa8, 0x29, 0xd2, 0x97, 538 0xd9, 0x05, 0xa2, 0x6f, 0xa8, 0x6f, 0x1c, 0x3a, 539 0xf6, 0x12, 0x42, 0x1a, 0x26, 0x6e, 0x87, 0xf3, 540 0x19, 0x04, 0x20, 0xa5, 0x29, 0x78, 0xee, 0xcf, 541 0x91, 0x06, 0xd2, 0x5a, 0x62, 0x2a, 0x7f, 0x1d, 542 0xa0, 0x7b, 0xb4, 0x31, 0x9c, 0xd2, 0x14, 0x60, 543 0xf5, 0x9b, 0xea, 0x4a, 0x41, 0xad, 0x47, 0x72, 544 0xf9, 0x01, 0xed, 0x7f, 0x5a, 0x27, 0x64, 0xa2, 545 0x53, 0x4e, 0x18, 0x51, 0x33, 0xa8, 0x1e, 0x3a, 546 0xc2, 0xe7, 0x2c, 0xe3, 0x63, 0x6d, 0x06, 0x29, 547 0x28, 548 }, 549 .octets_len = 145, 550 .valid = 0, 551 }, 552 553 { 554 .description = "point at infinity on secp256r1", 555 .nid = NID_X9_62_prime256v1, 556 .octets = { 0x00 }, 557 .octets_len = 1, 558 .valid = 1, 559 }, 560 { 561 .description = "point at infinity on secp256r1 (flipped y_bit)", 562 .nid = NID_X9_62_prime256v1, 563 .octets = { 0x01 }, 564 .octets_len = 1, 565 .valid = 0, 566 }, 567 { 568 .description = "zero x compressed point on secp256r1", 569 .nid = NID_X9_62_prime256v1, 570 .octets = { 571 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 575 0x00, 576 }, 577 .octets_len = 33, 578 .valid = 1, 579 }, 580 { 581 .description = 582 "zero x compressed point on secp256r1 (flipped y_bit)", 583 .nid = NID_X9_62_prime256v1, 584 .octets = { 585 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 589 0x00, 590 }, 591 .octets_len = 33, 592 .valid = 1, 593 }, 594 { 595 .description = "generic compressed point on secp256r1", 596 .nid = NID_X9_62_prime256v1, 597 .octets = { 598 0x03, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 599 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 600 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 601 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 602 0xdd, 603 }, 604 .octets_len = 33, 605 .valid = 1, 606 }, 607 { 608 .description = 609 "generic compressed point on secp256r1 (flipped y_bit)", 610 .nid = NID_X9_62_prime256v1, 611 .octets = { 612 0x02, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 613 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 614 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 615 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 616 0xdd, 617 }, 618 .octets_len = 33, 619 .valid = 1, 620 }, 621 { 622 .description = "zero x uncompressed point #1 on secp256r1", 623 .nid = NID_X9_62_prime256v1, 624 .octets = { 625 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 629 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 630 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 631 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 632 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 633 0xf4, 634 }, 635 .octets_len = 65, 636 .valid = 1, 637 }, 638 { 639 .description = 640 "zero x uncompressed point #1 on secp256r1 (flipped y_bit)", 641 .nid = NID_X9_62_prime256v1, 642 .octets = { 643 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 647 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 648 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 649 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 650 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 651 0xf4, 652 }, 653 .octets_len = 65, 654 .valid = 0, 655 }, 656 { 657 .description = "zero x uncompressed point #2 on secp256r1", 658 .nid = NID_X9_62_prime256v1, 659 .octets = { 660 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 663 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 664 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 665 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 666 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 667 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 668 0x0b, 669 }, 670 .octets_len = 65, 671 .valid = 1, 672 }, 673 { 674 .description = 675 "zero x uncompressed point #2 on secp256r1 (flipped y_bit)", 676 .nid = NID_X9_62_prime256v1, 677 .octets = { 678 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 682 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 683 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 684 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 685 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 686 0x0b, 687 }, 688 .octets_len = 65, 689 .valid = 0, 690 }, 691 { 692 .description = "generic uncompressed point on secp256r1", 693 .nid = NID_X9_62_prime256v1, 694 .octets = { 695 0x04, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 696 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 697 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 698 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 699 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 700 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 701 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 702 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 703 0x03, 704 }, 705 .octets_len = 65, 706 .valid = 1, 707 }, 708 { 709 .description = 710 "generic uncompressed point on secp256r1 (flipped y_bit)", 711 .nid = NID_X9_62_prime256v1, 712 .octets = { 713 0x05, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 714 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 715 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 716 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 717 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 718 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 719 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 720 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 721 0x03, 722 }, 723 .octets_len = 65, 724 .valid = 0, 725 }, 726 { 727 .description = "zero x hybrid point #1 on secp256r1", 728 .nid = NID_X9_62_prime256v1, 729 .octets = { 730 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 732 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 733 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 734 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 735 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 736 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 737 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 738 0xf4, 739 }, 740 .octets_len = 65, 741 .valid = 1, 742 }, 743 { 744 .description = 745 "zero x hybrid point #1 on secp256r1 (flipped y_bit)", 746 .nid = NID_X9_62_prime256v1, 747 .octets = { 748 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 752 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 753 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 754 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 755 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 756 0xf4, 757 }, 758 .octets_len = 65, 759 .valid = 0, 760 }, 761 { 762 .description = "zero x hybrid point #2 on secp256r1", 763 .nid = NID_X9_62_prime256v1, 764 .octets = { 765 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 769 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 770 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 771 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 772 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 773 0x0b, 774 }, 775 .octets_len = 65, 776 .valid = 1, 777 }, 778 { 779 .description = 780 "zero x hybrid point #2 on secp256r1 (flipped y_bit)", 781 .nid = NID_X9_62_prime256v1, 782 .octets = { 783 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 786 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 787 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 788 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 789 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 790 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 791 0x0b, 792 }, 793 .octets_len = 65, 794 .valid = 0, 795 }, 796 { 797 .description = "generic hybrid point on secp256r1", 798 .nid = NID_X9_62_prime256v1, 799 .octets = { 800 0x07, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 801 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 802 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 803 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 804 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 805 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 806 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 807 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 808 0xc5, 809 }, 810 .octets_len = 65, 811 .valid = 1, 812 }, 813 { 814 .description = 815 "generic hybrid point on secp256r1 (flipped y_bit)", 816 .nid = NID_X9_62_prime256v1, 817 .octets = { 818 0x06, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 819 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 820 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 821 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 822 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 823 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 824 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 825 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 826 0xc5, 827 }, 828 .octets_len = 65, 829 .valid = 0, 830 }, 831 }; 832 833 static const size_t N_POINT_CONVERSIONS = 834 sizeof(point_conversions) / sizeof(point_conversions[0]); 835 836 static int 837 point_conversion_form_y_bit(const struct point_conversion *test) 838 { 839 EC_GROUP *group = NULL; 840 EC_POINT *point = NULL; 841 int ret; 842 int failed = 0; 843 844 if ((group = EC_GROUP_new_by_curve_name(test->nid)) == NULL) 845 errx(1, "group"); 846 if ((point = EC_POINT_new(group)) == NULL) 847 errx(1, "point"); 848 849 ret = EC_POINT_oct2point(group, point, test->octets, test->octets_len, 850 NULL); 851 if (ret != test->valid) { 852 fprintf(stderr, "%s want %d got %d\n", test->description, 853 test->valid, ret); 854 failed |= 1; 855 } 856 857 EC_GROUP_free(group); 858 EC_POINT_free(point); 859 860 return failed; 861 } 862 863 static int 864 test_point_conversions(void) 865 { 866 size_t i; 867 int failed = 0; 868 869 for (i = 0; i < N_POINT_CONVERSIONS; i++) 870 failed |= point_conversion_form_y_bit(&point_conversions[i]); 871 872 fprintf(stderr, "%s: %s\n", __func__, failed ? "FAILED" : "SUCCESS"); 873 874 return failed; 875 } 876 877 int 878 main(int argc, char **argv) 879 { 880 int failed = 0; 881 882 failed |= test_random_points(); 883 failed |= test_hybrid_corner_case(); 884 failed |= test_point_conversions(); 885 886 fprintf(stderr, "%s\n", failed ? "FAILED" : "SUCCESS"); 887 888 return failed; 889 } 890