1 /* $OpenBSD: ec_point_conversion.c,v 1.1 2021/04/21 20:15:08 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 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 int 239 main(int argc, char **argv) 240 { 241 int failed = 0; 242 243 failed |= test_random_points(); 244 failed |= hybrid_corner_case(); 245 246 fprintf(stderr, "%s\n", failed ? "FAILED" : "SUCCESS"); 247 248 return failed; 249 } 250