]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[tls] Allow for NIST elliptic curve point formats
authorMichael Brown <mcb30@ipxe.org>
Tue, 21 Jan 2025 15:29:05 +0000 (15:29 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 21 Jan 2025 15:55:33 +0000 (15:55 +0000)
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 <mcb30@ipxe.org>
src/crypto/mishmash/oid_x25519.c
src/crypto/x25519.c
src/include/ipxe/crypto.h
src/include/ipxe/tls.h
src/net/tls.c

index 2f8aa065b5ff01f226b04ccd3b889ce652c9e61f..30b7905eac3c6691cb9bb3dcab889e1b261db9ca 100644 (file)
@@ -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 ),
 };
index ab5d2e8b0b562160172f71a7b430f929e2d9f639..995cfa352d73a4be373bdfcc95a9ddda6b6809e0 100644 (file)
@@ -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,
 };
index dcc73f3efcf182a547814fe322956023871b10f3..4bd543ae28b6b6f8ec33ba78df6c198582d1cfaf 100644 (file)
@@ -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
         *
index 08d58689e9bf9f087863437ed40d68679b789f25..bf9807230a968c5c66d978e8f67e22c10fd122a2 100644 (file)
@@ -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 */
index 286d2cc9fcd6dd31087eed74e03e10a5fea1d554..a94e71c8a71dff308f45e9a67d132cff9bfc9e64 100644 (file)
@@ -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,