summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/libcrypto/ec/ecp_oct.c153
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
219static int 219static int
220ec_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
228static int
220ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit) 229ec_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
245static int 254static int
255ec_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
273static int
246ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn) 274ec_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
252static int 280static int
281ec_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
302static int
253ec_oct_get_field_element_cbs(CBS *cbs, const EC_GROUP *group, BIGNUM *bn) 303ec_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}