[crypto] Generalise notion of uncompressed elliptic curve points

With algorithm private data pointers now available, the general
mechanism for key exchange using uncompressed elliptic curve points
can be separated from the Weierstrass curve implementation.

Generalise the mechanism for performing elliptic curve key exchange
using uncompressed affine co-ordinates.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2026-06-18 14:21:08 +01:00
parent af0e5d529b
commit 69e95ae7a5
7 changed files with 168 additions and 106 deletions
+105
View File
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 <assert.h>
#include <errno.h>
#include <string.h>
#include <ipxe/crypto.h>
#include <ipxe/elliptic.h>
/**
* 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;
}
+4 -1
View File
@@ -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 );
+4 -1
View File
@@ -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 );
-60
View File
@@ -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;
}
+50
View File
@@ -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 <stdint.h>
#include <ipxe/crypto.h>
/** 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 */
+1 -1
View File
@@ -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 )
+4 -43
View File
@@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED );
#include <ipxe/bigint.h>
#include <ipxe/crypto.h>
#include <ipxe/elliptic.h>
/** 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 */