diff options
author | tb <> | 2024-10-22 21:10:45 +0000 |
---|---|---|
committer | tb <> | 2024-10-22 21:10:45 +0000 |
commit | 2ecb80a0db01a12008dcf47db9a6f3f5862966ec (patch) | |
tree | cc5e766b146756db1f49d72144c1639f3fe3572d /src | |
parent | 9c7b8e21b0aef7b0d224cd59cdc95557a81f289f (diff) | |
download | openbsd-2ecb80a0db01a12008dcf47db9a6f3f5862966ec.tar.gz openbsd-2ecb80a0db01a12008dcf47db9a6f3f5862966ec.tar.bz2 openbsd-2ecb80a0db01a12008dcf47db9a6f3f5862966ec.zip |
Rewrite ec_GFp_simple_point2oct() using CBB
Factor ad-hoc inline code into helper functions. Use CBB and
BN_bn2binpad() instead of batshit crazy skip loops and pointer
banging. With all this done, the function becomes relatively
streamlined and pretty much symmetric with the new oct2point()
implementation.
ok jsing
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 | } |