]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
33388b44 | 2 | * Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved. |
aa8f3d76 | 3 | * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved |
84b08eee | 4 | * |
a7f182b7 | 5 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
4f22f405 RS |
6 | * this file except in compliance with the License. You can obtain a copy |
7 | * in the file LICENSE in the source distribution or at | |
8 | * https://www.openssl.org/source/license.html | |
84b08eee | 9 | */ |
4f22f405 | 10 | |
579422c8 P |
11 | /* |
12 | * ECDSA low level APIs are deprecated for public use, but still ok for | |
13 | * internal use. | |
14 | */ | |
15 | #include "internal/deprecated.h" | |
16 | ||
84b08eee DSH |
17 | #include <openssl/err.h> |
18 | #include <openssl/symhacks.h> | |
19 | ||
706457b7 | 20 | #include "ec_local.h" |
84b08eee | 21 | |
0f113f3e MC |
22 | int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, |
23 | EC_POINT *point, | |
24 | const BIGNUM *x_, int y_bit, | |
25 | BN_CTX *ctx) | |
26 | { | |
27 | BN_CTX *new_ctx = NULL; | |
28 | BIGNUM *tmp1, *tmp2, *x, *y; | |
29 | int ret = 0; | |
30 | ||
f844f9eb | 31 | #ifndef FIPS_MODULE |
0f113f3e MC |
32 | /* clear error queue */ |
33 | ERR_clear_error(); | |
a9612d6c | 34 | #endif |
0f113f3e MC |
35 | |
36 | if (ctx == NULL) { | |
a9612d6c | 37 | ctx = new_ctx = BN_CTX_new_ex(group->libctx); |
0f113f3e MC |
38 | if (ctx == NULL) |
39 | return 0; | |
40 | } | |
41 | ||
42 | y_bit = (y_bit != 0); | |
43 | ||
44 | BN_CTX_start(ctx); | |
45 | tmp1 = BN_CTX_get(ctx); | |
46 | tmp2 = BN_CTX_get(ctx); | |
47 | x = BN_CTX_get(ctx); | |
48 | y = BN_CTX_get(ctx); | |
49 | if (y == NULL) | |
50 | goto err; | |
51 | ||
35a1cc90 MC |
52 | /*- |
53 | * Recover y. We have a Weierstrass equation | |
54 | * y^2 = x^3 + a*x + b, | |
55 | * so y is one of the square roots of x^3 + a*x + b. | |
56 | */ | |
0f113f3e MC |
57 | |
58 | /* tmp1 := x^3 */ | |
59 | if (!BN_nnmod(x, x_, group->field, ctx)) | |
60 | goto err; | |
61 | if (group->meth->field_decode == 0) { | |
62 | /* field_{sqr,mul} work on standard representation */ | |
63 | if (!group->meth->field_sqr(group, tmp2, x_, ctx)) | |
64 | goto err; | |
65 | if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) | |
66 | goto err; | |
67 | } else { | |
68 | if (!BN_mod_sqr(tmp2, x_, group->field, ctx)) | |
69 | goto err; | |
70 | if (!BN_mod_mul(tmp1, tmp2, x_, group->field, ctx)) | |
71 | goto err; | |
72 | } | |
73 | ||
74 | /* tmp1 := tmp1 + a*x */ | |
75 | if (group->a_is_minus3) { | |
76 | if (!BN_mod_lshift1_quick(tmp2, x, group->field)) | |
77 | goto err; | |
78 | if (!BN_mod_add_quick(tmp2, tmp2, x, group->field)) | |
79 | goto err; | |
80 | if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, group->field)) | |
81 | goto err; | |
82 | } else { | |
83 | if (group->meth->field_decode) { | |
84 | if (!group->meth->field_decode(group, tmp2, group->a, ctx)) | |
85 | goto err; | |
86 | if (!BN_mod_mul(tmp2, tmp2, x, group->field, ctx)) | |
87 | goto err; | |
88 | } else { | |
89 | /* field_mul works on standard representation */ | |
90 | if (!group->meth->field_mul(group, tmp2, group->a, x, ctx)) | |
91 | goto err; | |
92 | } | |
93 | ||
94 | if (!BN_mod_add_quick(tmp1, tmp1, tmp2, group->field)) | |
95 | goto err; | |
96 | } | |
97 | ||
98 | /* tmp1 := tmp1 + b */ | |
99 | if (group->meth->field_decode) { | |
100 | if (!group->meth->field_decode(group, tmp2, group->b, ctx)) | |
101 | goto err; | |
102 | if (!BN_mod_add_quick(tmp1, tmp1, tmp2, group->field)) | |
103 | goto err; | |
104 | } else { | |
105 | if (!BN_mod_add_quick(tmp1, tmp1, group->b, group->field)) | |
106 | goto err; | |
107 | } | |
108 | ||
109 | if (!BN_mod_sqrt(y, tmp1, group->field, ctx)) { | |
f844f9eb | 110 | #ifndef FIPS_MODULE |
0f113f3e MC |
111 | unsigned long err = ERR_peek_last_error(); |
112 | ||
113 | if (ERR_GET_LIB(err) == ERR_LIB_BN | |
114 | && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { | |
115 | ERR_clear_error(); | |
9311d0c4 | 116 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_COMPRESSED_POINT); |
0f113f3e | 117 | } else |
a9612d6c MC |
118 | #endif |
119 | { | |
9311d0c4 | 120 | ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); |
a9612d6c | 121 | } |
0f113f3e MC |
122 | goto err; |
123 | } | |
124 | ||
125 | if (y_bit != BN_is_odd(y)) { | |
126 | if (BN_is_zero(y)) { | |
127 | int kron; | |
128 | ||
129 | kron = BN_kronecker(x, group->field, ctx); | |
130 | if (kron == -2) | |
131 | goto err; | |
132 | ||
133 | if (kron == 1) | |
9311d0c4 | 134 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_COMPRESSION_BIT); |
0f113f3e MC |
135 | else |
136 | /* | |
46f4e1be | 137 | * BN_mod_sqrt() should have caught this error (not a square) |
0f113f3e | 138 | */ |
9311d0c4 | 139 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_COMPRESSED_POINT); |
0f113f3e MC |
140 | goto err; |
141 | } | |
142 | if (!BN_usub(y, group->field, y)) | |
143 | goto err; | |
144 | } | |
145 | if (y_bit != BN_is_odd(y)) { | |
9311d0c4 | 146 | ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR); |
0f113f3e MC |
147 | goto err; |
148 | } | |
149 | ||
9cc570d4 | 150 | if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) |
0f113f3e MC |
151 | goto err; |
152 | ||
153 | ret = 1; | |
84b08eee DSH |
154 | |
155 | err: | |
0f113f3e | 156 | BN_CTX_end(ctx); |
23a1d5e9 | 157 | BN_CTX_free(new_ctx); |
0f113f3e MC |
158 | return ret; |
159 | } | |
160 | ||
161 | size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, | |
162 | point_conversion_form_t form, | |
163 | unsigned char *buf, size_t len, BN_CTX *ctx) | |
164 | { | |
165 | size_t ret; | |
166 | BN_CTX *new_ctx = NULL; | |
167 | int used_ctx = 0; | |
168 | BIGNUM *x, *y; | |
169 | size_t field_len, i, skip; | |
170 | ||
171 | if ((form != POINT_CONVERSION_COMPRESSED) | |
172 | && (form != POINT_CONVERSION_UNCOMPRESSED) | |
173 | && (form != POINT_CONVERSION_HYBRID)) { | |
9311d0c4 | 174 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_FORM); |
0f113f3e MC |
175 | goto err; |
176 | } | |
177 | ||
178 | if (EC_POINT_is_at_infinity(group, point)) { | |
179 | /* encodes to a single 0 octet */ | |
180 | if (buf != NULL) { | |
181 | if (len < 1) { | |
9311d0c4 | 182 | ERR_raise(ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL); |
0f113f3e MC |
183 | return 0; |
184 | } | |
185 | buf[0] = 0; | |
186 | } | |
187 | return 1; | |
188 | } | |
189 | ||
190 | /* ret := required output buffer length */ | |
191 | field_len = BN_num_bytes(group->field); | |
192 | ret = | |
193 | (form == | |
194 | POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; | |
195 | ||
196 | /* if 'buf' is NULL, just return required length */ | |
197 | if (buf != NULL) { | |
198 | if (len < ret) { | |
9311d0c4 | 199 | ERR_raise(ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL); |
0f113f3e MC |
200 | goto err; |
201 | } | |
202 | ||
203 | if (ctx == NULL) { | |
a9612d6c | 204 | ctx = new_ctx = BN_CTX_new_ex(group->libctx); |
0f113f3e MC |
205 | if (ctx == NULL) |
206 | return 0; | |
207 | } | |
208 | ||
209 | BN_CTX_start(ctx); | |
210 | used_ctx = 1; | |
211 | x = BN_CTX_get(ctx); | |
212 | y = BN_CTX_get(ctx); | |
213 | if (y == NULL) | |
214 | goto err; | |
215 | ||
9cc570d4 | 216 | if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) |
0f113f3e MC |
217 | goto err; |
218 | ||
219 | if ((form == POINT_CONVERSION_COMPRESSED | |
220 | || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y)) | |
221 | buf[0] = form + 1; | |
222 | else | |
223 | buf[0] = form; | |
224 | ||
225 | i = 1; | |
226 | ||
227 | skip = field_len - BN_num_bytes(x); | |
228 | if (skip > field_len) { | |
9311d0c4 | 229 | ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR); |
0f113f3e MC |
230 | goto err; |
231 | } | |
232 | while (skip > 0) { | |
233 | buf[i++] = 0; | |
234 | skip--; | |
235 | } | |
236 | skip = BN_bn2bin(x, buf + i); | |
237 | i += skip; | |
238 | if (i != 1 + field_len) { | |
9311d0c4 | 239 | ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR); |
0f113f3e MC |
240 | goto err; |
241 | } | |
242 | ||
243 | if (form == POINT_CONVERSION_UNCOMPRESSED | |
244 | || form == POINT_CONVERSION_HYBRID) { | |
245 | skip = field_len - BN_num_bytes(y); | |
246 | if (skip > field_len) { | |
9311d0c4 | 247 | ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR); |
0f113f3e MC |
248 | goto err; |
249 | } | |
250 | while (skip > 0) { | |
251 | buf[i++] = 0; | |
252 | skip--; | |
253 | } | |
254 | skip = BN_bn2bin(y, buf + i); | |
255 | i += skip; | |
256 | } | |
257 | ||
258 | if (i != ret) { | |
9311d0c4 | 259 | ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR); |
0f113f3e MC |
260 | goto err; |
261 | } | |
262 | } | |
263 | ||
264 | if (used_ctx) | |
265 | BN_CTX_end(ctx); | |
23a1d5e9 | 266 | BN_CTX_free(new_ctx); |
0f113f3e | 267 | return ret; |
84b08eee DSH |
268 | |
269 | err: | |
0f113f3e MC |
270 | if (used_ctx) |
271 | BN_CTX_end(ctx); | |
23a1d5e9 | 272 | BN_CTX_free(new_ctx); |
0f113f3e MC |
273 | return 0; |
274 | } | |
84b08eee DSH |
275 | |
276 | int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | |
0f113f3e MC |
277 | const unsigned char *buf, size_t len, BN_CTX *ctx) |
278 | { | |
279 | point_conversion_form_t form; | |
280 | int y_bit; | |
281 | BN_CTX *new_ctx = NULL; | |
282 | BIGNUM *x, *y; | |
283 | size_t field_len, enc_len; | |
284 | int ret = 0; | |
285 | ||
286 | if (len == 0) { | |
9311d0c4 | 287 | ERR_raise(ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL); |
0f113f3e MC |
288 | return 0; |
289 | } | |
290 | form = buf[0]; | |
291 | y_bit = form & 1; | |
292 | form = form & ~1U; | |
293 | if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) | |
294 | && (form != POINT_CONVERSION_UNCOMPRESSED) | |
295 | && (form != POINT_CONVERSION_HYBRID)) { | |
9311d0c4 | 296 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
0f113f3e MC |
297 | return 0; |
298 | } | |
299 | if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) { | |
9311d0c4 | 300 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
0f113f3e MC |
301 | return 0; |
302 | } | |
303 | ||
304 | if (form == 0) { | |
305 | if (len != 1) { | |
9311d0c4 | 306 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
0f113f3e MC |
307 | return 0; |
308 | } | |
309 | ||
310 | return EC_POINT_set_to_infinity(group, point); | |
311 | } | |
312 | ||
313 | field_len = BN_num_bytes(group->field); | |
314 | enc_len = | |
315 | (form == | |
316 | POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; | |
317 | ||
318 | if (len != enc_len) { | |
9311d0c4 | 319 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
0f113f3e MC |
320 | return 0; |
321 | } | |
322 | ||
323 | if (ctx == NULL) { | |
a9612d6c | 324 | ctx = new_ctx = BN_CTX_new_ex(group->libctx); |
0f113f3e MC |
325 | if (ctx == NULL) |
326 | return 0; | |
327 | } | |
328 | ||
329 | BN_CTX_start(ctx); | |
330 | x = BN_CTX_get(ctx); | |
331 | y = BN_CTX_get(ctx); | |
332 | if (y == NULL) | |
333 | goto err; | |
334 | ||
335 | if (!BN_bin2bn(buf + 1, field_len, x)) | |
336 | goto err; | |
337 | if (BN_ucmp(x, group->field) >= 0) { | |
9311d0c4 | 338 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
0f113f3e MC |
339 | goto err; |
340 | } | |
341 | ||
342 | if (form == POINT_CONVERSION_COMPRESSED) { | |
9cc570d4 | 343 | if (!EC_POINT_set_compressed_coordinates(group, point, x, y_bit, ctx)) |
0f113f3e MC |
344 | goto err; |
345 | } else { | |
346 | if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) | |
347 | goto err; | |
348 | if (BN_ucmp(y, group->field) >= 0) { | |
9311d0c4 | 349 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
0f113f3e MC |
350 | goto err; |
351 | } | |
352 | if (form == POINT_CONVERSION_HYBRID) { | |
353 | if (y_bit != BN_is_odd(y)) { | |
9311d0c4 | 354 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
0f113f3e MC |
355 | goto err; |
356 | } | |
357 | } | |
358 | ||
1e2012b7 | 359 | /* |
9cc570d4 | 360 | * EC_POINT_set_affine_coordinates is responsible for checking that |
1e2012b7 EK |
361 | * the point is on the curve. |
362 | */ | |
9cc570d4 | 363 | if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) |
0f113f3e MC |
364 | goto err; |
365 | } | |
366 | ||
0f113f3e | 367 | ret = 1; |
84b08eee | 368 | |
0f113f3e MC |
369 | err: |
370 | BN_CTX_end(ctx); | |
23a1d5e9 | 371 | BN_CTX_free(new_ctx); |
0f113f3e MC |
372 | return ret; |
373 | } |