From c9291bc5c7adfa9aa05e94aded90ba49d3dc8179 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 21 Jan 2025 15:29:05 +0000 Subject: [tls] Allow for NIST elliptic curve point formats The elliptic curve point representation for the x25519 curve includes only the X value, since the curve is designed such that the Montgomery ladder does not need to ever know or calculate a Y value. There is no curve point format byte: the public key data is simply the X value. The pre-master secret is also simply the X value of the shared secret curve point. The point representation for the NIST curves includes both X and Y values, and a single curve point format byte that must indicate that the format is uncompressed. The pre-master secret for the NIST curves does not include both X and Y values: only the X value is used. Extend the definition of an elliptic curve to allow the point size to be specified separately from the key size, and extend the definition of a TLS named curve to include an optional curve point format byte and a pre-master secret length. Signed-off-by: Michael Brown --- src/crypto/mishmash/oid_x25519.c | 1 + src/crypto/x25519.c | 1 + src/include/ipxe/crypto.h | 4 +++- src/include/ipxe/tls.h | 7 +++++++ src/net/tls.c | 38 ++++++++++++++++++++++++++++---------- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/crypto/mishmash/oid_x25519.c b/src/crypto/mishmash/oid_x25519.c index 2f8aa065b..30b7905ea 100644 --- a/src/crypto/mishmash/oid_x25519.c +++ b/src/crypto/mishmash/oid_x25519.c @@ -42,4 +42,5 @@ struct asn1_algorithm x25519_algorithm __asn1_algorithm = { struct tls_named_curve tls_x25519_named_curve __tls_named_curve ( 01 ) = { .curve = &x25519_curve, .code = htons ( TLS_NAMED_CURVE_X25519 ), + .pre_master_secret_len = sizeof ( struct x25519_value ), }; diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index ab5d2e8b0..995cfa352 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -839,6 +839,7 @@ static int x25519_curve_multiply ( const void *base, const void *scalar, /** X25519 elliptic curve */ struct elliptic_curve x25519_curve = { .name = "x25519", + .pointsize = sizeof ( struct x25519_value ), .keysize = sizeof ( struct x25519_value ), .multiply = x25519_curve_multiply, }; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index dcc73f3ef..4bd543ae2 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -184,7 +184,9 @@ struct pubkey_algorithm { struct elliptic_curve { /** Curve name */ const char *name; - /** Key size */ + /** Point (and public key) size */ + size_t pointsize; + /** Scalar (and private key) size */ size_t keysize; /** Multiply scalar by curve point * diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 08d58689e..bf9807230 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -218,12 +218,19 @@ struct tls_cipher_suite { /** TLS named curved type */ #define TLS_NAMED_CURVE_TYPE 3 +/** TLS uncompressed curve point format */ +#define TLS_POINT_FORMAT_UNCOMPRESSED 4 + /** A TLS named curve */ struct tls_named_curve { /** Elliptic curve */ struct elliptic_curve *curve; /** Numeric code (in network-endian order) */ uint16_t code; + /** Curve point format byte (if any) */ + uint8_t format; + /** Pre-master secret length */ + uint8_t pre_master_secret_len; }; /** TLS named curve table */ diff --git a/src/net/tls.c b/src/net/tls.c index 286d2cc9f..a94e71c8a 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1671,6 +1671,9 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { uint8_t public[0]; } __attribute__ (( packed )) *ecdh; size_t param_len; + size_t pointsize; + size_t keysize; + size_t offset; int rc; /* Parse ServerKeyExchange record */ @@ -1706,9 +1709,13 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { tls->server.exchange_len ); return -ENOTSUP_CURVE; } + DBGC ( tls, "TLS %p using named curve %s\n", tls, curve->curve->name ); + pointsize = curve->curve->pointsize; + keysize = curve->curve->keysize; + offset = ( curve->format ? 1 : 0 ); /* Check key length */ - if ( ecdh->public_len != curve->curve->keysize ) { + if ( ecdh->public_len != ( offset + pointsize ) ) { DBGC ( tls, "TLS %p invalid %s key\n", tls, curve->curve->name ); DBGC_HDA ( tls, 0, tls->server.exchange, @@ -1716,15 +1723,23 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { return -EINVAL_KEY_EXCHANGE; } + /* Check curve point format byte (if present) */ + if ( curve->format && ( ecdh->public[0] != curve->format ) ) { + DBGC ( tls, "TLS %p invalid %s curve point format\n", + tls, curve->curve->name ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); + return -EINVAL_KEY_EXCHANGE; + } + /* Construct pre-master secret and ClientKeyExchange record */ { - size_t len = curve->curve->keysize; - uint8_t private[len]; - uint8_t pre_master_secret[len]; + uint8_t private[keysize]; + uint8_t pre_master_secret[pointsize]; struct { uint32_t type_length; uint8_t public_len; - uint8_t public[len]; + uint8_t public[ecdh->public_len]; } __attribute__ (( packed )) key_xchg; /* Generate ephemeral private key */ @@ -1733,9 +1748,9 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { return rc; } - /* Calculate pre-master secret */ - if ( ( rc = ecdhe_key ( curve->curve, ecdh->public, - private, key_xchg.public, + /* Exchange keys */ + if ( ( rc = ecdhe_key ( curve->curve, ( ecdh->public + offset ), + private, ( key_xchg.public + offset ), pre_master_secret ) ) != 0 ) { DBGC ( tls, "TLS %p could not exchange ECDHE key: %s\n", tls, strerror ( rc ) ); @@ -1743,14 +1758,17 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { } /* Generate master secret */ - tls_generate_master_secret ( tls, pre_master_secret, len ); + tls_generate_master_secret ( tls, pre_master_secret, + curve->pre_master_secret_len ); /* Generate Client Key Exchange record */ key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) | htonl ( sizeof ( key_xchg ) - sizeof ( key_xchg.type_length ) ) ); - key_xchg.public_len = len; + key_xchg.public_len = sizeof ( key_xchg.public ); + if ( curve->format ) + key_xchg.public[0] = curve->format; /* Transmit Client Key Exchange record */ if ( ( rc = tls_send_handshake ( tls, &key_xchg, -- cgit