1 /* $OpenBSD: ec_point_conversion.c,v 1.17 2024/10/23 15:06:46 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 #include <string.h> 23 24 #include <openssl/bn.h> 25 #include <openssl/ec.h> 26 #include <openssl/objects.h> 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 if (len % 8) 60 fprintf(stderr, "\n"); 61 } 62 63 static int 64 roundtrip(EC_GROUP *group, EC_POINT *point, int form, BIGNUM *x, BIGNUM *y) 65 { 66 BIGNUM *x_out = NULL, *y_out = NULL; 67 size_t len; 68 uint8_t *buf = NULL; 69 int failed = 1; 70 71 if ((len = EC_POINT_point2oct(group, point, form, NULL, 0, NULL)) == 0) 72 errx(1, "point2oct"); 73 if ((buf = malloc(len)) == NULL) 74 errx(1, "malloc"); 75 if (EC_POINT_point2oct(group, point, form, buf, len, NULL) != len) 76 errx(1, "point2oct"); 77 78 if (!EC_POINT_oct2point(group, point, buf, len, NULL)) 79 errx(1, "%s oct2point", form2str(form)); 80 81 if ((x_out = BN_new()) == NULL) 82 errx(1, "new x_out"); 83 if ((y_out = BN_new()) == NULL) 84 errx(1, "new y_out"); 85 86 if (!EC_POINT_get_affine_coordinates(group, point, x_out, y_out, NULL)) 87 errx(1, "get affine"); 88 89 if (BN_cmp(x, x_out) != 0) { 90 warnx("%s: x", form2str(form)); 91 goto err; 92 } 93 if (BN_cmp(y, y_out) != 0) { 94 warnx("%s: y", form2str(form)); 95 goto err; 96 } 97 98 failed = 0; 99 100 err: 101 if (failed) 102 hexdump(buf, len); 103 104 free(buf); 105 BN_free(x_out); 106 BN_free(y_out); 107 108 return failed; 109 } 110 111 /* XXX This only tests multiples of the generator for now... */ 112 static int 113 test_random_points_on_curve(EC_builtin_curve *curve) 114 { 115 EC_GROUP *group; 116 BIGNUM *order = NULL; 117 BIGNUM *random; 118 BIGNUM *x, *y; 119 size_t i, j; 120 int failed = 0; 121 122 if ((group = EC_GROUP_new_by_curve_name(curve->nid)) == NULL) 123 errx(1, "EC_GROUP_new_by_curve_name(%s)", 124 OBJ_nid2sn(curve->nid)); 125 126 if ((order = BN_new()) == NULL) 127 errx(1, "BN_new order"); 128 if ((random = BN_new()) == NULL) 129 errx(1, "BN_new random"); 130 if ((x = BN_new()) == NULL) 131 errx(1, "BN_new x"); 132 if ((y = BN_new()) == NULL) 133 errx(1, "BN_new y"); 134 135 if (!EC_GROUP_get_order(group, order, NULL)) 136 errx(1, "EC_group_get_order"); 137 138 for (i = 0; i < N_RANDOM_POINTS; i++) { 139 EC_POINT *random_point; 140 141 do { 142 if (!BN_rand_range(random, order)) 143 errx(1, "BN_rand_range"); 144 } while (BN_is_zero(random)); 145 146 if ((random_point = EC_POINT_new(group)) == NULL) 147 errx(1, "EC_POINT_new"); 148 149 if (!EC_POINT_mul(group, random_point, random, NULL, NULL, NULL)) 150 errx(1, "EC_POINT_mul"); 151 152 if (EC_POINT_is_at_infinity(group, random_point)) { 153 EC_POINT_free(random_point); 154 155 warnx("info: got infinity"); 156 fprintf(stderr, "random = "); 157 BN_print_fp(stderr, random); 158 fprintf(stderr, "\n"); 159 160 continue; 161 } 162 163 if (!EC_POINT_get_affine_coordinates(group, random_point, 164 x, y, NULL)) 165 errx(1, "EC_POINT_get_affine_coordinates"); 166 167 for (j = 0; j < N_FORMS; j++) 168 failed |= roundtrip(group, random_point, forms[j], x, y); 169 170 EC_POINT_free(random_point); 171 } 172 173 BN_free(order); 174 BN_free(random); 175 BN_free(x); 176 BN_free(y); 177 EC_GROUP_free(group); 178 179 return failed; 180 } 181 182 static int 183 test_random_points(void) 184 { 185 EC_builtin_curve *all_curves = NULL; 186 size_t ncurves = 0; 187 size_t curve_id; 188 int failed = 0; 189 190 ncurves = EC_get_builtin_curves(NULL, 0); 191 if ((all_curves = calloc(ncurves, sizeof(EC_builtin_curve))) == NULL) 192 err(1, "calloc builtin curves"); 193 EC_get_builtin_curves(all_curves, ncurves); 194 195 for (curve_id = 0; curve_id < ncurves; curve_id++) 196 failed |= test_random_points_on_curve(&all_curves[curve_id]); 197 198 fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); 199 200 free(all_curves); 201 return failed; 202 } 203 204 static const struct point_conversion { 205 const char *description; 206 int nid; 207 uint8_t octets[256]; 208 size_t octets_len; 209 int valid; 210 int point_at_infinity; 211 } point_conversions[] = { 212 /* XXX - now that sect571 is no longer tested, add another test? */ 213 { 214 .description = "point at infinity on secp256r1", 215 .nid = NID_X9_62_prime256v1, 216 .octets = { 0x00 }, 217 .octets_len = 1, 218 .valid = 1, 219 .point_at_infinity = 1, 220 }, 221 { 222 .description = "point at infinity on secp256r1 (flipped y_bit)", 223 .nid = NID_X9_62_prime256v1, 224 .octets = { 0x01 }, 225 .octets_len = 1, 226 .valid = 0, 227 .point_at_infinity = 1, 228 }, 229 { 230 .description = "zero x compressed point on secp256r1", 231 .nid = NID_X9_62_prime256v1, 232 .octets = { 233 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 237 0x00, 238 }, 239 .octets_len = 33, 240 .valid = 1, 241 }, 242 { 243 .description = 244 "zero x compressed point on secp256r1 (flipped y_bit)", 245 .nid = NID_X9_62_prime256v1, 246 .octets = { 247 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 251 0x00, 252 }, 253 .octets_len = 33, 254 .valid = 1, 255 }, 256 { 257 .description = "generic compressed point on secp256r1", 258 .nid = NID_X9_62_prime256v1, 259 .octets = { 260 0x03, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 261 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 262 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 263 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 264 0xdd, 265 }, 266 .octets_len = 33, 267 .valid = 1, 268 }, 269 { 270 .description = 271 "generic compressed point on secp256r1 (flipped y_bit)", 272 .nid = NID_X9_62_prime256v1, 273 .octets = { 274 0x02, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 275 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 276 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 277 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 278 0xdd, 279 }, 280 .octets_len = 33, 281 .valid = 1, 282 }, 283 { 284 .description = "zero x uncompressed point #1 on secp256r1", 285 .nid = NID_X9_62_prime256v1, 286 .octets = { 287 0x04, 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, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 292 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 293 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 294 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 295 0xf4, 296 }, 297 .octets_len = 65, 298 .valid = 1, 299 }, 300 { 301 .description = 302 "zero x uncompressed point #1 on secp256r1 (flipped y_bit)", 303 .nid = NID_X9_62_prime256v1, 304 .octets = { 305 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 309 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 310 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 311 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 312 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 313 0xf4, 314 }, 315 .octets_len = 65, 316 .valid = 0, 317 }, 318 { 319 .description = "zero x uncompressed point #2 on secp256r1", 320 .nid = NID_X9_62_prime256v1, 321 .octets = { 322 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 326 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 327 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 328 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 329 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 330 0x0b, 331 }, 332 .octets_len = 65, 333 .valid = 1, 334 }, 335 { 336 .description = 337 "zero x uncompressed point #2 on secp256r1 (flipped y_bit)", 338 .nid = NID_X9_62_prime256v1, 339 .octets = { 340 0x05, 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, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 345 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 346 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 347 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 348 0x0b, 349 }, 350 .octets_len = 65, 351 .valid = 0, 352 }, 353 { 354 .description = "generic uncompressed point on secp256r1", 355 .nid = NID_X9_62_prime256v1, 356 .octets = { 357 0x04, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 358 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 359 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 360 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 361 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 362 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 363 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 364 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 365 0x03, 366 }, 367 .octets_len = 65, 368 .valid = 1, 369 }, 370 { 371 .description = 372 "generic uncompressed point on secp256r1 (flipped y_bit)", 373 .nid = NID_X9_62_prime256v1, 374 .octets = { 375 0x05, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 376 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 377 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 378 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 379 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 380 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 381 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 382 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 383 0x03, 384 }, 385 .octets_len = 65, 386 .valid = 0, 387 }, 388 { 389 .description = "zero x hybrid point #1 on secp256r1", 390 .nid = NID_X9_62_prime256v1, 391 .octets = { 392 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 396 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 397 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 398 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 399 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 400 0xf4, 401 }, 402 .octets_len = 65, 403 .valid = 1, 404 }, 405 { 406 .description = 407 "zero x hybrid point #1 on secp256r1 (flipped y_bit)", 408 .nid = NID_X9_62_prime256v1, 409 .octets = { 410 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 412 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 413 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 414 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 415 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 416 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 417 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 418 0xf4, 419 }, 420 .octets_len = 65, 421 .valid = 0, 422 }, 423 { 424 .description = "zero x hybrid point #2 on secp256r1", 425 .nid = NID_X9_62_prime256v1, 426 .octets = { 427 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 428 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 431 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 432 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 433 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 434 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 435 0x0b, 436 }, 437 .octets_len = 65, 438 .valid = 1, 439 }, 440 { 441 .description = 442 "zero x hybrid point #2 on secp256r1 (flipped y_bit)", 443 .nid = NID_X9_62_prime256v1, 444 .octets = { 445 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 446 0x00, 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, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 450 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 451 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 452 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 453 0x0b, 454 }, 455 .octets_len = 65, 456 .valid = 0, 457 }, 458 { 459 .description = "generic hybrid point on secp256r1", 460 .nid = NID_X9_62_prime256v1, 461 .octets = { 462 0x07, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 463 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 464 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 465 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 466 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 467 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 468 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 469 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 470 0xc5, 471 }, 472 .octets_len = 65, 473 .valid = 1, 474 }, 475 { 476 .description = 477 "generic hybrid point on secp256r1 (flipped y_bit)", 478 .nid = NID_X9_62_prime256v1, 479 .octets = { 480 0x06, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 481 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 482 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 483 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 484 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 485 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 486 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 487 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 488 0xc5, 489 }, 490 .octets_len = 65, 491 .valid = 0, 492 }, 493 }; 494 495 static const size_t N_POINT_CONVERSIONS = 496 sizeof(point_conversions) / sizeof(point_conversions[0]); 497 498 static int 499 check_point_at_infinity(const EC_GROUP *group, const EC_POINT *point, 500 const struct point_conversion *test) 501 { 502 const uint8_t conversion_forms[4] = { 0x00, 0x02, 0x04, 0x06, }; 503 uint8_t buf[1]; 504 uint8_t form; 505 size_t i, ret; 506 int failed = 0; 507 508 /* The form for the point at infinity is expected to fail. */ 509 form = conversion_forms[0]; 510 511 ret = EC_POINT_point2oct(group, point, form, buf, sizeof(buf), NULL); 512 if (ret != 0) { 513 fprintf(stderr, "FAIL: %s: expected encoding with form 0x%02x " 514 "to fail, got %zu\n", test->description, form, ret); 515 failed |= 1; 516 } 517 518 /* For all other forms we expect the zero octet. */ 519 for (i = 1; i < sizeof(conversion_forms); i++) { 520 form = conversion_forms[i]; 521 522 ret = EC_POINT_point2oct(group, point, form, buf, sizeof(buf), NULL); 523 if (ret != 1) { 524 fprintf(stderr, "FAIL: %s: expected success, got %zu\n", 525 test->description, ret); 526 failed |= 1; 527 continue; 528 } 529 530 if (memcmp(buf, test->octets, test->octets_len) != 0) { 531 fprintf(stderr, "FAIL: %s: want 0x%02x, got 0x%02x\n", 532 test->description, test->octets[0], buf[0]); 533 failed |= 1; 534 continue; 535 } 536 } 537 538 return failed; 539 } 540 541 static int 542 point_conversion_form_y_bit(const struct point_conversion *test) 543 { 544 EC_GROUP *group = NULL; 545 EC_POINT *point = NULL; 546 int ret; 547 int failed = 0; 548 549 if ((group = EC_GROUP_new_by_curve_name(test->nid)) == NULL) 550 errx(1, "group"); 551 if ((point = EC_POINT_new(group)) == NULL) 552 errx(1, "point"); 553 554 ret = EC_POINT_oct2point(group, point, test->octets, test->octets_len, 555 NULL); 556 if (ret != test->valid) { 557 fprintf(stderr, "%s want %d got %d\n", test->description, 558 test->valid, ret); 559 failed |= 1; 560 } 561 562 if (test->valid && test->point_at_infinity) { 563 failed |= check_point_at_infinity(group, point, test); 564 } else if (test->valid) { 565 uint8_t buf[256]; 566 uint8_t form = test->octets[0] & 0x06; 567 size_t len; 568 569 len = EC_POINT_point2oct(group, point, form, buf, sizeof(buf), NULL); 570 571 if (len != test->octets_len) { 572 fprintf(stderr, "%s: EC_POINT_point2oct: want %zu, got %zu\n", 573 test->description, test->octets_len, len); 574 failed |= 1; 575 goto failed; 576 } 577 if (memcmp(test->octets, buf, len) != 0) { 578 fprintf(stderr, "%s: unexpected encoding\nwant:\n", 579 test->description); 580 hexdump(test->octets, test->octets_len); 581 fprintf(stderr, "\ngot:\n"); 582 hexdump(buf, len); 583 failed |= 1; 584 goto failed; 585 } 586 } 587 588 failed: 589 EC_GROUP_free(group); 590 EC_POINT_free(point); 591 592 return failed; 593 } 594 595 static int 596 test_point_conversions(void) 597 { 598 size_t i; 599 int failed = 0; 600 601 for (i = 0; i < N_POINT_CONVERSIONS; i++) 602 failed |= point_conversion_form_y_bit(&point_conversions[i]); 603 604 fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); 605 606 return failed; 607 } 608 609 int 610 main(int argc, char **argv) 611 { 612 int failed = 0; 613 614 failed |= test_random_points(); 615 failed |= test_point_conversions(); 616 617 return failed; 618 } 619