summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/ec/ecp_oct.c
diff options
context:
space:
mode:
authortb <>2024-10-30 18:16:34 +0000
committertb <>2024-10-30 18:16:34 +0000
commitf953655e6861bda2cfd07fa49af0ecd20b4507c2 (patch)
tree4305dbdabff19dba57f0176ca9be0a859323868b /src/lib/libcrypto/ec/ecp_oct.c
parent8c30fb7d85e73088455141bfbd758b3a43c931df (diff)
downloadopenbsd-f953655e6861bda2cfd07fa49af0ecd20b4507c2.tar.gz
openbsd-f953655e6861bda2cfd07fa49af0ecd20b4507c2.tar.bz2
openbsd-f953655e6861bda2cfd07fa49af0ecd20b4507c2.zip
Move the GFp-specific point <-> octets functions to ec_convert.c
discussed with jsing
Diffstat (limited to 'src/lib/libcrypto/ec/ecp_oct.c')
-rw-r--r--src/lib/libcrypto/ec/ecp_oct.c296
1 files changed, 1 insertions, 295 deletions
diff --git a/src/lib/libcrypto/ec/ecp_oct.c b/src/lib/libcrypto/ec/ecp_oct.c
index ce63bfadc4..0f4d8cb551 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.29 2024/10/25 18:06:42 tb Exp $ */ 1/* $OpenBSD: ecp_oct.c,v 1.30 2024/10/30 18:16:34 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.
@@ -184,297 +184,3 @@ ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
184 184
185 return ret; 185 return ret;
186} 186}
187
188/*
189 * Only the last three bits of the leading octet of a point should be set.
190 * Bits 3 and 2 encode the conversion form for all points except the point
191 * at infinity. In compressed and hybrid form bit 1 indicates if the even
192 * or the odd solution of the quadratic equation for y should be used.
193 *
194 * The public point_conversion_t enum lacks the point at infinity, so we
195 * ignore it except at the API boundary.
196 */
197
198#define EC_OCT_YBIT 0x01
199
200#define EC_OCT_POINT_AT_INFINITY 0x00
201#define EC_OCT_POINT_COMPRESSED 0x02
202#define EC_OCT_POINT_UNCOMPRESSED 0x04
203#define EC_OCT_POINT_HYBRID 0x06
204#define EC_OCT_POINT_CONVERSION_MASK 0x06
205
206static int
207ec_oct_conversion_form_is_valid(uint8_t form)
208{
209 return (form & EC_OCT_POINT_CONVERSION_MASK) == form;
210}
211
212static int
213ec_oct_check_hybrid_ybit_is_consistent(uint8_t form, int ybit, const BIGNUM *y)
214{
215 if (form == EC_OCT_POINT_HYBRID && ybit != BN_is_odd(y)) {
216 ECerror(EC_R_INVALID_ENCODING);
217 return 0;
218 }
219
220 return 1;
221}
222
223/* Nonzero y-bit only makes sense with compressed or hybrid encoding. */
224static int
225ec_oct_nonzero_ybit_allowed(uint8_t form)
226{
227 return form == EC_OCT_POINT_COMPRESSED || form == EC_OCT_POINT_HYBRID;
228}
229
230static int
231ec_oct_add_leading_octet_cbb(CBB *cbb, uint8_t form, int ybit)
232{
233 if (ec_oct_nonzero_ybit_allowed(form) && ybit != 0)
234 form |= EC_OCT_YBIT;
235
236 return CBB_add_u8(cbb, form);
237}
238
239static int
240ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit)
241{
242 uint8_t octet;
243
244 if (!CBS_get_u8(cbs, &octet)) {
245 ECerror(EC_R_BUFFER_TOO_SMALL);
246 return 0;
247 }
248
249 *out_ybit = octet & EC_OCT_YBIT;
250 *out_form = octet & ~EC_OCT_YBIT;
251
252 if (!ec_oct_conversion_form_is_valid(*out_form)) {
253 ECerror(EC_R_INVALID_ENCODING);
254 return 0;
255 }
256
257 if (*out_ybit != 0 && !ec_oct_nonzero_ybit_allowed(*out_form)) {
258 ECerror(EC_R_INVALID_ENCODING);
259 return 0;
260 }
261
262 return 1;
263}
264
265static int
266ec_oct_encoded_length(const EC_GROUP *group, uint8_t form, size_t *out_len)
267{
268 switch (form) {
269 case EC_OCT_POINT_AT_INFINITY:
270 *out_len = 1;
271 return 1;
272 case EC_OCT_POINT_COMPRESSED:
273 *out_len = 1 + BN_num_bytes(&group->field);
274 return 1;
275 case EC_OCT_POINT_UNCOMPRESSED:
276 case EC_OCT_POINT_HYBRID:
277 *out_len = 1 + 2 * BN_num_bytes(&group->field);
278 return 1;
279 default:
280 return 0;
281 }
282}
283
284static int
285ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn)
286{
287 /* Ensure bn is in the range [0, field). */
288 return !BN_is_negative(bn) && BN_cmp(&group->field, bn) > 0;
289}
290
291static int
292ec_oct_add_field_element_cbb(CBB *cbb, const EC_GROUP *group, const BIGNUM *bn)
293{
294 uint8_t *buf = NULL;
295 int buf_len = BN_num_bytes(&group->field);
296
297 if (!ec_oct_field_element_is_valid(group, bn)) {
298 ECerror(EC_R_BIGNUM_OUT_OF_RANGE);
299 return 0;
300 }
301 if (!CBB_add_space(cbb, &buf, buf_len)) {
302 ECerror(ERR_R_MALLOC_FAILURE);
303 return 0;
304 }
305 if (BN_bn2binpad(bn, buf, buf_len) != buf_len) {
306 ECerror(ERR_R_MALLOC_FAILURE);
307 return 0;
308 }
309
310 return 1;
311}
312
313static int
314ec_oct_get_field_element_cbs(CBS *cbs, const EC_GROUP *group, BIGNUM *bn)
315{
316 CBS field_element;
317
318 if (!CBS_get_bytes(cbs, &field_element, BN_num_bytes(&group->field))) {
319 ECerror(EC_R_INVALID_ENCODING);
320 return 0;
321 }
322 if (!BN_bin2bn(CBS_data(&field_element), CBS_len(&field_element), bn)) {
323 ECerror(ERR_R_MALLOC_FAILURE);
324 return 0;
325 }
326 if (!ec_oct_field_element_is_valid(group, bn)) {
327 ECerror(EC_R_BIGNUM_OUT_OF_RANGE);
328 return 0;
329 }
330
331 return 1;
332}
333
334size_t
335ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point,
336 point_conversion_form_t conversion_form, unsigned char *buf, size_t len,
337 BN_CTX *ctx)
338{
339 CBB cbb;
340 uint8_t form;
341 BIGNUM *x, *y;
342 size_t encoded_length;
343 size_t ret = 0;
344
345 if (conversion_form > UINT8_MAX) {
346 ECerror(EC_R_INVALID_FORM);
347 return 0;
348 }
349
350 form = conversion_form;
351
352 /*
353 * Established behavior is to reject a request for the form 0 for the
354 * point at infinity even if it is valid.
355 */
356 if (form == 0 || !ec_oct_conversion_form_is_valid(form)) {
357 ECerror(EC_R_INVALID_FORM);
358 return 0;
359 }
360
361 if (EC_POINT_is_at_infinity(group, point))
362 form = EC_OCT_POINT_AT_INFINITY;
363
364 if (!ec_oct_encoded_length(group, form, &encoded_length)) {
365 ECerror(EC_R_INVALID_FORM);
366 return 0;
367 }
368
369 if (buf == NULL)
370 return encoded_length;
371
372 if (len < encoded_length) {
373 ECerror(EC_R_BUFFER_TOO_SMALL);
374 return 0;
375 }
376
377 BN_CTX_start(ctx);
378 if (!CBB_init_fixed(&cbb, buf, len))
379 goto err;
380
381 if (form == EC_OCT_POINT_AT_INFINITY) {
382 if (!ec_oct_add_leading_octet_cbb(&cbb, form, 0))
383 goto err;
384
385 goto done;
386 }
387
388 if ((x = BN_CTX_get(ctx)) == NULL)
389 goto err;
390 if ((y = BN_CTX_get(ctx)) == NULL)
391 goto err;
392 if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx))
393 goto err;
394
395 if (!ec_oct_add_leading_octet_cbb(&cbb, form, BN_is_odd(y)))
396 goto err;
397
398 if (form == EC_OCT_POINT_COMPRESSED) {
399 if (!ec_oct_add_field_element_cbb(&cbb, group, x))
400 goto err;
401 } else {
402 if (!ec_oct_add_field_element_cbb(&cbb, group, x))
403 goto err;
404 if (!ec_oct_add_field_element_cbb(&cbb, group, y))
405 goto err;
406 }
407
408 done:
409 if (!CBB_finish(&cbb, NULL, &ret))
410 goto err;
411
412 if (ret != encoded_length) {
413 ret = 0;
414 goto err;
415 }
416
417 err:
418 CBB_cleanup(&cbb);
419 BN_CTX_end(ctx);
420
421 return ret;
422}
423
424int
425ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
426 const unsigned char *buf, size_t len, BN_CTX *ctx)
427{
428 CBS cbs;
429 uint8_t form;
430 int ybit;
431 BIGNUM *x, *y;
432 int ret = 0;
433
434 BN_CTX_start(ctx);
435 CBS_init(&cbs, buf, len);
436
437 if (!ec_oct_get_leading_octet_cbs(&cbs, &form, &ybit))
438 goto err;
439
440 if (form == EC_OCT_POINT_AT_INFINITY) {
441 if (!EC_POINT_set_to_infinity(group, point))
442 goto err;
443
444 goto done;
445 }
446
447 if ((x = BN_CTX_get(ctx)) == NULL)
448 goto err;
449 if ((y = BN_CTX_get(ctx)) == NULL)
450 goto err;
451
452 if (form == EC_OCT_POINT_COMPRESSED) {
453 if (!ec_oct_get_field_element_cbs(&cbs, group, x))
454 goto err;
455 if (!EC_POINT_set_compressed_coordinates(group, point, x, ybit, ctx))
456 goto err;
457 } else {
458 if (!ec_oct_get_field_element_cbs(&cbs, group, x))
459 goto err;
460 if (!ec_oct_get_field_element_cbs(&cbs, group, y))
461 goto err;
462 if (!ec_oct_check_hybrid_ybit_is_consistent(form, ybit, y))
463 goto err;
464 if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
465 goto err;
466 }
467
468 done:
469 if (CBS_len(&cbs) > 0) {
470 ECerror(EC_R_INVALID_ENCODING);
471 goto err;
472 }
473
474 ret = 1;
475
476 err:
477 BN_CTX_end(ctx);
478
479 return ret;
480}