diff options
| author | tb <> | 2021-04-19 17:06:37 +0000 |
|---|---|---|
| committer | tb <> | 2021-04-19 17:06:37 +0000 |
| commit | 09d5d7044b93b2ed06d049c8ee912bc45dfa1207 (patch) | |
| tree | 75e41b2251a7f10efde5d1af2dcd2d788aa654fa /src | |
| parent | 9224df62e4b0dd5251c753a7931def2f1756be8b (diff) | |
| download | openbsd-09d5d7044b93b2ed06d049c8ee912bc45dfa1207.tar.gz openbsd-09d5d7044b93b2ed06d049c8ee912bc45dfa1207.tar.bz2 openbsd-09d5d7044b93b2ed06d049c8ee912bc45dfa1207.zip | |
Avoid division by zero in hybrid point encoding
In hybrid and compressed point encodings, the form octet contains a bit
of information allowing to calculate y from x. For a point on a binary
curve, this bit is zero if x is zero, otherwise it must match the
rightmost bit of of the field element y / x. The existing code only
considers the second possibility. It could thus fail with a division by
zero error as found by Guido Vranken's cryptofuzz.
This commit adds a few explanatory comments to oct2point and fixes some
KNF issues. The only actual code change is in the last hunk which adds a
BN_is_zero(x) check to avoid the division by zero.
ok jsing
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/ec/ec2_oct.c | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/src/lib/libcrypto/ec/ec2_oct.c b/src/lib/libcrypto/ec/ec2_oct.c index 5f7f7e3c99..9cd1dddfa1 100644 --- a/src/lib/libcrypto/ec/ec2_oct.c +++ b/src/lib/libcrypto/ec/ec2_oct.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: ec2_oct.c,v 1.12 2020/12/04 08:55:30 tb Exp $ */ | 1 | /* $OpenBSD: ec2_oct.c,v 1.13 2021/04/19 17:06:37 tb Exp $ */ |
| 2 | /* ==================================================================== | 2 | /* ==================================================================== |
| 3 | * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. | 3 | * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. |
| 4 | * | 4 | * |
| @@ -280,10 +280,11 @@ ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, | |||
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | 282 | ||
| 283 | /* Converts an octet string representation to an EC_POINT. | 283 | /* |
| 284 | * Converts an octet string representation to an EC_POINT. | ||
| 284 | * Note that the simple implementation only uses affine coordinates. | 285 | * Note that the simple implementation only uses affine coordinates. |
| 285 | */ | 286 | */ |
| 286 | int | 287 | int |
| 287 | ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | 288 | ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, |
| 288 | const unsigned char *buf, size_t len, BN_CTX *ctx) | 289 | const unsigned char *buf, size_t len, BN_CTX *ctx) |
| 289 | { | 290 | { |
| @@ -298,19 +299,35 @@ ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | |||
| 298 | ECerror(EC_R_BUFFER_TOO_SMALL); | 299 | ECerror(EC_R_BUFFER_TOO_SMALL); |
| 299 | return 0; | 300 | return 0; |
| 300 | } | 301 | } |
| 301 | form = buf[0]; | 302 | |
| 302 | y_bit = form & 1; | 303 | /* |
| 303 | form = form & ~1U; | 304 | * The first octet is the point conversion octet PC, see X9.62, page 4 |
| 304 | if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) && | 305 | * and section 4.4.2. It must be: |
| 305 | (form != POINT_CONVERSION_UNCOMPRESSED) && | 306 | * 0x00 for the point at infinity |
| 306 | (form != POINT_CONVERSION_HYBRID)) { | 307 | * 0x02 or 0x03 for compressed form |
| 308 | * 0x04 for uncompressed form | ||
| 309 | * 0x06 or 0x07 for hybrid form. | ||
| 310 | * For compressed or hybrid forms, we store the last bit of buf[0] as | ||
| 311 | * y_bit and clear it from buf[0] so as to obtain a POINT_CONVERSION_*. | ||
| 312 | * We error if buf[0] contains any but the above values. | ||
| 313 | */ | ||
| 314 | y_bit = buf[0] & 1; | ||
| 315 | form = buf[0] & ~1U; | ||
| 316 | |||
| 317 | if (form != 0 && form != POINT_CONVERSION_COMPRESSED && | ||
| 318 | form != POINT_CONVERSION_UNCOMPRESSED && | ||
| 319 | form != POINT_CONVERSION_HYBRID) { | ||
| 307 | ECerror(EC_R_INVALID_ENCODING); | 320 | ECerror(EC_R_INVALID_ENCODING); |
| 308 | return 0; | 321 | return 0; |
| 309 | } | 322 | } |
| 310 | if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) { | 323 | if (form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) { |
| 311 | ECerror(EC_R_INVALID_ENCODING); | 324 | if (y_bit != 0) { |
| 312 | return 0; | 325 | ECerror(EC_R_INVALID_ENCODING); |
| 326 | return 0; | ||
| 327 | } | ||
| 313 | } | 328 | } |
| 329 | |||
| 330 | /* The point at infinity is represented by a single zero octet. */ | ||
| 314 | if (form == 0) { | 331 | if (form == 0) { |
| 315 | if (len != 1) { | 332 | if (len != 1) { |
| 316 | ECerror(EC_R_INVALID_ENCODING); | 333 | ECerror(EC_R_INVALID_ENCODING); |
| @@ -318,6 +335,7 @@ ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | |||
| 318 | } | 335 | } |
| 319 | return EC_POINT_set_to_infinity(group, point); | 336 | return EC_POINT_set_to_infinity(group, point); |
| 320 | } | 337 | } |
| 338 | |||
| 321 | field_len = (EC_GROUP_get_degree(group) + 7) / 8; | 339 | field_len = (EC_GROUP_get_degree(group) + 7) / 8; |
| 322 | enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : | 340 | enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : |
| 323 | 1 + 2 * field_len; | 341 | 1 + 2 * field_len; |
| @@ -326,6 +344,7 @@ ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | |||
| 326 | ECerror(EC_R_INVALID_ENCODING); | 344 | ECerror(EC_R_INVALID_ENCODING); |
| 327 | return 0; | 345 | return 0; |
| 328 | } | 346 | } |
| 347 | |||
| 329 | if (ctx == NULL) { | 348 | if (ctx == NULL) { |
| 330 | ctx = new_ctx = BN_CTX_new(); | 349 | ctx = new_ctx = BN_CTX_new(); |
| 331 | if (ctx == NULL) | 350 | if (ctx == NULL) |
| @@ -360,11 +379,24 @@ ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | |||
| 360 | goto err; | 379 | goto err; |
| 361 | } | 380 | } |
| 362 | if (form == POINT_CONVERSION_HYBRID) { | 381 | if (form == POINT_CONVERSION_HYBRID) { |
| 363 | if (!group->meth->field_div(group, yxi, y, x, ctx)) | 382 | /* |
| 364 | goto err; | 383 | * Check that the form in the encoding was set |
| 365 | if (y_bit != BN_is_odd(yxi)) { | 384 | * correctly according to X9.62 4.4.2.a, 4(c), |
| 366 | ECerror(EC_R_INVALID_ENCODING); | 385 | * see also first paragraph of X9.62 4.4.1.b. |
| 367 | goto err; | 386 | */ |
| 387 | if (BN_is_zero(x)) { | ||
| 388 | if (y_bit != 0) { | ||
| 389 | ECerror(EC_R_INVALID_ENCODING); | ||
| 390 | goto err; | ||
| 391 | } | ||
| 392 | } else { | ||
| 393 | if (!group->meth->field_div(group, yxi, y, x, | ||
| 394 | ctx)) | ||
| 395 | goto err; | ||
| 396 | if (y_bit != BN_is_odd(yxi)) { | ||
| 397 | ECerror(EC_R_INVALID_ENCODING); | ||
| 398 | goto err; | ||
| 399 | } | ||
| 368 | } | 400 | } |
| 369 | } | 401 | } |
| 370 | /* | 402 | /* |
