diff --git a/src/crypto/elliptic.c b/src/crypto/elliptic.c new file mode 100644 index 000000000..75b8ba068 --- /dev/null +++ b/src/crypto/elliptic.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2026 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +/** @file + * + * Elliptic curves + * + */ + +#include +#include +#include +#include +#include + +/** + * Share public key + * + * @v exchange Key exchange algorithm + * @v private Private key + * @v public Public key to fill in + */ +void elliptic_share ( struct exchange_algorithm *exchange, const void *private, + void *public ) { + struct elliptic_curve *curve = exchange->priv; + size_t len = exchange->sharedsize; + elliptic_uncompressed_t ( len ) *result = public; + int rc; + + /* Sanity checks */ + assert ( curve->keysize == exchange->privsize ); + assert ( curve->pointsize == sizeof ( result->xy ) ); + assert ( sizeof ( *result ) == exchange->pubsize ); + + /* Calculate public key */ + result->format = ELLIPTIC_FORMAT_UNCOMPRESSED; + rc = elliptic_multiply ( curve, curve->base, private, &result->xy ); + + /* Can never fail when using the curve's own base point */ + assert ( rc == 0 ); +} + +/** + * Agree shared secret + * + * @v exchange Key exchange algorithm + * @v private Private key + * @v partner Partner public key + * @v shared Shared secret to fill in + * @ret rc Return status code + */ +int elliptic_agree ( struct exchange_algorithm *exchange, const void *private, + const void *partner, void *shared ) { + struct elliptic_curve *curve = exchange->priv; + size_t len = exchange->sharedsize; + const elliptic_uncompressed_t ( len ) *base = partner; + elliptic_uncompressed_t ( len ) result; + int rc; + + /* Sanity checks */ + assert ( curve->keysize == exchange->privsize ); + assert ( curve->pointsize == sizeof ( base->xy ) ); + assert ( curve->pointsize == sizeof ( result.xy ) ); + assert ( sizeof ( *base ) == exchange->pubsize ); + assert ( sizeof ( result.x ) == exchange->sharedsize ); + + /* Calculate shared secret */ + if ( ( rc = elliptic_multiply ( curve, &base->xy, private, + result.xy ) ) != 0 ) + return rc; + memcpy ( shared, &result.x, sizeof ( result.x ) ); + + /* Check for point at infinity */ + if ( elliptic_is_infinity ( curve, &result.xy ) ) + return -EPERM; + + /* Check format byte */ + if ( base->format != ELLIPTIC_FORMAT_UNCOMPRESSED ) + return -EPERM; + + return 0; +} diff --git a/src/crypto/p256.c b/src/crypto/p256.c index 074f3c79f..e6ea902f9 100644 --- a/src/crypto/p256.c +++ b/src/crypto/p256.c @@ -71,5 +71,8 @@ static const uint8_t p256_order[P256_LEN] = { }; /** P-256 elliptic curve */ -WEIERSTRASS_CURVE ( p256, p256_curve, p256_algorithm, P256_LEN, +WEIERSTRASS_CURVE ( p256, p256_curve, P256_LEN, p256_prime, p256_a, p256_b, p256_base, p256_order ); + +/** P-256 key exchange */ +ELLIPTIC_EXCHANGE ( p256, p256_algorithm, P256_LEN, &p256_curve ); diff --git a/src/crypto/p384.c b/src/crypto/p384.c index fe49adc8c..d5cfa1c68 100644 --- a/src/crypto/p384.c +++ b/src/crypto/p384.c @@ -82,5 +82,8 @@ static const uint8_t p384_order[P384_LEN] = { }; /** P-384 elliptic curve */ -WEIERSTRASS_CURVE ( p384, p384_curve, p384_algorithm, P384_LEN, +WEIERSTRASS_CURVE ( p384, p384_curve, P384_LEN, p384_prime, p384_a, p384_b, p384_base, p384_order ); + +/** P-384 key exchange */ +ELLIPTIC_EXCHANGE ( p384, p384_algorithm, P384_LEN, &p384_curve ); diff --git a/src/crypto/weierstrass.c b/src/crypto/weierstrass.c index d669b9a73..1f84919eb 100644 --- a/src/crypto/weierstrass.c +++ b/src/crypto/weierstrass.c @@ -1038,63 +1038,3 @@ int weierstrass_add_once ( struct elliptic_curve *curve, return 0; } - -/** - * Share public key - * - * @v exchange Key exchange algorithm - * @v private Private key - * @v public Public key to fill in - */ -void weierstrass_share ( struct exchange_algorithm *exchange, - const void *private, void *public ) { - struct elliptic_curve *curve = exchange->priv; - struct weierstrass_curve *weierstrass = curve->priv; - size_t len = weierstrass->len; - weierstrass_uncompressed_t ( len ) *uncompressed = public; - int rc; - - /* Calculate public key */ - uncompressed->format = WEIERSTRASS_FORMAT; - rc = weierstrass_multiply ( curve, weierstrass->base, private, - &uncompressed->xy ); - - /* Can never fail when using the curve's own base point */ - assert ( rc == 0 ); -} - -/** - * Agree shared secret - * - * @v exchange Key exchange algorithm - * @v private Private key - * @v partner Partner public key - * @v shared Shared secret to fill in - * @ret rc Return status code - */ -int weierstrass_agree ( struct exchange_algorithm *exchange, - const void *private, const void *partner, - void *shared ) { - struct elliptic_curve *curve = exchange->priv; - struct weierstrass_curve *weierstrass = curve->priv; - size_t len = weierstrass->len; - const weierstrass_uncompressed_t ( len ) *uncompressed = partner; - weierstrass_raw_t ( len ) point; - int rc; - - /* Calculate shared secret */ - if ( ( rc = weierstrass_multiply ( curve, &uncompressed->xy, private, - &point.xy ) ) != 0 ) - return rc; - memcpy ( shared, &point.x, sizeof ( point.x ) ); - - /* Check for point at infinity */ - if ( weierstrass_is_infinity ( curve, &point.xy ) ) - return -EPERM; - - /* Check format byte */ - if ( uncompressed->format != WEIERSTRASS_FORMAT ) - return -EPERM; - - return 0; -} diff --git a/src/include/ipxe/elliptic.h b/src/include/ipxe/elliptic.h new file mode 100644 index 000000000..ff3165101 --- /dev/null +++ b/src/include/ipxe/elliptic.h @@ -0,0 +1,50 @@ +#ifndef _IPXE_ELLIPTIC_H +#define _IPXE_ELLIPTIC_H + +/** @file + * + * Elliptic curves + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +#include +#include + +/** An uncompressed elliptic curve point */ +#define elliptic_uncompressed_t( len ) \ + struct { \ + uint8_t format; \ + union { \ + struct { \ + uint8_t x[ (len) ]; \ + uint8_t y[ (len) ]; \ + } __attribute__ (( packed )); \ + uint8_t xy[ (len) * 2 ]; \ + }; \ + } __attribute__ (( packed )) + +/** Format byte for uncompressed curve point representation */ +#define ELLIPTIC_FORMAT_UNCOMPRESSED 0x04 + +extern void elliptic_share ( struct exchange_algorithm *exchange, + const void *private, void *public ); +extern int elliptic_agree ( struct exchange_algorithm *exchange, + const void *private, const void *partner, + void *shared ); + +/** Define an uncompressed elliptic curve point key exchange algorithm */ +#define ELLIPTIC_EXCHANGE( _name, _exchange, _len, _curve ) \ + struct exchange_algorithm _exchange = { \ + .name = #_name, \ + .privsize = (_len), \ + .pubsize = sizeof ( elliptic_uncompressed_t (_len) ), \ + .sharedsize = (_len), \ + .share = elliptic_share, \ + .agree = elliptic_agree, \ + .priv = _curve, \ + } + +#endif /* _IPXE_ELLIPTIC_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 1398346e0..9f4661790 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -447,7 +447,7 @@ FILE_SECBOOT ( PERMITTED ); #define ERRFILE_usb_settings ( ERRFILE_OTHER | 0x00650000 ) #define ERRFILE_weierstrass ( ERRFILE_OTHER | 0x00660000 ) #define ERRFILE_efi_cacert ( ERRFILE_OTHER | 0x00670000 ) -#define ERRFILE_ecdhe ( ERRFILE_OTHER | 0x00680000 ) +#define ERRFILE_elliptic ( ERRFILE_OTHER | 0x00680000 ) #define ERRFILE_ecdsa ( ERRFILE_OTHER | 0x00690000 ) #define ERRFILE_crypto_null ( ERRFILE_OTHER | 0x006a0000 ) #define ERRFILE_ffdhe ( ERRFILE_OTHER | 0x006b0000 ) diff --git a/src/include/ipxe/weierstrass.h b/src/include/ipxe/weierstrass.h index 9e9514d9a..005f713f4 100644 --- a/src/include/ipxe/weierstrass.h +++ b/src/include/ipxe/weierstrass.h @@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED ); #include #include +#include /** Number of axes in Weierstrass curve point representation */ #define WEIERSTRASS_AXES 2 @@ -67,37 +68,6 @@ FILE_SECBOOT ( PERMITTED ); bigint_t ( size * 3 ) all; \ } -/** - * Define a Weierstrass raw affine co-ordinate type - * - * @v len Length of scalar values - * @ret type Raw affine co-ordinate type - */ -#define weierstrass_raw_t( len ) \ - union { \ - uint8_t axis[2][ len ]; \ - struct { \ - uint8_t x[ len ]; \ - uint8_t y[ len ]; \ - } __attribute__ (( packed )); \ - uint8_t xy[ len * 2 ]; \ - } - -/** - * Define a Weierstrass "uncompressed" affine co-ordinate type - * - * @v len Length of scalar values - * @ret type Uncompressed affine co-ordinate type - */ -#define weierstrass_uncompressed_t( len ) \ - struct { \ - uint8_t format; \ - weierstrass_raw_t ( len ); \ - } __attribute__ (( packed )) - -/** Format byte for Weierstrass curve point representation */ -#define WEIERSTRASS_FORMAT 0x04 /* "uncompressed" */ - /** Indexes for stored multiples of the field prime */ enum weierstrass_multiple { WEIERSTRASS_N = 0, @@ -169,8 +139,8 @@ extern int weierstrass_agree ( struct exchange_algorithm *exchange, void *shared ); /** Define a Weierstrass curve */ -#define WEIERSTRASS_CURVE( _name, _curve, _exchange, _len, _prime, \ - _a, _b, _base, _order ) \ +#define WEIERSTRASS_CURVE( _name, _curve, _len, _prime, _a, _b, _base, \ + _order ) \ static bigint_t ( weierstrass_size(_len) ) \ _name ## _cache[WEIERSTRASS_NUM_CACHED]; \ static struct weierstrass_curve _name ## _weierstrass = { \ @@ -193,7 +163,7 @@ extern int weierstrass_agree ( struct exchange_algorithm *exchange, }; \ struct elliptic_curve _curve = { \ .name = #_name, \ - .pointsize = sizeof ( weierstrass_raw_t(_len) ), \ + .pointsize = ( (_len) * WEIERSTRASS_AXES ), \ .keysize = (_len), \ .base = (_base), \ .order = (_order), \ @@ -201,15 +171,6 @@ extern int weierstrass_agree ( struct exchange_algorithm *exchange, .multiply = weierstrass_multiply, \ .add = weierstrass_add_once, \ .priv = &_name ## _weierstrass, \ - }; \ - struct exchange_algorithm _exchange = { \ - .name = #_name, \ - .privsize = (_len), \ - .pubsize = sizeof ( weierstrass_uncompressed_t(_len) ), \ - .sharedsize = (_len), \ - .share = weierstrass_share, \ - .agree = weierstrass_agree, \ - .priv = &_curve, \ } #endif /* _IPXE_WEIERSTRASS_H */