b1c8e3ed8a8115744fda9ed0d3dd4477b562ecec
[openssl.git] / crypto / ec / ecp_oct.c
1 /*
2  * Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved.
3  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4  *
5  * Licensed under the Apache License 2.0 (the "License").  You may not use
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
9  */
10
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
17 #include <openssl/err.h>
18 #include <openssl/symhacks.h>
19
20 #include "ec_local.h"
21
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
31 #ifndef FIPS_MODULE
32     /* clear error queue */
33     ERR_clear_error();
34 #endif
35
36     if (ctx == NULL) {
37         ctx = new_ctx = BN_CTX_new_ex(group->libctx);
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
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      */
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)) {
110 #ifndef FIPS_MODULE
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();
116             ERR_raise(ERR_LIB_EC, EC_R_INVALID_COMPRESSED_POINT);
117         } else
118 #endif
119         {
120             ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
121         }
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)
134                 ERR_raise(ERR_LIB_EC, EC_R_INVALID_COMPRESSION_BIT);
135             else
136                 /*
137                  * BN_mod_sqrt() should have caught this error (not a square)
138                  */
139                 ERR_raise(ERR_LIB_EC, EC_R_INVALID_COMPRESSED_POINT);
140             goto err;
141         }
142         if (!BN_usub(y, group->field, y))
143             goto err;
144     }
145     if (y_bit != BN_is_odd(y)) {
146         ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR);
147         goto err;
148     }
149
150     if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
151         goto err;
152
153     ret = 1;
154
155  err:
156     BN_CTX_end(ctx);
157     BN_CTX_free(new_ctx);
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)) {
174         ERR_raise(ERR_LIB_EC, EC_R_INVALID_FORM);
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) {
182                 ERR_raise(ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL);
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) {
199             ERR_raise(ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL);
200             goto err;
201         }
202
203         if (ctx == NULL) {
204             ctx = new_ctx = BN_CTX_new_ex(group->libctx);
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
216         if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx))
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) {
229             ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR);
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) {
239             ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR);
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) {
247                 ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR);
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) {
259             ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR);
260             goto err;
261         }
262     }
263
264     if (used_ctx)
265         BN_CTX_end(ctx);
266     BN_CTX_free(new_ctx);
267     return ret;
268
269  err:
270     if (used_ctx)
271         BN_CTX_end(ctx);
272     BN_CTX_free(new_ctx);
273     return 0;
274 }
275
276 int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
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) {
287         ERR_raise(ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL);
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)) {
296         ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
297         return 0;
298     }
299     if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) {
300         ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
301         return 0;
302     }
303
304     if (form == 0) {
305         if (len != 1) {
306             ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
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) {
319         ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
320         return 0;
321     }
322
323     if (ctx == NULL) {
324         ctx = new_ctx = BN_CTX_new_ex(group->libctx);
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) {
338         ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
339         goto err;
340     }
341
342     if (form == POINT_CONVERSION_COMPRESSED) {
343         if (!EC_POINT_set_compressed_coordinates(group, point, x, y_bit, ctx))
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) {
349             ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
350             goto err;
351         }
352         if (form == POINT_CONVERSION_HYBRID) {
353             if (y_bit != BN_is_odd(y)) {
354                 ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
355                 goto err;
356             }
357         }
358
359         /*
360          * EC_POINT_set_affine_coordinates is responsible for checking that
361          * the point is on the curve.
362          */
363         if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
364             goto err;
365     }
366
367     ret = 1;
368
369  err:
370     BN_CTX_end(ctx);
371     BN_CTX_free(new_ctx);
372     return ret;
373 }