diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/ec/ecp_oct.c | 153 |
1 files changed, 90 insertions, 63 deletions
diff --git a/src/lib/libcrypto/ec/ecp_oct.c b/src/lib/libcrypto/ec/ecp_oct.c index aa5a3906d1..0a66a5cd48 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.24 2024/10/22 21:08:49 tb Exp $ */ | 1 | /* $OpenBSD: ecp_oct.c,v 1.25 2024/10/22 21:10:45 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. |
| @@ -217,6 +217,15 @@ ec_oct_nonzero_ybit_allowed(uint8_t form) | |||
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | static int | 219 | static int |
| 220 | ec_oct_add_leading_octet_cbb(CBB *cbb, uint8_t form, int ybit) | ||
| 221 | { | ||
| 222 | if (ec_oct_nonzero_ybit_allowed(form) && ybit != 0) | ||
| 223 | form |= EC_OCT_YBIT; | ||
| 224 | |||
| 225 | return CBB_add_u8(cbb, form); | ||
| 226 | } | ||
| 227 | |||
| 228 | static int | ||
| 220 | ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit) | 229 | ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit) |
| 221 | { | 230 | { |
| 222 | uint8_t octet; | 231 | uint8_t octet; |
| @@ -243,6 +252,25 @@ ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit) | |||
| 243 | } | 252 | } |
| 244 | 253 | ||
| 245 | static int | 254 | static int |
| 255 | ec_oct_encoded_length(const EC_GROUP *group, uint8_t form, size_t *out_len) | ||
| 256 | { | ||
| 257 | switch (form) { | ||
| 258 | case EC_OCT_POINT_AT_INFINITY: | ||
| 259 | *out_len = 1; | ||
| 260 | return 1; | ||
| 261 | case EC_OCT_POINT_COMPRESSED: | ||
| 262 | *out_len = 1 + BN_num_bytes(&group->field); | ||
| 263 | return 1; | ||
| 264 | case EC_OCT_POINT_UNCOMPRESSED: | ||
| 265 | case EC_OCT_POINT_HYBRID: | ||
| 266 | *out_len = 1 + 2 * BN_num_bytes(&group->field); | ||
| 267 | return 1; | ||
| 268 | default: | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | static int | ||
| 246 | ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn) | 274 | ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn) |
| 247 | { | 275 | { |
| 248 | /* Ensure bn is in the range [0, field). */ | 276 | /* Ensure bn is in the range [0, field). */ |
| @@ -250,6 +278,28 @@ ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn) | |||
| 250 | } | 278 | } |
| 251 | 279 | ||
| 252 | static int | 280 | static int |
| 281 | ec_oct_add_field_element_cbb(CBB *cbb, const EC_GROUP *group, const BIGNUM *bn) | ||
| 282 | { | ||
| 283 | uint8_t *buf = NULL; | ||
| 284 | int buf_len = BN_num_bytes(&group->field); | ||
| 285 | |||
| 286 | if (!ec_oct_field_element_is_valid(group, bn)) { | ||
| 287 | ECerror(EC_R_BIGNUM_OUT_OF_RANGE); | ||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | if (!CBB_add_space(cbb, &buf, buf_len)) { | ||
| 291 | ECerror(ERR_R_MALLOC_FAILURE); | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | if (BN_bn2binpad(bn, buf, buf_len) != buf_len) { | ||
| 295 | ECerror(ERR_R_MALLOC_FAILURE); | ||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | return 1; | ||
| 300 | } | ||
| 301 | |||
| 302 | static int | ||
| 253 | ec_oct_get_field_element_cbs(CBS *cbs, const EC_GROUP *group, BIGNUM *bn) | 303 | ec_oct_get_field_element_cbs(CBS *cbs, const EC_GROUP *group, BIGNUM *bn) |
| 254 | { | 304 | { |
| 255 | CBS field_element; | 305 | CBS field_element; |
| @@ -275,9 +325,10 @@ ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, | |||
| 275 | point_conversion_form_t conversion_form, unsigned char *buf, size_t len, | 325 | point_conversion_form_t conversion_form, unsigned char *buf, size_t len, |
| 276 | BN_CTX *ctx) | 326 | BN_CTX *ctx) |
| 277 | { | 327 | { |
| 328 | CBB cbb; | ||
| 278 | uint8_t form; | 329 | uint8_t form; |
| 279 | BIGNUM *x, *y; | 330 | BIGNUM *x, *y; |
| 280 | size_t field_len, i, skip; | 331 | size_t encoded_length; |
| 281 | size_t ret = 0; | 332 | size_t ret = 0; |
| 282 | 333 | ||
| 283 | if (conversion_form > UINT8_MAX) { | 334 | if (conversion_form > UINT8_MAX) { |
| @@ -296,82 +347,58 @@ ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, | |||
| 296 | return 0; | 347 | return 0; |
| 297 | } | 348 | } |
| 298 | 349 | ||
| 299 | if (EC_POINT_is_at_infinity(group, point) > 0) { | 350 | if (EC_POINT_is_at_infinity(group, point)) |
| 300 | /* encodes to a single 0 octet */ | 351 | form = EC_OCT_POINT_AT_INFINITY; |
| 301 | if (buf != NULL) { | 352 | |
| 302 | if (len < 1) { | 353 | if (!ec_oct_encoded_length(group, form, &encoded_length)) { |
| 303 | ECerror(EC_R_BUFFER_TOO_SMALL); | 354 | ECerror(EC_R_INVALID_FORM); |
| 304 | return 0; | 355 | return 0; |
| 305 | } | ||
| 306 | buf[0] = 0; | ||
| 307 | } | ||
| 308 | return 1; | ||
| 309 | } | 356 | } |
| 310 | 357 | ||
| 311 | /* ret := required output buffer length */ | 358 | if (buf == NULL) |
| 312 | field_len = BN_num_bytes(&group->field); | 359 | return encoded_length; |
| 313 | ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; | 360 | |
| 361 | if (len < encoded_length) { | ||
| 362 | ECerror(EC_R_BUFFER_TOO_SMALL); | ||
| 363 | return 0; | ||
| 364 | } | ||
| 314 | 365 | ||
| 366 | CBB_init_fixed(&cbb, buf, len); | ||
| 315 | BN_CTX_start(ctx); | 367 | BN_CTX_start(ctx); |
| 316 | 368 | ||
| 317 | /* if 'buf' is NULL, just return required length */ | 369 | if ((x = BN_CTX_get(ctx)) == NULL) |
| 318 | if (buf != NULL) { | 370 | goto err; |
| 319 | if (len < ret) { | 371 | if ((y = BN_CTX_get(ctx)) == NULL) |
| 320 | ECerror(EC_R_BUFFER_TOO_SMALL); | 372 | goto err; |
| 321 | goto err; | 373 | if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) |
| 322 | } | 374 | goto err; |
| 375 | |||
| 376 | if (!ec_oct_add_leading_octet_cbb(&cbb, form, BN_is_odd(y))) | ||
| 377 | goto err; | ||
| 323 | 378 | ||
| 324 | if ((x = BN_CTX_get(ctx)) == NULL) | 379 | if (form == EC_OCT_POINT_AT_INFINITY) { |
| 380 | /* Encoded in leading octet. */; | ||
| 381 | } else if (form == EC_OCT_POINT_COMPRESSED) { | ||
| 382 | if (!ec_oct_add_field_element_cbb(&cbb, group, x)) | ||
| 325 | goto err; | 383 | goto err; |
| 326 | if ((y = BN_CTX_get(ctx)) == NULL) | 384 | } else { |
| 385 | if (!ec_oct_add_field_element_cbb(&cbb, group, x)) | ||
| 327 | goto err; | 386 | goto err; |
| 328 | 387 | if (!ec_oct_add_field_element_cbb(&cbb, group, y)) | |
| 329 | if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) | ||
| 330 | goto err; | 388 | goto err; |
| 389 | } | ||
| 331 | 390 | ||
| 332 | if ((form == POINT_CONVERSION_COMPRESSED || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y)) | 391 | if (!CBB_finish(&cbb, NULL, &ret)) |
| 333 | buf[0] = form + 1; | 392 | goto err; |
| 334 | else | ||
| 335 | buf[0] = form; | ||
| 336 | |||
| 337 | i = 1; | ||
| 338 | 393 | ||
| 339 | skip = field_len - BN_num_bytes(x); | 394 | if (ret != encoded_length) { |
| 340 | if (skip > field_len) { | 395 | ret = 0; |
| 341 | ECerror(ERR_R_INTERNAL_ERROR); | 396 | goto err; |
| 342 | goto err; | ||
| 343 | } | ||
| 344 | while (skip > 0) { | ||
| 345 | buf[i++] = 0; | ||
| 346 | skip--; | ||
| 347 | } | ||
| 348 | skip = BN_bn2bin(x, buf + i); | ||
| 349 | i += skip; | ||
| 350 | if (i != 1 + field_len) { | ||
| 351 | ECerror(ERR_R_INTERNAL_ERROR); | ||
| 352 | goto err; | ||
| 353 | } | ||
| 354 | if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID) { | ||
| 355 | skip = field_len - BN_num_bytes(y); | ||
| 356 | if (skip > field_len) { | ||
| 357 | ECerror(ERR_R_INTERNAL_ERROR); | ||
| 358 | goto err; | ||
| 359 | } | ||
| 360 | while (skip > 0) { | ||
| 361 | buf[i++] = 0; | ||
| 362 | skip--; | ||
| 363 | } | ||
| 364 | skip = BN_bn2bin(y, buf + i); | ||
| 365 | i += skip; | ||
| 366 | } | ||
| 367 | if (i != ret) { | ||
| 368 | ECerror(ERR_R_INTERNAL_ERROR); | ||
| 369 | goto err; | ||
| 370 | } | ||
| 371 | } | 397 | } |
| 372 | 398 | ||
| 373 | err: | 399 | err: |
| 374 | BN_CTX_end(ctx); | 400 | BN_CTX_end(ctx); |
| 401 | CBB_cleanup(&cbb); | ||
| 375 | 402 | ||
| 376 | return ret; | 403 | return ret; |
| 377 | } | 404 | } |
