diff options
author | tb <> | 2024-10-22 21:08:49 +0000 |
---|---|---|
committer | tb <> | 2024-10-22 21:08:49 +0000 |
commit | 9c7b8e21b0aef7b0d224cd59cdc95557a81f289f (patch) | |
tree | c7a7659adfc9aa37c728d69a790a50ca3f073b1d /src | |
parent | 0e8f02da5cba6c145d528b1887147781392b4d70 (diff) | |
download | openbsd-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.c | 143 |
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 | |||
74 | int | 76 | int |
75 | ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, | 77 | ec_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. */ | ||
213 | static int | ||
214 | ec_oct_nonzero_ybit_allowed(uint8_t form) | ||
215 | { | ||
216 | return form == EC_OCT_POINT_COMPRESSED || form == EC_OCT_POINT_HYBRID; | ||
217 | } | ||
218 | |||
219 | static int | ||
220 | ec_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 | |||
245 | static int | ||
246 | ec_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 | |||
252 | static int | ||
253 | ec_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 | |||
210 | size_t | 273 | size_t |
211 | ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, | 274 | ec_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 | |||
317 | ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | 380 | ec_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: |