summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortb <>2024-10-22 21:08:49 +0000
committertb <>2024-10-22 21:08:49 +0000
commit9c7b8e21b0aef7b0d224cd59cdc95557a81f289f (patch)
treec7a7659adfc9aa37c728d69a790a50ca3f073b1d /src
parent0e8f02da5cba6c145d528b1887147781392b4d70 (diff)
downloadopenbsd-9c7b8e21b0aef7b0d224cd59cdc95557a81f289f.tar.gz
openbsd-9c7b8e21b0aef7b0d224cd59cdc95557a81f289f.tar.bz2
openbsd-9c7b8e21b0aef7b0d224cd59cdc95557a81f289f.zip
Rewrite ec_GFp_simple_oct2point() using CBS
Transform the spaghetti in here into something more readable. Factor various inline checks into helper functions to make the logic clearer. This is a bit longer but a lot safer and simpler. It accepts exactly the same input as the original version. ok jsing
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/ec/ecp_oct.c143
1 files changed, 86 insertions, 57 deletions
diff --git a/src/lib/libcrypto/ec/ecp_oct.c b/src/lib/libcrypto/ec/ecp_oct.c
index 9646e44499..aa5a3906d1 100644
--- a/src/lib/libcrypto/ec/ecp_oct.c
+++ b/src/lib/libcrypto/ec/ecp_oct.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ecp_oct.c,v 1.23 2024/10/22 21:06:16 tb Exp $ */ 1/* $OpenBSD: ecp_oct.c,v 1.24 2024/10/22 21:08:49 tb Exp $ */
2/* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de> 2/* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
3 * for the OpenSSL project. 3 * for the OpenSSL project.
4 * Includes code written by Bodo Moeller for the OpenSSL project. 4 * Includes code written by Bodo Moeller for the OpenSSL project.
@@ -71,6 +71,8 @@
71 71
72#include "ec_local.h" 72#include "ec_local.h"
73 73
74#include "bytestring.h"
75
74int 76int
75ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, 77ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
76 EC_POINT *point, const BIGNUM *x_, int y_bit, BN_CTX *ctx) 78 EC_POINT *point, const BIGNUM *x_, int y_bit, BN_CTX *ctx)
@@ -207,6 +209,67 @@ ec_oct_conversion_form_is_valid(uint8_t form)
207 return (form & EC_OCT_POINT_CONVERSION_MASK) == form; 209 return (form & EC_OCT_POINT_CONVERSION_MASK) == form;
208} 210}
209 211
212/* Nonzero y-bit only makes sense with compressed or hybrid encoding. */
213static int
214ec_oct_nonzero_ybit_allowed(uint8_t form)
215{
216 return form == EC_OCT_POINT_COMPRESSED || form == EC_OCT_POINT_HYBRID;
217}
218
219static int
220ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit)
221{
222 uint8_t octet;
223
224 if (!CBS_get_u8(cbs, &octet)) {
225 ECerror(EC_R_BUFFER_TOO_SMALL);
226 return 0;
227 }
228
229 *out_ybit = octet & EC_OCT_YBIT;
230 *out_form = octet & ~EC_OCT_YBIT;
231
232 if (!ec_oct_conversion_form_is_valid(*out_form)) {
233 ECerror(EC_R_INVALID_ENCODING);
234 return 0;
235 }
236
237 if (*out_ybit != 0 && !ec_oct_nonzero_ybit_allowed(*out_form)) {
238 ECerror(EC_R_INVALID_ENCODING);
239 return 0;
240 }
241
242 return 1;
243}
244
245static int
246ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn)
247{
248 /* Ensure bn is in the range [0, field). */
249 return !BN_is_negative(bn) && BN_cmp(&group->field, bn) > 0;
250}
251
252static int
253ec_oct_get_field_element_cbs(CBS *cbs, const EC_GROUP *group, BIGNUM *bn)
254{
255 CBS field_element;
256
257 if (!CBS_get_bytes(cbs, &field_element, BN_num_bytes(&group->field))) {
258 ECerror(EC_R_INVALID_ENCODING);
259 return 0;
260 }
261 if (!BN_bin2bn(CBS_data(&field_element), CBS_len(&field_element), bn)) {
262 ECerror(ERR_R_MALLOC_FAILURE);
263 return 0;
264 }
265 if (!ec_oct_field_element_is_valid(group, bn)) {
266 ECerror(EC_R_BIGNUM_OUT_OF_RANGE);
267 return 0;
268 }
269
270 return 1;
271}
272
210size_t 273size_t
211ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, 274ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point,
212 point_conversion_form_t conversion_form, unsigned char *buf, size_t len, 275 point_conversion_form_t conversion_form, unsigned char *buf, size_t len,
@@ -317,44 +380,13 @@ int
317ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, 380ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
318 const unsigned char *buf, size_t len, BN_CTX *ctx) 381 const unsigned char *buf, size_t len, BN_CTX *ctx)
319{ 382{
320 point_conversion_form_t form; 383 CBS cbs;
321 int y_bit; 384 uint8_t form;
385 int ybit;
322 BIGNUM *x, *y; 386 BIGNUM *x, *y;
323 size_t field_len, enc_len;
324 int ret = 0; 387 int ret = 0;
325 388
326 if (len == 0) { 389 CBS_init(&cbs, buf, len);
327 ECerror(EC_R_BUFFER_TOO_SMALL);
328 return 0;
329 }
330 form = buf[0];
331 y_bit = form & 1;
332 form = form & ~1U;
333 if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
334 && (form != POINT_CONVERSION_UNCOMPRESSED)
335 && (form != POINT_CONVERSION_HYBRID)) {
336 ECerror(EC_R_INVALID_ENCODING);
337 return 0;
338 }
339 if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) {
340 ECerror(EC_R_INVALID_ENCODING);
341 return 0;
342 }
343 if (form == 0) {
344 if (len != 1) {
345 ECerror(EC_R_INVALID_ENCODING);
346 return 0;
347 }
348 return EC_POINT_set_to_infinity(group, point);
349 }
350 field_len = BN_num_bytes(&group->field);
351 enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
352
353 if (len != enc_len) {
354 ECerror(EC_R_INVALID_ENCODING);
355 return 0;
356 }
357
358 BN_CTX_start(ctx); 390 BN_CTX_start(ctx);
359 391
360 if ((x = BN_CTX_get(ctx)) == NULL) 392 if ((x = BN_CTX_get(ctx)) == NULL)
@@ -362,40 +394,37 @@ ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
362 if ((y = BN_CTX_get(ctx)) == NULL) 394 if ((y = BN_CTX_get(ctx)) == NULL)
363 goto err; 395 goto err;
364 396
365 if (!BN_bin2bn(buf + 1, field_len, x)) 397 if (!ec_oct_get_leading_octet_cbs(&cbs, &form, &ybit))
366 goto err;
367 if (BN_ucmp(x, &group->field) >= 0) {
368 ECerror(EC_R_INVALID_ENCODING);
369 goto err; 398 goto err;
370 } 399
371 if (form == POINT_CONVERSION_COMPRESSED) { 400 if (form == EC_OCT_POINT_AT_INFINITY) {
372 /* 401 if (!EC_POINT_set_to_infinity(group, point))
373 * EC_POINT_set_compressed_coordinates checks that the point 402 goto err;
374 * is on the curve as required by X9.62. 403 } else if (form == EC_OCT_POINT_COMPRESSED) {
375 */ 404 if (!ec_oct_get_field_element_cbs(&cbs, group, x))
376 if (!EC_POINT_set_compressed_coordinates(group, point, x, y_bit, ctx)) 405 goto err;
406 if (!EC_POINT_set_compressed_coordinates(group, point, x, ybit, ctx))
377 goto err; 407 goto err;
378 } else { 408 } else {
379 if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) 409 if (!ec_oct_get_field_element_cbs(&cbs, group, x))
380 goto err; 410 goto err;
381 if (BN_ucmp(y, &group->field) >= 0) { 411 if (!ec_oct_get_field_element_cbs(&cbs, group, y))
382 ECerror(EC_R_INVALID_ENCODING);
383 goto err; 412 goto err;
384 } 413 if (form == EC_OCT_POINT_HYBRID) {
385 if (form == POINT_CONVERSION_HYBRID) { 414 if (ybit != BN_is_odd(y)) {
386 if (y_bit != BN_is_odd(y)) {
387 ECerror(EC_R_INVALID_ENCODING); 415 ECerror(EC_R_INVALID_ENCODING);
388 goto err; 416 goto err;
389 } 417 }
390 } 418 }
391 /*
392 * EC_POINT_set_affine_coordinates checks that the point is
393 * on the curve as required by X9.62.
394 */
395 if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) 419 if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
396 goto err; 420 goto err;
397 } 421 }
398 422
423 if (CBS_len(&cbs) > 0) {
424 ECerror(EC_R_INVALID_ENCODING);
425 goto err;
426 }
427
399 ret = 1; 428 ret = 1;
400 429
401 err: 430 err: