summaryrefslogtreecommitdiffstats
path: root/src/crypto
diff options
context:
space:
mode:
authorSimon Rettberg2024-04-12 14:00:15 +0200
committerSimon Rettberg2024-04-12 14:00:15 +0200
commit98dc341428e247141f120d05fac48c4e144a4c0f (patch)
tree3ebacb37927e338383ac64c2e20eb0b2f820cb85 /src/crypto
parentMerge branch 'master' into openslx (diff)
parentMerge branch 'ipxe:master' into aqc1xx (diff)
downloadipxe-98dc341428e247141f120d05fac48c4e144a4c0f.tar.gz
ipxe-98dc341428e247141f120d05fac48c4e144a4c0f.tar.xz
ipxe-98dc341428e247141f120d05fac48c4e144a4c0f.zip
Merge branch 'aqc1xx' into openslx
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/bigint.c25
-rw-r--r--src/crypto/des.c695
-rw-r--r--src/crypto/gcm.c14
-rw-r--r--src/crypto/md4.c10
-rw-r--r--src/crypto/md5.c10
-rw-r--r--src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c61
-rw-r--r--src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c60
-rw-r--r--src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c45
-rw-r--r--src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c45
-rw-r--r--src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c61
-rw-r--r--src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c45
-rw-r--r--src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c45
-rw-r--r--src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c45
-rw-r--r--src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c45
-rw-r--r--src/crypto/mishmash/oid_x25519.c45
-rw-r--r--src/crypto/mishmash/rsa_aes_cbc_sha1.c34
-rw-r--r--src/crypto/mishmash/rsa_aes_cbc_sha256.c34
-rw-r--r--src/crypto/mishmash/rsa_aes_gcm_sha256.c17
-rw-r--r--src/crypto/mishmash/rsa_aes_gcm_sha384.c17
-rw-r--r--src/crypto/mschapv2.c363
-rw-r--r--src/crypto/sha1.c12
-rw-r--r--src/crypto/sha256.c18
-rw-r--r--src/crypto/sha512.c18
-rw-r--r--src/crypto/x25519.c844
-rw-r--r--src/crypto/x509.c32
25 files changed, 2495 insertions, 145 deletions
diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c
index ac9670ef..656f979e 100644
--- a/src/crypto/bigint.c
+++ b/src/crypto/bigint.c
@@ -51,6 +51,31 @@ static struct profiler bigint_mod_multiply_subtract_profiler __profiler =
{ .name = "bigint_mod_multiply.subtract" };
/**
+ * Conditionally swap big integers (in constant time)
+ *
+ * @v first0 Element 0 of big integer to be conditionally swapped
+ * @v second0 Element 0 of big integer to be conditionally swapped
+ * @v size Number of elements in big integers
+ * @v swap Swap first and second big integers
+ */
+void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0,
+ unsigned int size, int swap ) {
+ bigint_element_t mask;
+ bigint_element_t xor;
+ unsigned int i;
+
+ /* Construct mask */
+ mask = ( ( bigint_element_t ) ( ! swap ) - 1 );
+
+ /* Conditionally swap elements */
+ for ( i = 0 ; i < size ; i++ ) {
+ xor = ( mask & ( first0[i] ^ second0[i] ) );
+ first0[i] ^= xor;
+ second0[i] ^= xor;
+ }
+}
+
+/**
* Perform modular multiplication of big integers
*
* @v multiplicand0 Element 0 of big integer to be multiplied
diff --git a/src/crypto/des.c b/src/crypto/des.c
new file mode 100644
index 00000000..6918bec3
--- /dev/null
+++ b/src/crypto/des.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2024 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
+ *
+ * DES algorithm
+ *
+ * DES was not designed to be implemented in software, and therefore
+ * contains a large number of bit permutation operations that are
+ * essentially free in hardware (requiring only wires, no gates) but
+ * expensive in software.
+ *
+ * Since DES is no longer used as a practical block cipher for large
+ * volumes of data, we optimise for code size, and do not attempt to
+ * obtain fast throughput.
+ *
+ * The algorithm is specified in NIST SP 800-67, downloadable from
+ * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-67r2.pdf
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/ecb.h>
+#include <ipxe/cbc.h>
+#include <ipxe/init.h>
+#include <ipxe/des.h>
+
+/**
+ * DES shift schedule
+ *
+ * The DES shift schedule (ordered from round 16 down to round 1) is
+ * {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}. In binary, this may be
+ * represented as {1,10,10,10,10,10,10,1,10,10,10,10,10,10,1,1} and
+ * concatenated (without padding) to produce a single binary integer
+ * 1101010101010110101010101011 (equal to 0x0d556aab in hexadecimal).
+ *
+ * This integer may then be consumed LSB-first, where a 1 bit
+ * indicates a shift and the generation of a round key, and a 0 bit
+ * indicates a shift without the generation of a round key.
+ */
+#define DES_SCHEDULE 0x0d556aab
+
+/**
+ * Define an element pair in a DES S-box
+ *
+ * @v x Upper element of element pair
+ * @v y Lower element of element pair
+ *
+ * DES S-box elements are 4-bit values. We encode two values per
+ * byte, ordering the elements so that the six-bit input value may be
+ * used directly as a lookup index.
+ *
+ * Specifically, if the input value is {r1,c3,c2,c1,c0,r0}, where
+ * {r1,r0} is the table row index and {c3,c2,c1,c0} is the table
+ * column index (as used in the DES specification), then:
+ *
+ * - {r1,c3,c2,c1,c0} is the byte index into the table
+ *
+ * - (4*r0) is the required bit shift to extract the 4-bit value
+ */
+#define SBYTE( x, y ) ( ( (y) << 4 ) | (x) )
+
+/**
+ * Define a row pair in a DES S-box
+ *
+ * @v x0..xf Upper row of row pair
+ * @v y0..yf Lower row of row pair
+ */
+#define SBOX( x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, \
+ y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, ya, yb, yc, yd, ye, yf ) \
+ SBYTE ( x0, y0 ), SBYTE ( x1, y1 ), SBYTE ( x2, y2 ), SBYTE ( x3, y3 ),\
+ SBYTE ( x4, y4 ), SBYTE ( x5, y5 ), SBYTE ( x6, y6 ), SBYTE ( x7, y7 ),\
+ SBYTE ( x8, y8 ), SBYTE ( x9, y9 ), SBYTE ( xa, ya ), SBYTE ( xb, yb ),\
+ SBYTE ( xc, yc ), SBYTE ( xd, yd ), SBYTE ( xe, ye ), SBYTE ( xf, yf )
+
+/** DES S-boxes S1..S8 */
+static const uint8_t des_s[8][32] = { {
+ /* S1 */
+ SBOX ( 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 ),
+ SBOX ( 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 )
+}, {
+ /* S2 */
+ SBOX ( 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 ),
+ SBOX ( 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 )
+}, {
+ /* S3 */
+ SBOX ( 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 ),
+ SBOX ( 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 )
+}, {
+ /* S4 */
+ SBOX ( 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 ),
+ SBOX ( 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 )
+}, {
+ /* S5 */
+ SBOX ( 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 ),
+ SBOX ( 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 )
+}, {
+ /* S6 */
+ SBOX ( 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 ),
+ SBOX ( 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 )
+}, {
+ /* S7 */
+ SBOX ( 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 ),
+ SBOX ( 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 )
+}, {
+ /* S8 */
+ SBOX ( 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 ),
+ SBOX ( 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 )
+} };
+
+/**
+ * Define a bit index within permuted choice 2 (PC2)
+ *
+ * @v bit Bit index
+ *
+ * Permuted choice 2 (PC2) is used to select bits from a concatenated
+ * pair of 28-bit registers ("C" and "D") as part of the key schedule.
+ * We store these as 32-bit registers and so must add 4 to indexes
+ * above 28.
+ */
+#define DES_PC2( x ) ( (x) + ( ( (x) > 28 ) ? 4 : 0 ) )
+
+/**
+ * Define six bits of permuted choice 2 (PC2)
+ *
+ * @v r1:r0 Bits corresponding to S-box row index
+ * @v c3:c0 Bits corresponding to S-box column index
+ *
+ * There are 8 steps within a DES round (one step per S-box). Each
+ * step requires six bits of the round key, corresponding to the S-box
+ * input value {r1,c3,c2,c1,c0,r0}, where {r1,r0} is the table row
+ * index and {c3,c2,c1,c0} is the table column index.
+ *
+ * As an optimisation, we store the least significant of the 6 bits in
+ * the sign bit of a signed 8-bit value, and the remaining 5 bits in
+ * the least significant 5 bits of the 8-bit value. See the comments
+ * in des_sbox() for further details.
+ */
+#define DES_PC2R( r1, c3, c2, c1, c0, r0 ) \
+ DES_PC2 ( r0 ), /* LSB stored in sign bit */ \
+ DES_PC2 ( r0 ), /* Unused bit */ \
+ DES_PC2 ( r0 ), /* Unused bit */ \
+ DES_PC2 ( r1 ), /* Remaining 5 bits */ \
+ DES_PC2 ( c3 ), /* ... */ \
+ DES_PC2 ( c2 ), /* ... */ \
+ DES_PC2 ( c1 ), /* ... */ \
+ DES_PC2 ( c0 ) /* ... */
+
+/**
+ * A DES systematic permutation generator
+ *
+ * Many of the permutations used in DES comprise systematic bit
+ * patterns. We generate these permutations at runtime to save on
+ * code size.
+ */
+struct des_generator {
+ /** Permutation */
+ uint8_t *permutation;
+ /** Seed value */
+ uint32_t seed;
+};
+
+/**
+ * Define a DES permutation generator
+ *
+ * @v PERMUTATION Permutation
+ * @v OFFSET Fixed input bit offset (0 or 1)
+ * @v INV<n> Input bit index bit <n> should be inverted
+ * @v BIT<n> Source bit for input bit index bit <n>
+ * @ret generator Permutation generator
+ */
+#define DES_GENERATOR( PERMUTATION, OFFSET, INV5, BIT5, INV4, BIT4, \
+ INV3, BIT3, INV2, BIT2, INV1, BIT1, INV0, BIT0 ) \
+ { \
+ .permutation = (PERMUTATION), \
+ .seed = ( ( (INV0) << 31 ) | ( (BIT0) << 28 ) | \
+ ( (INV1) << 27 ) | ( (BIT1) << 24 ) | \
+ ( (INV2) << 23 ) | ( (BIT2) << 20 ) | \
+ ( (INV3) << 19 ) | ( (BIT3) << 16 ) | \
+ ( (INV4) << 15 ) | ( (BIT4) << 12 ) | \
+ ( (INV5) << 11 ) | ( (BIT5) << 8 ) | \
+ ( ( uint32_t ) sizeof (PERMUTATION) - 1 ) | \
+ (OFFSET) ), \
+ }
+
+/** DES permuted choice 1 (PC1) "C" register */
+static uint8_t des_pc1c[29];
+
+/** DES permuted choice 1 (PC1) "D" register */
+static uint8_t des_pc1d[33];
+
+/** DES permuted choice 2 (PC2) */
+static const uint8_t des_pc2[65] = {
+ DES_PC2R ( 14, 17, 11, 24, 1, 5 ),
+ DES_PC2R ( 3, 28, 15, 6, 21, 10 ),
+ DES_PC2R ( 23, 19, 12, 4, 26, 8 ),
+ DES_PC2R ( 16, 7, 27, 20, 13, 2 ),
+ DES_PC2R ( 41, 52, 31, 37, 47, 55 ),
+ DES_PC2R ( 30, 40, 51, 45, 33, 48 ),
+ DES_PC2R ( 44, 49, 39, 56, 34, 53 ),
+ DES_PC2R ( 46, 42, 50, 36, 29, 32 ),
+ 0 /* terminator */
+};
+
+/** DES initial permutation (IP) */
+static uint8_t des_ip[65];
+
+/** DES data permutation (P) */
+static const uint8_t des_p[33] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25,
+ 0 /* terminator */
+};
+
+/** DES final / inverse initial permutation (FP / IP^-1) */
+static uint8_t des_fp[65];
+
+/** DES permutation generators */
+static struct des_generator des_generators[] = {
+
+ /* The DES initial permutation transforms the bit index
+ * {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x4,x3,~x5}+1
+ */
+ DES_GENERATOR ( des_ip, 1, 1, 2, 1, 1, 1, 0, 0, 4, 0, 3, 1, 5 ),
+
+ /* The DES final permutation transforms the bit index
+ * {x5,x4,x3,x2,x1,x0}+1 into {~x0,x2,x1,~x5,~x4,~x3}+1
+ *
+ * There is an asymmetry in the DES block diagram for the last
+ * of the 16 rounds, which is functionally equivalent to
+ * performing 16 identical rounds and then swapping the left
+ * and right halves before applying the final permutation. We
+ * may therefore account for this asymmetry by inverting the
+ * MSB in each bit index, to point to the corresponding bit in
+ * the other half.
+ *
+ * This is equivalent to using a permutation that transforms
+ * {x5,x4,x3,x2,x1,x0}+1 into {x0,x2,x1,~x5,~x4,~x3}+1
+ */
+ DES_GENERATOR ( des_fp, 1, 0, 0, 0, 2, 0, 1, 1, 5, 1, 4, 1, 3 ),
+
+ /* The "C" half of DES permuted choice 1 (PC1) transforms the
+ * bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x5,x4,x3}+1
+ */
+ DES_GENERATOR ( des_pc1c, 1, 1, 2, 1, 1, 1, 0, 0, 5, 0, 4, 0, 3 ),
+
+ /* The "D" half of DES permuted choice 1 (PC1) transforms the
+ * bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,~x5,~x4,~x3}+0
+ *
+ * Due to the idosyncratic design choice of using 28-bit
+ * registers in the DES key expansion schedule, the final four
+ * permutation values appear at indices [28:31] instead of
+ * [24:27]. This is adjusted for in @c des_setkey().
+ */
+ DES_GENERATOR ( des_pc1d, 0, 1, 2, 1, 1, 1, 0, 1, 5, 1, 4, 1, 3 ),
+};
+
+/**
+ * Generate DES permutation
+ *
+ * @v generator Generator
+ */
+static __attribute__ (( noinline )) void
+des_generate ( struct des_generator *generator ) {
+ uint8_t *permutation = generator->permutation;
+ uint32_t seed = generator->seed;
+ unsigned int index = 0;
+ uint8_t accum;
+ uint8_t bit;
+
+ /* Generate permutations
+ *
+ * This loop is optimised for code size on a
+ * register-constrained architecture such as i386.
+ */
+ do {
+ /* Rotate seed to access MSB's bit descriptor */
+ seed = ror32 ( seed, 8 );
+
+ /* Initialise accumulator with six flag bits */
+ accum = 0xfc;
+
+ /* Accumulate bits until all six flag bits are cleared */
+ do {
+ /* Extract specified bit from index. Use a
+ * rotation instead of a shift, since this
+ * will allow the mask to be elided.
+ */
+ bit = ror8 ( index, ( seed & 0x07 ) );
+ seed = ror32 ( seed, 3 );
+
+ /* Toggle bit if applicable */
+ bit ^= seed;
+ seed = ror32 ( seed, 1 );
+
+ /* Add bit to accumulator and clear one flag bit */
+ accum <<= 1;
+ accum |= ( bit & 0x01 );
+
+ } while ( accum & 0x80 );
+
+ /* Add constant offset if applicable */
+ accum += ( seed & 0x01 );
+
+ /* Store permutation */
+ permutation[index] = accum;
+
+ /* Loop until reaching length (which is always even) */
+ } while ( ++index < ( seed & 0xfe ) );
+ DBGC2 ( permutation, "DES generated permutation %p:\n", permutation );
+ DBGC2_HDA ( permutation, 0, permutation,
+ ( ( seed & 0xfe ) + 1 /* zero terminator */ ) );
+}
+
+/**
+ * Initialise permutations
+ */
+static void des_init ( void ) {
+ unsigned int i;
+
+ /* Generate all generated permutations */
+ for ( i = 0 ; i < ( sizeof ( des_generators ) /
+ sizeof ( des_generators[0] ) ) ; i++ ) {
+ des_generate ( &des_generators[i] );
+ }
+}
+
+/** Initialisation function */
+struct init_fn des_init_fn __init_fn ( INIT_NORMAL ) = {
+ .initialise = des_init,
+};
+
+/**
+ * Perform bit permutation
+ *
+ * @v permutation Bit permutation (zero-terminated)
+ * @v in Input value
+ * @v out Output value
+ */
+static void des_permute ( const uint8_t *permutation, const uint8_t *in,
+ uint8_t *out ) {
+ uint8_t mask = 0x80;
+ uint8_t accum = 0;
+ unsigned int bit;
+
+ /* Extract individual input bits to construct output value */
+ while ( ( bit = *(permutation++) ) ) {
+ bit--;
+ if ( in[ bit / 8 ] & ( 0x80 >> ( bit % 8 ) ) )
+ accum |= mask;
+ *out = accum;
+ mask = ror8 ( mask, 1 );
+ if ( mask == 0x80 ) {
+ out++;
+ accum = 0;
+ }
+ }
+}
+
+/**
+ * Perform DES S-box substitution
+ *
+ * @v in 32-bit input value (native endian)
+ * @v rkey 48-bit round key
+ * @ret out 32-bit output value (native endian)
+ */
+static uint32_t des_sbox ( uint32_t in, const union des_round_key *rkey ) {
+ uint32_t out = 0;
+ uint32_t lookup;
+ int32_t key;
+ uint8_t sub;
+ unsigned int i;
+
+ /* Perform input expansion, key addition, and S-box substitution */
+ for ( i = 0 ; i < 8 ; i++ ) {
+
+ /* Rotate input and output */
+ out = rol32 ( out, 4 );
+ in = rol32 ( in, 4 );
+
+ /* Extract step key from relevant 6 bits of round key
+ *
+ * The least significant of the 6 bits (corresponding
+ * to bit r0 in the S-box lookup index) is stored in
+ * the sign bit of the step key byte. It will
+ * therefore be propagated via sign extension to the
+ * MSB of the 32-bit step key.
+ *
+ * The remaining 5 of the 6 bits (corresponding to
+ * bits {r1,c3,c2,c1,c0} in the S-box lookup index)
+ * are stored in the least significant 5 bits of the
+ * step key byte and will end up in the least
+ * significant 5 bits of the 32-bit step key.
+ */
+ key = rkey->step[i];
+
+ /* Add step key to input to produce S-box lookup index
+ *
+ * We do not ever perform an explicit expansion of the
+ * input value from 32 to 48 bits. Instead, we rotate
+ * the 32-bit input value by 4 bits on each step, and
+ * extract the relevant 6 bits.
+ *
+ * The least significant of the 6 bits (corresponding
+ * to bit r0 in the S-box lookup index) is currently
+ * in the MSB of the 32-bit (rotated) input value.
+ *
+ * The remaining 5 of the 6 bits (corresponding to
+ * bits {r1,c3,c2,c1,c0} in the S-box lookup index)
+ * are currently in the least significant 5 bits of
+ * the 32-bit (rotated) input value.
+ *
+ * This aligns with the placement of the bits in the
+ * step key (see above), and we can therefore perform
+ * a single XOR to add the 6-bit step key to the
+ * relevant 6 bits of the input value.
+ */
+ lookup = ( in ^ key );
+
+ /* Look up S[i][in ^ key] from S-box
+ *
+ * We have bits {r1,c3,c2,c1,c0} in the least
+ * significant 5 bits of the lookup index, and so can
+ * use the masked lookup index directly as a byte
+ * index into the relevant S-box to extract the byte
+ * containing both {r1,c3,c2,c1,c0,'0'} and
+ * {r1,c3,c2,c1,c0,'1'}.
+ *
+ * We then use the MSB of the 32-bit lookup index to
+ * extract the relevant nibble for the full lookup
+ * index {r1,c3,c2,c1,c0,r0}.
+ */
+ sub = des_s[i][ lookup & 0x1f ];
+ sub >>= ( ( lookup >> 29 ) & 4 );
+ sub &= 0x0f;
+
+ /* Substitute S[i][input ^ key] into output */
+ out |= sub;
+ }
+
+ return out;
+}
+
+/**
+ * Perform a single DES round
+ *
+ * @v block DES block
+ * @v rkey 48-bit round key
+ */
+static void des_round ( union des_block *block,
+ const union des_round_key *rkey ) {
+ union des_dword sbox;
+ uint32_t left;
+ uint32_t right;
+
+ /* Extract left and right halves L[n-1] and R[n-1] */
+ left = block->left.dword;
+ right = block->right.dword;
+ DBGC2 ( block, "DES L=%08x R=%08x K=%08x%08x", be32_to_cpu ( left ),
+ be32_to_cpu ( right ), be32_to_cpu ( rkey->dword[0] ),
+ be32_to_cpu ( rkey->dword[1] ) );
+
+ /* L[n] = R[n-1] */
+ block->left.dword = right;
+
+ /* Calculate Feistel function f(R[n-1], K[n]) */
+ sbox.dword = cpu_to_be32 ( des_sbox ( be32_to_cpu ( right ), rkey ) );
+ des_permute ( des_p, sbox.byte, block->right.byte );
+
+ /* R[n] = L[n-1] + f(R[n-1], K[n]) */
+ block->right.dword ^= left;
+ DBGC2 ( block, " => L=%08x R=%08x\n",
+ be32_to_cpu ( block->left.dword ),
+ be32_to_cpu ( block->right.dword ) );
+}
+
+/**
+ * Perform all DES rounds
+ *
+ * @v in Input DES block
+ * @v out Output DES block
+ * @v rkey Starting 48-bit round key
+ * @v offset Byte offset between round keys
+ */
+static void des_rounds ( const union des_block *in, union des_block *out,
+ const union des_round_key *rkey,
+ ssize_t offset ) {
+ union des_block tmp;
+ unsigned int i;
+
+ /* Apply initial permutation */
+ des_permute ( des_ip, in->byte, tmp.byte );
+
+ /* Perform all DES rounds, consuming keys in the specified order */
+ for ( i = 0 ; i < DES_ROUNDS ; i++ ) {
+ des_round ( &tmp, rkey );
+ rkey = ( ( ( void * ) rkey ) + offset );
+ }
+
+ /* Apply final permutation */
+ DBGC ( &tmp, "DES %scrypted %08x%08x => ",
+ ( ( offset > 0 ) ? "en" : "de" ), be32_to_cpu ( in->dword[0] ),
+ be32_to_cpu ( in->dword[1] ) );
+ des_permute ( des_fp, tmp.byte, out->byte );
+ DBGC ( &tmp, "%08x%08x\n", be32_to_cpu ( out->dword[0] ),
+ be32_to_cpu ( out->dword[1] ) );
+}
+
+/**
+ * Rotate 28-bit word
+ *
+ * @v dword 28-bit dword value
+ * @ret dword Rotated 28-bit dword value
+ */
+static uint32_t des_rol28 ( uint32_t dword ) {
+ int32_t sdword;
+
+ /* Convert to native-endian */
+ sdword = be32_to_cpu ( dword );
+
+ /* Signed shift right by 4 places to copy bit 31 to bits 27:31 */
+ sdword >>= 4;
+
+ /* Rotate left */
+ sdword = rol32 ( sdword, 1 );
+
+ /* Shift left by 4 places to restore bit positions */
+ sdword <<= 4;
+
+ /* Convert back to big-endian */
+ dword = cpu_to_be32 ( sdword );
+
+ return dword;
+}
+
+/**
+ * Set key
+ *
+ * @v ctx Context
+ * @v key Key
+ * @v keylen Key length
+ * @ret rc Return status code
+ */
+static int des_setkey ( void *ctx, const void *key, size_t keylen ) {
+ struct des_context *des = ctx;
+ union des_round_key *rkey = des->rkey;
+ union des_block reg;
+ uint32_t schedule;
+
+ /* Validate key length */
+ if ( keylen != DES_BLOCKSIZE )
+ return -EINVAL;
+ DBGC ( des, "DES %p new key:\n", des );
+ DBGC_HDA ( des, 0, key, keylen );
+
+ /* Apply permuted choice 1 */
+ des_permute ( des_pc1c, key, reg.c.byte );
+ des_permute ( des_pc1d, key, reg.d.byte );
+ reg.d.byte[3] <<= 4; /* see comment for @c des_pc1d */
+ DBGC2 ( des, "DES %p C[ 0]=%07x D[ 0]=%07x\n",
+ des, ( be32_to_cpu ( reg.c.dword ) >> 4 ),
+ ( be32_to_cpu ( reg.d.dword ) >> 4 ) );
+
+ /* Generate round keys */
+ for ( schedule = DES_SCHEDULE ; schedule ; schedule >>= 1 ) {
+
+ /* Shift 28-bit words */
+ reg.c.dword = des_rol28 ( reg.c.dword );
+ reg.d.dword = des_rol28 ( reg.d.dword );
+
+ /* Skip rounds according to shift schedule */
+ if ( ! ( schedule & 1 ) )
+ continue;
+
+ /* Apply permuted choice 2 */
+ des_permute ( des_pc2, reg.byte, rkey->byte );
+ DBGC2 ( des, "DES %p C[%2zd]=%07x D[%2zd]=%07x K[%2zd]="
+ "%08x%08x\n", des, ( ( rkey - des->rkey ) + 1 ),
+ ( be32_to_cpu ( reg.c.dword ) >> 4 ),
+ ( ( rkey - des->rkey ) + 1 ),
+ ( be32_to_cpu ( reg.d.dword ) >> 4 ),
+ ( ( rkey - des->rkey ) + 1 ),
+ be32_to_cpu ( rkey->dword[0] ),
+ be32_to_cpu ( rkey->dword[1] ) );
+
+ /* Move to next key */
+ rkey++;
+ }
+
+ /* Sanity check */
+ assert ( rkey == &des->rkey[DES_ROUNDS] );
+
+ return 0;
+}
+
+/**
+ * Encrypt data
+ *
+ * @v ctx Context
+ * @v src Data to encrypt
+ * @v dst Buffer for encrypted data
+ * @v len Length of data
+ */
+static void des_encrypt ( void *ctx, const void *src, void *dst, size_t len ) {
+ struct des_context *des = ctx;
+
+ /* Sanity check */
+ assert ( len == DES_BLOCKSIZE );
+
+ /* Cipher using keys in forward direction */
+ des_rounds ( src, dst, &des->rkey[0], sizeof ( des->rkey[0] ) );
+}
+
+/**
+ * Decrypt data
+ *
+ * @v ctx Context
+ * @v src Data to decrypt
+ * @v dst Buffer for decrypted data
+ * @v len Length of data
+ */
+static void des_decrypt ( void *ctx, const void *src, void *dst, size_t len ) {
+ struct des_context *des = ctx;
+
+ /* Sanity check */
+ assert ( len == DES_BLOCKSIZE );
+
+ /* Cipher using keys in reverse direction */
+ des_rounds ( src, dst, &des->rkey[ DES_ROUNDS - 1 ],
+ -sizeof ( des->rkey[0] ) );
+}
+
+/** Basic DES algorithm */
+struct cipher_algorithm des_algorithm = {
+ .name = "des",
+ .ctxsize = sizeof ( struct des_context ),
+ .blocksize = DES_BLOCKSIZE,
+ .alignsize = 0,
+ .authsize = 0,
+ .setkey = des_setkey,
+ .setiv = cipher_null_setiv,
+ .encrypt = des_encrypt,
+ .decrypt = des_decrypt,
+ .auth = cipher_null_auth,
+};
+
+/* DES in Electronic Codebook mode */
+ECB_CIPHER ( des_ecb, des_ecb_algorithm,
+ des_algorithm, struct des_context, DES_BLOCKSIZE );
+
+/* DES in Cipher Block Chaining mode */
+CBC_CIPHER ( des_cbc, des_cbc_algorithm,
+ des_algorithm, struct des_context, DES_BLOCKSIZE );
diff --git a/src/crypto/gcm.c b/src/crypto/gcm.c
index 9d8bae82..a32890d5 100644
--- a/src/crypto/gcm.c
+++ b/src/crypto/gcm.c
@@ -469,13 +469,15 @@ int gcm_setkey ( struct gcm_context *context, const void *key, size_t keylen,
* @v ivlen Initialisation vector length
*/
void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ) {
- union gcm_block *check = ( ( void * ) context );
- /* Sanity checks */
- linker_assert ( &context->hash == check, gcm_bad_layout );
- linker_assert ( &context->len == check + 1, gcm_bad_layout );
- linker_assert ( &context->ctr == check + 2, gcm_bad_layout );
- linker_assert ( &context->key == check + 3, gcm_bad_layout );
+ /* Sanity check: ensure that memset()s will clear expected state */
+ build_assert ( &context->hash < &context->ctr );
+ build_assert ( &context->len < &context->ctr );
+ build_assert ( &context->ctr < &context->key );
+ build_assert ( ( ( void * ) &context->raw_cipher ) >
+ ( ( void * ) &context->key ) );
+ build_assert ( ( ( void * ) context->raw_ctx ) >
+ ( ( void * ) &context->key ) );
/* Reset non-key state */
memset ( context, 0, offsetof ( typeof ( *context ), key ) );
diff --git a/src/crypto/md4.c b/src/crypto/md4.c
index ca5dcc21..dcd86a42 100644
--- a/src/crypto/md4.c
+++ b/src/crypto/md4.c
@@ -155,11 +155,11 @@ static void md4_digest ( struct md4_context *context ) {
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
- linker_assert ( &u.ddd.dd.digest.h[0] == a, md4_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[1] == b, md4_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[2] == c, md4_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[3] == d, md4_bad_layout );
- linker_assert ( &u.ddd.dd.data.dword[0] == w, md4_bad_layout );
+ build_assert ( &u.ddd.dd.digest.h[0] == a );
+ build_assert ( &u.ddd.dd.digest.h[1] == b );
+ build_assert ( &u.ddd.dd.digest.h[2] == c );
+ build_assert ( &u.ddd.dd.digest.h[3] == d );
+ build_assert ( &u.ddd.dd.data.dword[0] == w );
DBGC ( context, "MD4 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
diff --git a/src/crypto/md5.c b/src/crypto/md5.c
index bee382e9..5c62513e 100644
--- a/src/crypto/md5.c
+++ b/src/crypto/md5.c
@@ -178,11 +178,11 @@ static void md5_digest ( struct md5_context *context ) {
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
- linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout );
- linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout );
+ build_assert ( &u.ddd.dd.digest.h[0] == a );
+ build_assert ( &u.ddd.dd.digest.h[1] == b );
+ build_assert ( &u.ddd.dd.digest.h[2] == c );
+ build_assert ( &u.ddd.dd.digest.h[3] == d );
+ build_assert ( &u.ddd.dd.data.dword[0] == w );
DBGC ( context, "MD5 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
diff --git a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c
new file mode 100644
index 00000000..05e409f7
--- /dev/null
+++ b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/tls.h>
+
+/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */
+struct tls_cipher_suite
+tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
+ .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ),
+ .key_len = ( 128 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA1_DIGEST_SIZE,
+ .exchange = &tls_dhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha1_algorithm,
+ .handshake = &sha256_algorithm,
+};
+
+/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */
+struct tls_cipher_suite
+tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = {
+ .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ),
+ .key_len = ( 256 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA1_DIGEST_SIZE,
+ .exchange = &tls_dhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha1_algorithm,
+ .handshake = &sha256_algorithm,
+};
diff --git a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c
new file mode 100644
index 00000000..6ce42864
--- /dev/null
+++ b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha256.h>
+#include <ipxe/tls.h>
+
+/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
+struct tls_cipher_suite
+tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
+ .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ),
+ .key_len = ( 128 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA256_DIGEST_SIZE,
+ .exchange = &tls_dhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha256_algorithm,
+ .handshake = &sha256_algorithm,
+};
+
+/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
+struct tls_cipher_suite
+tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = {
+ .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ),
+ .key_len = ( 256 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA256_DIGEST_SIZE,
+ .exchange = &tls_dhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha256_algorithm,
+ .handshake = &sha256_algorithm,
+};
diff --git a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c
new file mode 100644
index 00000000..dc5cad9f
--- /dev/null
+++ b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha256.h>
+#include <ipxe/tls.h>
+
+/** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
+struct tls_cipher_suite
+tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = {
+ .code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ),
+ .key_len = ( 128 / 8 ),
+ .fixed_iv_len = 4,
+ .record_iv_len = 8,
+ .mac_len = 0,
+ .exchange = &tls_dhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_gcm_algorithm,
+ .digest = &sha256_algorithm,
+ .handshake = &sha256_algorithm,
+};
diff --git a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c
new file mode 100644
index 00000000..0448255f
--- /dev/null
+++ b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha512.h>
+#include <ipxe/tls.h>
+
+/** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
+struct tls_cipher_suite
+tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = {
+ .code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ),
+ .key_len = ( 256 / 8 ),
+ .fixed_iv_len = 4,
+ .record_iv_len = 8,
+ .mac_len = 0,
+ .exchange = &tls_dhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_gcm_algorithm,
+ .digest = &sha384_algorithm,
+ .handshake = &sha384_algorithm,
+};
diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c
new file mode 100644
index 00000000..c23f65cc
--- /dev/null
+++ b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/tls.h>
+
+/** TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA cipher suite */
+struct tls_cipher_suite
+tls_ecdhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = {
+ .code = htons ( TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA ),
+ .key_len = ( 128 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA1_DIGEST_SIZE,
+ .exchange = &tls_ecdhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha1_algorithm,
+ .handshake = &sha256_algorithm,
+};
+
+/** TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA cipher suite */
+struct tls_cipher_suite
+tls_ecdhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = {
+ .code = htons ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ),
+ .key_len = ( 256 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA1_DIGEST_SIZE,
+ .exchange = &tls_ecdhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha1_algorithm,
+ .handshake = &sha256_algorithm,
+};
diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c
new file mode 100644
index 00000000..431e2e30
--- /dev/null
+++ b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha256.h>
+#include <ipxe/tls.h>
+
+/** TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
+struct tls_cipher_suite
+tls_ecdhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = {
+ .code = htons ( TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ),
+ .key_len = ( 128 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA256_DIGEST_SIZE,
+ .exchange = &tls_ecdhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha256_algorithm,
+ .handshake = &sha256_algorithm,
+};
diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c
new file mode 100644
index 00000000..c5297680
--- /dev/null
+++ b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha512.h>
+#include <ipxe/tls.h>
+
+/** TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 cipher suite */
+struct tls_cipher_suite
+tls_ecdhe_rsa_with_aes_256_cbc_sha384 __tls_cipher_suite ( 04 ) = {
+ .code = htons ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ),
+ .key_len = ( 256 / 8 ),
+ .fixed_iv_len = 0,
+ .record_iv_len = AES_BLOCKSIZE,
+ .mac_len = SHA384_DIGEST_SIZE,
+ .exchange = &tls_ecdhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha384_algorithm,
+ .handshake = &sha384_algorithm,
+};
diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c
new file mode 100644
index 00000000..4f4e38c6
--- /dev/null
+++ b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha256.h>
+#include <ipxe/tls.h>
+
+/** TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
+struct tls_cipher_suite
+tls_ecdhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = {
+ .code = htons ( TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ),
+ .key_len = ( 128 / 8 ),
+ .fixed_iv_len = 4,
+ .record_iv_len = 8,
+ .mac_len = 0,
+ .exchange = &tls_ecdhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_gcm_algorithm,
+ .digest = &sha256_algorithm,
+ .handshake = &sha256_algorithm,
+};
diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c
new file mode 100644
index 00000000..0bc7c305
--- /dev/null
+++ b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha512.h>
+#include <ipxe/tls.h>
+
+/** TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
+struct tls_cipher_suite
+tls_ecdhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = {
+ .code = htons ( TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ),
+ .key_len = ( 256 / 8 ),
+ .fixed_iv_len = 4,
+ .record_iv_len = 8,
+ .mac_len = 0,
+ .exchange = &tls_ecdhe_exchange_algorithm,
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_gcm_algorithm,
+ .digest = &sha384_algorithm,
+ .handshake = &sha384_algorithm,
+};
diff --git a/src/crypto/mishmash/oid_x25519.c b/src/crypto/mishmash/oid_x25519.c
new file mode 100644
index 00000000..2f8aa065
--- /dev/null
+++ b/src/crypto/mishmash/oid_x25519.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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 (at your option) 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 );
+
+#include <byteswap.h>
+#include <ipxe/x25519.h>
+#include <ipxe/asn1.h>
+#include <ipxe/tls.h>
+
+/** "x25519" object identifier */
+static uint8_t oid_x25519[] = { ASN1_OID_X25519 };
+
+/** "x25519" OID-identified algorithm */
+struct asn1_algorithm x25519_algorithm __asn1_algorithm = {
+ .name = "x25519",
+ .curve = &x25519_curve,
+ .oid = ASN1_CURSOR ( oid_x25519 ),
+};
+
+/** X25519 named curve */
+struct tls_named_curve tls_x25519_named_curve __tls_named_curve ( 01 ) = {
+ .curve = &x25519_curve,
+ .code = htons ( TLS_NAMED_CURVE_X25519 ),
+};
diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha1.c b/src/crypto/mishmash/rsa_aes_cbc_sha1.c
index 9f8193de..0862fb5a 100644
--- a/src/crypto/mishmash/rsa_aes_cbc_sha1.c
+++ b/src/crypto/mishmash/rsa_aes_cbc_sha1.c
@@ -30,39 +30,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/sha256.h>
#include <ipxe/tls.h>
-/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */
-struct tls_cipher_suite
-tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = {
- .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ),
- .key_len = ( 128 / 8 ),
- .fixed_iv_len = 0,
- .record_iv_len = AES_BLOCKSIZE,
- .mac_len = SHA1_DIGEST_SIZE,
- .exchange = &tls_dhe_exchange_algorithm,
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha1_algorithm,
- .handshake = &sha256_algorithm,
-};
-
-/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */
-struct tls_cipher_suite
-tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = {
- .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ),
- .key_len = ( 256 / 8 ),
- .fixed_iv_len = 0,
- .record_iv_len = AES_BLOCKSIZE,
- .mac_len = SHA1_DIGEST_SIZE,
- .exchange = &tls_dhe_exchange_algorithm,
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha1_algorithm,
- .handshake = &sha256_algorithm,
-};
-
/** TLS_RSA_WITH_AES_128_CBC_SHA cipher suite */
struct tls_cipher_suite
-tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
+tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 25 ) = {
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 0,
@@ -77,7 +47,7 @@ tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
/** TLS_RSA_WITH_AES_256_CBC_SHA cipher suite */
struct tls_cipher_suite
-tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = {
+tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 26 ) = {
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 0,
diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha256.c b/src/crypto/mishmash/rsa_aes_cbc_sha256.c
index d0dc8496..e5928db8 100644
--- a/src/crypto/mishmash/rsa_aes_cbc_sha256.c
+++ b/src/crypto/mishmash/rsa_aes_cbc_sha256.c
@@ -29,39 +29,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/sha256.h>
#include <ipxe/tls.h>
-/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
-struct tls_cipher_suite
-tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = {
- .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ),
- .key_len = ( 128 / 8 ),
- .fixed_iv_len = 0,
- .record_iv_len = AES_BLOCKSIZE,
- .mac_len = SHA256_DIGEST_SIZE,
- .exchange = &tls_dhe_exchange_algorithm,
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha256_algorithm,
- .handshake = &sha256_algorithm,
-};
-
-/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
-struct tls_cipher_suite
-tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 04 ) = {
- .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ),
- .key_len = ( 256 / 8 ),
- .fixed_iv_len = 0,
- .record_iv_len = AES_BLOCKSIZE,
- .mac_len = SHA256_DIGEST_SIZE,
- .exchange = &tls_dhe_exchange_algorithm,
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha256_algorithm,
- .handshake = &sha256_algorithm,
-};
-
/** TLS_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
struct tls_cipher_suite
-tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
+tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 23 ) = {
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 0,
@@ -76,7 +46,7 @@ tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
/** TLS_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
struct tls_cipher_suite
-tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = {
+tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 24 ) = {
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 0,
diff --git a/src/crypto/mishmash/rsa_aes_gcm_sha256.c b/src/crypto/mishmash/rsa_aes_gcm_sha256.c
index cf9c4c27..b18bbd84 100644
--- a/src/crypto/mishmash/rsa_aes_gcm_sha256.c
+++ b/src/crypto/mishmash/rsa_aes_gcm_sha256.c
@@ -29,24 +29,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/sha256.h>
#include <ipxe/tls.h>
-/** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
-struct tls_cipher_suite
-tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = {
- .code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ),
- .key_len = ( 128 / 8 ),
- .fixed_iv_len = 4,
- .record_iv_len = 8,
- .mac_len = 0,
- .exchange = &tls_dhe_exchange_algorithm,
- .pubkey = &rsa_algorithm,
- .cipher = &aes_gcm_algorithm,
- .digest = &sha256_algorithm,
- .handshake = &sha256_algorithm,
-};
-
/** TLS_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
struct tls_cipher_suite
-tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = {
+tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 21 ) = {
.code = htons ( TLS_RSA_WITH_AES_128_GCM_SHA256 ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 4,
diff --git a/src/crypto/mishmash/rsa_aes_gcm_sha384.c b/src/crypto/mishmash/rsa_aes_gcm_sha384.c
index 10a977f7..06558aae 100644
--- a/src/crypto/mishmash/rsa_aes_gcm_sha384.c
+++ b/src/crypto/mishmash/rsa_aes_gcm_sha384.c
@@ -29,24 +29,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/sha512.h>
#include <ipxe/tls.h>
-/** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
-struct tls_cipher_suite
-tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = {
- .code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ),
- .key_len = ( 256 / 8 ),
- .fixed_iv_len = 4,
- .record_iv_len = 8,
- .mac_len = 0,
- .exchange = &tls_dhe_exchange_algorithm,
- .pubkey = &rsa_algorithm,
- .cipher = &aes_gcm_algorithm,
- .digest = &sha384_algorithm,
- .handshake = &sha384_algorithm,
-};
-
/** TLS_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
struct tls_cipher_suite
-tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = {
+tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 22 ) = {
.code = htons ( TLS_RSA_WITH_AES_256_GCM_SHA384 ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 4,
diff --git a/src/crypto/mschapv2.c b/src/crypto/mschapv2.c
new file mode 100644
index 00000000..ac55fec1
--- /dev/null
+++ b/src/crypto/mschapv2.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2024 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
+ *
+ * MS-CHAPv2 authentication
+ *
+ * The algorithms used for MS-CHAPv2 authentication are defined in
+ * RFC 2759 section 8.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <byteswap.h>
+#include <ipxe/md4.h>
+#include <ipxe/sha1.h>
+#include <ipxe/des.h>
+#include <ipxe/mschapv2.h>
+
+/**
+ * MS-CHAPv2 context block
+ *
+ * For no particularly discernible reason, MS-CHAPv2 uses two
+ * different digest algorithms and one block cipher. The uses do not
+ * overlap, so share the context storage between these to reduce stack
+ * usage.
+ */
+union mschapv2_context {
+ /** SHA-1 digest context */
+ uint8_t sha1[SHA1_CTX_SIZE];
+ /** MD4 digest context */
+ uint8_t md4[MD4_CTX_SIZE];
+ /** DES cipher context */
+ uint8_t des[DES_CTX_SIZE];
+};
+
+/**
+ * MS-CHAPv2 challenge hash
+ *
+ * MS-CHAPv2 calculates the SHA-1 digest of the peer challenge, the
+ * authenticator challenge, and the username, and then uses only the
+ * first 8 bytes of the result (as a DES plaintext block).
+ */
+union mschapv2_challenge_hash {
+ /** SHA-1 digest */
+ uint8_t sha1[SHA1_DIGEST_SIZE];
+ /** DES plaintext block */
+ uint8_t des[DES_BLOCKSIZE];
+};
+
+/**
+ * MS-CHAPv2 password hash
+ *
+ * MS-CHAPv2 calculates the MD4 digest of an unspecified two-byte
+ * little-endian Unicode encoding (presumably either UCS-2LE or
+ * UTF-16LE) of the password.
+ *
+ * For constructing the challenge response, the MD4 digest is then
+ * zero-padded to 21 bytes and used as three separate 56-bit DES keys.
+ *
+ * For constructing the authenticator response, the MD4 digest is then
+ * used as an input to a SHA-1 digest along with the NT response and a
+ * magic constant.
+ */
+union mschapv2_password_hash {
+ /** MD4 digest */
+ uint8_t md4[MD4_DIGEST_SIZE];
+ /** SHA-1 digest */
+ uint8_t sha1[SHA1_DIGEST_SIZE];
+ /** DES keys */
+ uint8_t des[3][DES_BLOCKSIZE];
+ /** DES key expansion */
+ uint8_t expand[ 3 * DES_BLOCKSIZE ];
+};
+
+/** MS-CHAPv2 magic constant 1 */
+static const char mschapv2_magic1[39] =
+ "Magic server to client signing constant";
+
+/** MS-CHAPv2 magic constant 2 */
+static const char mschapv2_magic2[41] =
+ "Pad to make it do more than one iteration";
+
+/**
+ * Calculate MS-CHAPv2 challenge hash
+ *
+ * @v ctx Context block
+ * @v challenge Authenticator challenge
+ * @v peer Peer challenge
+ * @v username User name (or NULL to use empty string)
+ * @v chash Challenge hash to fill in
+ *
+ * This is the ChallengeHash() function as documented in RFC 2759
+ * section 8.2.
+ */
+static void
+mschapv2_challenge_hash ( union mschapv2_context *ctx,
+ const struct mschapv2_challenge *challenge,
+ const struct mschapv2_challenge *peer,
+ const char *username,
+ union mschapv2_challenge_hash *chash ) {
+ struct digest_algorithm *sha1 = &sha1_algorithm;
+
+ /* Calculate SHA-1 hash of challenges and username */
+ digest_init ( sha1, ctx->sha1 );
+ digest_update ( sha1, ctx->sha1, peer, sizeof ( *peer ) );
+ digest_update ( sha1, ctx->sha1, challenge, sizeof ( *challenge ) );
+ if ( username ) {
+ digest_update ( sha1, ctx->sha1, username,
+ strlen ( username ) );
+ }
+ digest_final ( sha1, ctx->sha1, chash->sha1 );
+ DBGC ( ctx, "MSCHAPv2 authenticator challenge:\n" );
+ DBGC_HDA ( ctx, 0, challenge, sizeof ( *challenge ) );
+ DBGC ( ctx, "MSCHAPv2 peer challenge:\n" );
+ DBGC_HDA ( ctx, 0, peer, sizeof ( *peer ) );
+ DBGC ( ctx, "MSCHAPv2 challenge hash:\n" );
+ DBGC_HDA ( ctx, 0, chash->des, sizeof ( chash->des ) );
+}
+
+/**
+ * Calculate MS-CHAPv2 password hash
+ *
+ * @v ctx Context block
+ * @v password Password (or NULL to use empty string)
+ * @v phash Password hash to fill in
+ *
+ * This is the NtPasswordHash() function as documented in RFC 2759
+ * section 8.3.
+ */
+static void mschapv2_password_hash ( union mschapv2_context *ctx,
+ const char *password,
+ union mschapv2_password_hash *phash ) {
+ struct digest_algorithm *md4 = &md4_algorithm;
+ uint16_t wc;
+ uint8_t c;
+
+ /* Construct zero-padded MD4 hash of encoded password */
+ memset ( phash, 0, sizeof ( *phash ) );
+ digest_init ( md4, ctx->md4 );
+ if ( password ) {
+ while ( ( c = *(password++) ) ) {
+ wc = cpu_to_le16 ( c );
+ digest_update ( md4, ctx->md4, &wc, sizeof ( wc ) );
+ }
+ }
+ digest_final ( md4, ctx->md4, phash->md4 );
+ DBGC ( ctx, "MSCHAPv2 password hash:\n" );
+ DBGC_HDA ( ctx, 0, phash->md4, sizeof ( phash->md4 ) );
+}
+
+/**
+ * Hash the MS-CHAPv2 password hash
+ *
+ * @v ctx Context block
+ * @v phash Password hash to be rehashed
+ *
+ * This is the HashNtPasswordHash() function as documented in RFC 2759
+ * section 8.4.
+ */
+static void mschapv2_hash_hash ( union mschapv2_context *ctx,
+ union mschapv2_password_hash *phash ) {
+ struct digest_algorithm *md4 = &md4_algorithm;
+
+ /* Calculate MD4 hash of existing MD4 hash */
+ digest_init ( md4, ctx->md4 );
+ digest_update ( md4, ctx->md4, phash->md4, sizeof ( phash->md4 ) );
+ digest_final ( md4, ctx->md4, phash->md4 );
+ DBGC ( ctx, "MSCHAPv2 password hash hash:\n" );
+ DBGC_HDA ( ctx, 0, phash->md4, sizeof ( phash->md4 ) );
+}
+
+/**
+ * Expand MS-CHAPv2 password hash by inserting DES dummy parity bits
+ *
+ * @v ctx Context block
+ * @v phash Password hash to expand
+ *
+ * This is part of the DesEncrypt() function as documented in RFC 2759
+ * section 8.6.
+ */
+static void mschapv2_expand_hash ( union mschapv2_context *ctx,
+ union mschapv2_password_hash *phash ) {
+ uint8_t *dst;
+ uint8_t *src;
+ unsigned int i;
+
+ /* Expand password hash by inserting (unused) DES parity bits */
+ for ( i = ( sizeof ( phash->expand ) - 1 ) ; i > 0 ; i-- ) {
+ dst = &phash->expand[i];
+ src = ( dst - ( i / 8 ) );
+ *dst = ( ( ( src[-1] << 8 ) | src[0] ) >> ( i % 8 ) );
+ }
+ DBGC ( ctx, "MSCHAPv2 expanded password hash:\n" );
+ DBGC_HDA ( ctx, 0, phash->expand, sizeof ( phash->expand ) );
+}
+
+/**
+ * Calculate MS-CHAPv2 challenge response
+ *
+ * @v ctx Context block
+ * @v chash Challenge hash
+ * @v phash Password hash (after expansion)
+ * @v nt NT response to fill in
+ *
+ * This is the ChallengeResponse() function as documented in RFC 2759
+ * section 8.5.
+ */
+static void
+mschapv2_challenge_response ( union mschapv2_context *ctx,
+ const union mschapv2_challenge_hash *chash,
+ const union mschapv2_password_hash *phash,
+ struct mschapv2_nt_response *nt ) {
+ struct cipher_algorithm *des = &des_algorithm;
+ unsigned int i;
+ int rc;
+
+ /* Construct response. The design of the algorithm here is
+ * interesting, suggesting that an intern at Microsoft had
+ * heard the phrase "Triple DES" and hazarded a blind guess at
+ * what it might mean.
+ */
+ for ( i = 0 ; i < ( sizeof ( phash->des ) /
+ sizeof ( phash->des[0] ) ) ; i++ ) {
+ rc = cipher_setkey ( des, ctx->des, phash->des[i],
+ sizeof ( phash->des[i] ) );
+ assert ( rc == 0 ); /* no failure mode exists */
+ cipher_encrypt ( des, ctx->des, chash->des, nt->block[i],
+ sizeof ( chash->des ) );
+ }
+ DBGC ( ctx, "MSCHAPv2 NT response:\n" );
+ DBGC_HDA ( ctx, 0, nt, sizeof ( *nt ) );
+}
+
+/**
+ * Calculate MS-CHAPv2 challenge response
+ *
+ * @v username User name (or NULL to use empty string)
+ * @v password Password (or NULL to use empty string)
+ * @v challenge Authenticator challenge
+ * @v peer Peer challenge
+ * @v response Challenge response to fill in
+ *
+ * This is essentially the GenerateNTResponse() function as documented
+ * in RFC 2759 section 8.1.
+ */
+void mschapv2_response ( const char *username, const char *password,
+ const struct mschapv2_challenge *challenge,
+ const struct mschapv2_challenge *peer,
+ struct mschapv2_response *response ) {
+ union mschapv2_context ctx;
+ union mschapv2_challenge_hash chash;
+ union mschapv2_password_hash phash;
+
+ /* Zero reserved fields */
+ memset ( response, 0, sizeof ( *response ) );
+
+ /* Copy peer challenge to response */
+ memcpy ( &response->peer, peer, sizeof ( response->peer ) );
+
+ /* Construct challenge hash */
+ mschapv2_challenge_hash ( &ctx, challenge, peer, username, &chash );
+
+ /* Construct expanded password hash */
+ mschapv2_password_hash ( &ctx, password, &phash );
+ mschapv2_expand_hash ( &ctx, &phash );
+
+ /* Construct NT response */
+ mschapv2_challenge_response ( &ctx, &chash, &phash, &response->nt );
+ DBGC ( &ctx, "MSCHAPv2 challenge response:\n" );
+ DBGC_HDA ( &ctx, 0, response, sizeof ( *response ) );
+}
+
+/**
+ * Calculate MS-CHAPv2 authenticator response
+ *
+ * @v username User name (or NULL to use empty string)
+ * @v password Password (or NULL to use empty string)
+ * @v challenge Authenticator challenge
+ * @v response Challenge response
+ * @v auth Authenticator response to fill in
+ *
+ * This is essentially the GenerateAuthenticatorResponse() function as
+ * documented in RFC 2759 section 8.7.
+ */
+void mschapv2_auth ( const char *username, const char *password,
+ const struct mschapv2_challenge *challenge,
+ const struct mschapv2_response *response,
+ struct mschapv2_auth *auth ) {
+ struct digest_algorithm *sha1 = &sha1_algorithm;
+ union mschapv2_context ctx;
+ union mschapv2_challenge_hash chash;
+ union mschapv2_password_hash phash;
+ char tmp[3];
+ char *wtf;
+ unsigned int i;
+
+ /* Construct hash of password hash */
+ mschapv2_password_hash ( &ctx, password, &phash );
+ mschapv2_hash_hash ( &ctx, &phash );
+
+ /* Construct unnamed intermediate hash */
+ digest_init ( sha1, ctx.sha1 );
+ digest_update ( sha1, ctx.sha1, phash.md4, sizeof ( phash.md4 ) );
+ digest_update ( sha1, ctx.sha1, &response->nt,
+ sizeof ( response->nt ) );
+ digest_update ( sha1, ctx.sha1, mschapv2_magic1,
+ sizeof ( mschapv2_magic1 ) );
+ digest_final ( sha1, ctx.sha1, phash.sha1 );
+ DBGC ( &ctx, "MSCHAPv2 NT response:\n" );
+ DBGC_HDA ( &ctx, 0, &response->nt, sizeof ( response->nt ) );
+ DBGC ( &ctx, "MSCHAPv2 unnamed intermediate hash:\n" );
+ DBGC_HDA ( &ctx, 0, phash.sha1, sizeof ( phash.sha1 ) );
+
+ /* Construct challenge hash */
+ mschapv2_challenge_hash ( &ctx, challenge, &response->peer,
+ username, &chash );
+
+ /* Construct authenticator response hash */
+ digest_init ( sha1, ctx.sha1 );
+ digest_update ( sha1, ctx.sha1, phash.sha1, sizeof ( phash.sha1 ) );
+ digest_update ( sha1, ctx.sha1, chash.des, sizeof ( chash.des ) );
+ digest_update ( sha1, ctx.sha1, mschapv2_magic2,
+ sizeof ( mschapv2_magic2 ) );
+ digest_final ( sha1, ctx.sha1, phash.sha1 );
+ DBGC ( &ctx, "MSCHAPv2 authenticator response hash:\n" );
+ DBGC_HDA ( &ctx, 0, phash.sha1, sizeof ( phash.sha1 ) );
+
+ /* Encode authenticator response hash */
+ wtf = auth->wtf;
+ *(wtf++) = 'S';
+ *(wtf++) = '=';
+ DBGC ( &ctx, "MSCHAPv2 authenticator response: S=" );
+ for ( i = 0 ; i < sizeof ( phash.sha1 ) ; i++ ) {
+ snprintf ( tmp, sizeof ( tmp ), "%02X", phash.sha1[i] );
+ *(wtf++) = tmp[0];
+ *(wtf++) = tmp[1];
+ DBGC ( &ctx, "%s", tmp );
+ }
+ DBGC ( &ctx, "\n" );
+}
diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c
index 94fce002..8eecc75b 100644
--- a/src/crypto/sha1.c
+++ b/src/crypto/sha1.c
@@ -145,12 +145,12 @@ static void sha1_digest ( struct sha1_context *context ) {
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
- linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout );
- linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout );
+ build_assert ( &u.ddd.dd.digest.h[0] == a );
+ build_assert ( &u.ddd.dd.digest.h[1] == b );
+ build_assert ( &u.ddd.dd.digest.h[2] == c );
+ build_assert ( &u.ddd.dd.digest.h[3] == d );
+ build_assert ( &u.ddd.dd.digest.h[4] == e );
+ build_assert ( &u.ddd.dd.data.dword[0] == w );
DBGC ( context, "SHA1 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index 6bd72771..c30300eb 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -140,15 +140,15 @@ static void sha256_digest ( struct sha256_context *context ) {
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
- linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout );
- linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout );
+ build_assert ( &u.ddd.dd.digest.h[0] == a );
+ build_assert ( &u.ddd.dd.digest.h[1] == b );
+ build_assert ( &u.ddd.dd.digest.h[2] == c );
+ build_assert ( &u.ddd.dd.digest.h[3] == d );
+ build_assert ( &u.ddd.dd.digest.h[4] == e );
+ build_assert ( &u.ddd.dd.digest.h[5] == f );
+ build_assert ( &u.ddd.dd.digest.h[6] == g );
+ build_assert ( &u.ddd.dd.digest.h[7] == h );
+ build_assert ( &u.ddd.dd.data.dword[0] == w );
DBGC ( context, "SHA256 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c
index e8489501..d7d44b28 100644
--- a/src/crypto/sha512.c
+++ b/src/crypto/sha512.c
@@ -156,15 +156,15 @@ static void sha512_digest ( struct sha512_context *context ) {
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 );
- linker_assert ( &u.ddq.dd.digest.h[0] == a, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.digest.h[1] == b, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.digest.h[2] == c, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.digest.h[3] == d, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.digest.h[4] == e, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.digest.h[5] == f, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.digest.h[6] == g, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.digest.h[7] == h, sha512_bad_layout );
- linker_assert ( &u.ddq.dd.data.qword[0] == w, sha512_bad_layout );
+ build_assert ( &u.ddq.dd.digest.h[0] == a );
+ build_assert ( &u.ddq.dd.digest.h[1] == b );
+ build_assert ( &u.ddq.dd.digest.h[2] == c );
+ build_assert ( &u.ddq.dd.digest.h[3] == d );
+ build_assert ( &u.ddq.dd.digest.h[4] == e );
+ build_assert ( &u.ddq.dd.digest.h[5] == f );
+ build_assert ( &u.ddq.dd.digest.h[6] == g );
+ build_assert ( &u.ddq.dd.digest.h[7] == h );
+ build_assert ( &u.ddq.dd.data.qword[0] == w );
DBGC ( context, "SHA512 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddq.dd.digest,
diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c
new file mode 100644
index 00000000..d58f7168
--- /dev/null
+++ b/src/crypto/x25519.c
@@ -0,0 +1,844 @@
+/*
+ * Copyright (C) 2024 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
+ *
+ * X25519 key exchange
+ *
+ * This implementation is inspired by and partially based upon the
+ * paper "Implementing Curve25519/X25519: A Tutorial on Elliptic Curve
+ * Cryptography" by Martin Kleppmann, available for download from
+ * https://www.cl.cam.ac.uk/teaching/2122/Crypto/curve25519.pdf
+ *
+ * The underlying modular addition, subtraction, and multiplication
+ * operations are completely redesigned for substantially improved
+ * efficiency compared to the TweetNaCl implementation studied in that
+ * paper.
+ *
+ * TweetNaCl iPXE
+ * --------- ----
+ *
+ * Storage size of each big integer 128 40
+ * (in bytes)
+ *
+ * Stack usage for key exchange 1144 360
+ * (in bytes, large objects only)
+ *
+ * Cost of big integer addition 16 5
+ * (in number of 64-bit additions)
+ *
+ * Cost of big integer multiplication 273 31
+ * (in number of 64-bit multiplications)
+ *
+ * The implementation is constant-time (provided that the underlying
+ * big integer operations are also constant-time).
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <ipxe/init.h>
+#include <ipxe/crypto.h>
+#include <ipxe/x25519.h>
+
+/** X25519 reduction constant
+ *
+ * The X25519 field prime is p=2^255-19. This gives us:
+ *
+ * p = 2^255 - 19
+ * 2^255 = p + 19
+ * 2^255 = 19 (mod p)
+ * k * 2^255 = k * 19 (mod p)
+ *
+ * We can therefore reduce a value modulo p by taking the high-order
+ * bits of the value from bit 255 and above, multiplying by 19, and
+ * adding this to the low-order 255 bits of the value.
+ *
+ * This would be cumbersome to do in practice since it would require
+ * partitioning the value at a 255-bit boundary (and hence would
+ * require some shifting and masking operations). However, we can
+ * note that:
+ *
+ * k * 2^255 = k * 19 (mod p)
+ * k * 2 * 2^255 = k * 2 * 19 (mod p)
+ * k * 2^256 = k * 38 (mod p)
+ *
+ * We can therefore simplify the reduction to taking the high order
+ * bits of the value from bit 256 and above, multiplying by 38, and
+ * adding this to the low-order 256 bits of the value.
+ *
+ * Since 256 will inevitably be a multiple of the big integer element
+ * size (typically 32 or 64 bits), this avoids the need to perform any
+ * shifting or masking operations.
+ */
+#define X25519_REDUCE_256 38
+
+/** X25519 multiplication step 1 result
+ *
+ * Step 1 of X25519 multiplication is to compute the product of two
+ * X25519 unsigned 258-bit integers.
+ *
+ * Both multiplication inputs are limited to 258 bits, and so the
+ * product will have at most 516 bits.
+ */
+union x25519_multiply_step1 {
+ /** Raw product
+ *
+ * Big integer multiplication produces a result with a number
+ * of elements equal to the sum of the number of elements in
+ * each input.
+ */
+ bigint_t ( X25519_SIZE + X25519_SIZE ) product;
+ /** Partition into low-order and high-order bits
+ *
+ * Reduction modulo p requires separating the low-order 256
+ * bits from the remaining high-order bits.
+ *
+ * Since the value will never exceed 516 bits (see above),
+ * there will be at most 260 high-order bits.
+ */
+ struct {
+ /** Low-order 256 bits */
+ bigint_t ( bigint_required_size ( ( 256 /* bits */ + 7 ) / 8 ) )
+ low_256bit;
+ /** High-order 260 bits */
+ bigint_t ( bigint_required_size ( ( 260 /* bits */ + 7 ) / 8 ) )
+ high_260bit;
+ } __attribute__ (( packed )) parts;
+};
+
+/** X25519 multiplication step 2 result
+ *
+ * Step 2 of X25519 multiplication is to multiply the high-order 260
+ * bits from step 1 with the 6-bit reduction constant 38, and to add
+ * this to the low-order 256 bits from step 1.
+ *
+ * The multiplication inputs are limited to 260 and 6 bits
+ * respectively, and so the product will have at most 266 bits. After
+ * adding the low-order 256 bits from step 1, the result will have at
+ * most 267 bits.
+ */
+union x25519_multiply_step2 {
+ /** Raw product
+ *
+ * Big integer multiplication produces a result with a number
+ * of elements equal to the sum of the number of elements in
+ * each input.
+ */
+ bigint_t ( bigint_required_size ( ( 260 /* bits */ + 7 ) / 8 ) +
+ bigint_required_size ( ( 6 /* bits */ + 7 ) / 8 ) ) product;
+ /** Big integer value
+ *
+ * The value will never exceed 267 bits (see above), and so
+ * may be consumed as a normal X25519 big integer.
+ */
+ x25519_t value;
+ /** Partition into low-order and high-order bits
+ *
+ * Reduction modulo p requires separating the low-order 256
+ * bits from the remaining high-order bits.
+ *
+ * Since the value will never exceed 267 bits (see above),
+ * there will be at most 11 high-order bits.
+ */
+ struct {
+ /** Low-order 256 bits */
+ bigint_t ( bigint_required_size ( ( 256 /* bits */ + 7 ) / 8 ) )
+ low_256bit;
+ /** High-order 11 bits */
+ bigint_t ( bigint_required_size ( ( 11 /* bits */ + 7 ) / 8 ) )
+ high_11bit;
+ } __attribute__ (( packed )) parts;
+};
+
+/** X25519 multiplication step 3 result
+ *
+ * Step 3 of X25519 multiplication is to multiply the high-order 11
+ * bits from step 2 with the 6-bit reduction constant 38, and to add
+ * this to the low-order 256 bits from step 2.
+ *
+ * The multiplication inputs are limited to 11 and 6 bits
+ * respectively, and so the product will have at most 17 bits. After
+ * adding the low-order 256 bits from step 2, the result will have at
+ * most 257 bits.
+ */
+union x25519_multiply_step3 {
+ /** Raw product
+ *
+ * Big integer multiplication produces a result with a number
+ * of elements equal to the sum of the number of elements in
+ * each input.
+ */
+ bigint_t ( bigint_required_size ( ( 11 /* bits */ + 7 ) / 8 ) +
+ bigint_required_size ( ( 6 /* bits */ + 7 ) / 8 ) ) product;
+ /** Big integer value
+ *
+ * The value will never exceed 267 bits (see above), and so
+ * may be consumed as a normal X25519 big integer.
+ */
+ x25519_t value;
+};
+
+/** X25519 multiplication temporary working space
+ *
+ * We overlap the buffers used by each step of the multiplication
+ * calculation to reduce the total stack space required:
+ *
+ * |--------------------------------------------------------|
+ * | <- pad -> | <------------ step 1 result -------------> |
+ * | | <- low 256 bits -> | <-- high 260 bits --> |
+ * | <------- step 2 result ------> | <-- step 3 result --> |
+ * |--------------------------------------------------------|
+ */
+union x25519_multiply_workspace {
+ /** Step 1 result */
+ struct {
+ /** Padding to avoid collision between steps 1 and 2
+ *
+ * The step 2 multiplication consumes the high 260
+ * bits of step 1, and so the step 2 multiplication
+ * result must not overlap this portion of the step 1
+ * result.
+ */
+ uint8_t pad[ sizeof ( union x25519_multiply_step2 ) -
+ offsetof ( union x25519_multiply_step1,
+ parts.high_260bit ) ];
+ /** Step 1 result */
+ union x25519_multiply_step1 step1;
+ } __attribute__ (( packed ));
+ /** Steps 2 and 3 results */
+ struct {
+ /** Step 2 result */
+ union x25519_multiply_step2 step2;
+ /** Step 3 result */
+ union x25519_multiply_step3 step3;
+ } __attribute__ (( packed ));
+};
+
+/** An X25519 elliptic curve point in projective coordinates
+ *
+ * A point (x,y) on the Montgomery curve used in X25519 is represented
+ * using projective coordinates (X/Z,Y/Z) so that intermediate
+ * calculations may be performed on both numerator and denominator
+ * separately, with the division step performed only once at the end
+ * of the calculation.
+ *
+ * The group operation calculation is performed using a Montgomery
+ * ladder as:
+ *
+ * X[2i] = ( X[i]^2 - Z[i]^2 )^2
+ * X[2i+1] = ( X[i] * X[i+1] - Z[i] * Z[i+1] )^2
+ * Z[2i] = 4 * X[i] * Z[i] * ( X[i]^2 + A * X[i] * Z[i] + Z[i]^2 )
+ * Z[2i+1] = X[0] * ( X[i] * Z[i+1] - X[i+1] * Z[i] ) ^ 2
+ *
+ * It is therefore not necessary to store (or use) the value of Y.
+ */
+struct x25519_projective {
+ /** X coordinate */
+ union x25519_quad257 X;
+ /** Z coordinate */
+ union x25519_quad257 Z;
+};
+
+/** An X25519 Montgomery ladder step */
+struct x25519_step {
+ /** X[n]/Z[n] */
+ struct x25519_projective x_n;
+ /** X[n+1]/Z[n+1] */
+ struct x25519_projective x_n1;
+};
+
+/** Constant p=2^255-19 (the finite field prime) */
+static const uint8_t x25519_p_raw[] = {
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed
+};
+
+/** Constant p=2^255-19 (the finite field prime) */
+static x25519_t x25519_p;
+
+/** Constant 2p=2^256-38 */
+static x25519_t x25519_2p;
+
+/** Constant 4p=2^257-76 */
+static x25519_t x25519_4p;
+
+/** Reduction constant (used during multiplication) */
+static const uint8_t x25519_reduce_256_raw[] = { X25519_REDUCE_256 };
+
+/** Reduction constant (used during multiplication) */
+static bigint_t ( bigint_required_size ( sizeof ( x25519_reduce_256_raw ) ) )
+ x25519_reduce_256;
+
+/** Constant 121665 (used in the Montgomery ladder) */
+static const uint8_t x25519_121665_raw[] = { 0x01, 0xdb, 0x41 };
+
+/** Constant 121665 (used in the Montgomery ladder) */
+static union x25519_oct258 x25519_121665;
+
+/** Constant g=9 (the group generator) */
+static struct x25519_value x25519_generator = {
+ .raw = { 9, }
+};
+
+/**
+ * Initialise constants
+ *
+ */
+static void x25519_init_constants ( void ) {
+
+ /* Construct constant p */
+ bigint_init ( &x25519_p, x25519_p_raw, sizeof ( x25519_p_raw ) );
+
+ /* Construct constant 2p */
+ bigint_copy ( &x25519_p, &x25519_2p );
+ bigint_add ( &x25519_p, &x25519_2p );
+
+ /* Construct constant 4p */
+ bigint_copy ( &x25519_2p, &x25519_4p );
+ bigint_add ( &x25519_2p, &x25519_4p );
+
+ /* Construct reduction constant */
+ bigint_init ( &x25519_reduce_256, x25519_reduce_256_raw,
+ sizeof ( x25519_reduce_256_raw ) );
+
+ /* Construct constant 121665 */
+ bigint_init ( &x25519_121665.value, x25519_121665_raw,
+ sizeof ( x25519_121665_raw ) );
+}
+
+/** Initialisation function */
+struct init_fn x25519_init_fn __init_fn ( INIT_NORMAL ) = {
+ .initialise = x25519_init_constants,
+};
+
+/**
+ * Add big integers modulo field prime
+ *
+ * @v augend Big integer to add
+ * @v addend Big integer to add
+ * @v result Big integer to hold result (may overlap augend)
+ */
+static inline __attribute__ (( always_inline )) void
+x25519_add ( const union x25519_quad257 *augend,
+ const union x25519_quad257 *addend,
+ union x25519_oct258 *result ) {
+ int copy;
+
+ /* Copy augend if necessary */
+ copy = ( result != &augend->oct258 );
+ build_assert ( __builtin_constant_p ( copy ) );
+ if ( copy ) {
+ build_assert ( result != &addend->oct258 );
+ bigint_copy ( &augend->oct258.value, &result->value );
+ }
+
+ /* Perform addition
+ *
+ * Both inputs are in the range [0,4p-1] and the resulting
+ * sum is therefore in the range [0,8p-2].
+ *
+ * This range lies within the range [0,8p-1] and the result is
+ * therefore a valid X25519 unsigned 258-bit integer, as
+ * required.
+ */
+ bigint_add ( &addend->value, &result->value );
+}
+
+/**
+ * Subtract big integers modulo field prime
+ *
+ * @v minuend Big integer from which to subtract
+ * @v subtrahend Big integer to subtract
+ * @v result Big integer to hold result (may overlap minuend)
+ */
+static inline __attribute__ (( always_inline )) void
+x25519_subtract ( const union x25519_quad257 *minuend,
+ const union x25519_quad257 *subtrahend,
+ union x25519_oct258 *result ) {
+ int copy;
+
+ /* Copy minuend if necessary */
+ copy = ( result != &minuend->oct258 );
+ build_assert ( __builtin_constant_p ( copy ) );
+ if ( copy ) {
+ build_assert ( result != &subtrahend->oct258 );
+ bigint_copy ( &minuend->oct258.value, &result->value );
+ }
+
+ /* Perform subtraction
+ *
+ * Both inputs are in the range [0,4p-1] and the resulting
+ * difference is therefore in the range [1-4p,4p-1].
+ *
+ * This range lies partially outside the range [0,8p-1] and
+ * the result is therefore not yet a valid X25519 unsigned
+ * 258-bit integer.
+ */
+ bigint_subtract ( &subtrahend->value, &result->value );
+
+ /* Add constant multiple of field prime p
+ *
+ * Add the constant 4p to the result. This brings the result
+ * within the range [1,8p-1] (without changing the value
+ * modulo p).
+ *
+ * This range lies within the range [0,8p-1] and the result is
+ * therefore now a valid X25519 unsigned 258-bit integer, as
+ * required.
+ */
+ bigint_add ( &x25519_4p, &result->value );
+}
+
+/**
+ * Multiply big integers modulo field prime
+ *
+ * @v multiplicand Big integer to be multiplied
+ * @v multiplier Big integer to be multiplied
+ * @v result Big integer to hold result (may overlap either input)
+ */
+void x25519_multiply ( const union x25519_oct258 *multiplicand,
+ const union x25519_oct258 *multiplier,
+ union x25519_quad257 *result ) {
+ union x25519_multiply_workspace tmp;
+ union x25519_multiply_step1 *step1 = &tmp.step1;
+ union x25519_multiply_step2 *step2 = &tmp.step2;
+ union x25519_multiply_step3 *step3 = &tmp.step3;
+
+ /* Step 1: perform raw multiplication
+ *
+ * step1 = multiplicand * multiplier
+ *
+ * Both inputs are 258-bit numbers and the step 1 result is
+ * therefore 258+258=516 bits.
+ */
+ static_assert ( sizeof ( step1->product ) >= sizeof ( step1->parts ) );
+ bigint_multiply ( &multiplicand->value, &multiplier->value,
+ &step1->product );
+
+ /* Step 2: reduce high-order 516-256=260 bits of step 1 result
+ *
+ * Use the identity 2^256=38 (mod p) to reduce the high-order
+ * bits of the step 1 result. We split the 516-bit result
+ * from step 1 into its low-order 256 bits and high-order 260
+ * bits:
+ *
+ * step1 = step1(low 256 bits) + step1(high 260 bits) * 2^256
+ *
+ * and then perform the calculation:
+ *
+ * step2 = step1 (mod p)
+ * = step1(low 256 bits) + step1(high 260 bits) * 2^256 (mod p)
+ * = step1(low 256 bits) + step1(high 260 bits) * 38 (mod p)
+ *
+ * There are 6 bits in the constant value 38. The step 2
+ * multiplication product will therefore have 260+6=266 bits,
+ * and the step 2 result (after the addition) will therefore
+ * have 267 bits.
+ */
+ static_assert ( sizeof ( step2->product ) >= sizeof ( step2->value ) );
+ static_assert ( sizeof ( step2->product ) >= sizeof ( step2->parts ) );
+ bigint_grow ( &step1->parts.low_256bit, &result->value );
+ bigint_multiply ( &step1->parts.high_260bit, &x25519_reduce_256,
+ &step2->product );
+ bigint_add ( &result->value, &step2->value );
+
+ /* Step 3: reduce high-order 267-256=11 bits of step 2 result
+ *
+ * Use the identity 2^256=38 (mod p) again to reduce the
+ * high-order bits of the step 2 result. As before, we split
+ * the 267-bit result from step 2 into its low-order 256 bits
+ * and high-order 11 bits:
+ *
+ * step2 = step2(low 256 bits) + step2(high 11 bits) * 2^256
+ *
+ * and then perform the calculation:
+ *
+ * step3 = step2 (mod p)
+ * = step2(low 256 bits) + step2(high 11 bits) * 2^256 (mod p)
+ * = step2(low 256 bits) + step2(high 11 bits) * 38 (mod p)
+ *
+ * There are 6 bits in the constant value 38. The step 3
+ * multiplication product will therefore have 11+6=19 bits,
+ * and the step 3 result (after the addition) will therefore
+ * have 257 bits.
+ *
+ * A loose upper bound for the step 3 result (after the
+ * addition) is given by:
+ *
+ * step3 < ( 2^256 - 1 ) + ( 2^19 - 1 )
+ * < ( 2^257 - 2^256 - 1 ) + ( 2^19 - 1 )
+ * < ( 2^257 - 76 ) - 2^256 + 2^19 + 74
+ * < 4 * ( 2^255 - 19 ) - 2^256 + 2^19 + 74
+ * < 4p - 2^256 + 2^19 + 74
+ *
+ * and so the step 3 result is strictly less than 4p, and
+ * therefore lies within the range [0,4p-1].
+ */
+ memset ( &step3->value, 0, sizeof ( step3->value ) );
+ bigint_grow ( &step2->parts.low_256bit, &result->value );
+ bigint_multiply ( &step2->parts.high_11bit, &x25519_reduce_256,
+ &step3->product );
+ bigint_add ( &step3->value, &result->value );
+
+ /* Step 1 calculates the product of the input operands, and
+ * each subsequent step reduces the number of bits in the
+ * result while preserving this value (modulo p). The final
+ * result is therefore equal to the product of the input
+ * operands (modulo p), as required.
+ *
+ * The step 3 result lies within the range [0,4p-1] and the
+ * final result is therefore a valid X25519 unsigned 257-bit
+ * integer, as required.
+ */
+}
+
+/**
+ * Compute multiplicative inverse
+ *
+ * @v invertend Big integer to be inverted
+ * @v result Big integer to hold result (may not overlap input)
+ */
+void x25519_invert ( const union x25519_oct258 *invertend,
+ union x25519_quad257 *result ) {
+ int i;
+
+ /* Sanity check */
+ assert ( invertend != &result->oct258 );
+
+ /* Calculate inverse as x^(-1)=x^(p-2) where p is the field prime
+ *
+ * The field prime is p=2^255-19 and so:
+ *
+ * p - 2 = 2^255 - 21
+ * = (2^255 - 1) - 2^4 - 2^2
+ *
+ * i.e. p-2 is a 254-bit number in which all bits are set
+ * apart from bit 2 and bit 4.
+ *
+ * We use the square-and-multiply method to compute x^(p-2).
+ */
+ bigint_copy ( &invertend->value, &result->value );
+ for ( i = 253 ; i >= 0 ; i-- ) {
+
+ /* Square running total */
+ x25519_multiply ( &result->oct258, &result->oct258, result );
+
+ /* For each set bit in the exponent, multiply by invertend */
+ if ( ( i != 2 ) && ( i != 4 ) ) {
+ x25519_multiply ( invertend, &result->oct258, result );
+ }
+ }
+}
+
+/**
+ * Reduce big integer via conditional subtraction
+ *
+ * @v subtrahend Big integer to subtract
+ * @v value Big integer to be subtracted from, if possible
+ */
+static void x25519_reduce_by ( const x25519_t *subtrahend, x25519_t *value ) {
+ unsigned int max_bit = ( ( 8 * sizeof ( *value ) ) - 1 );
+ x25519_t tmp;
+
+ /* Conditionally subtract subtrahend
+ *
+ * Subtract the subtrahend, discarding the result (in constant
+ * time) if the subtraction underflows.
+ */
+ bigint_copy ( value, &tmp );
+ bigint_subtract ( subtrahend, value );
+ bigint_swap ( value, &tmp, bigint_bit_is_set ( value, max_bit ) );
+}
+
+/**
+ * Reduce big integer to canonical range
+ *
+ * @v value Big integer to be reduced
+ */
+void x25519_reduce ( union x25519_quad257 *value ) {
+
+ /* Conditionally subtract 2p
+ *
+ * Subtract twice the field prime, discarding the result (in
+ * constant time) if the subtraction underflows.
+ *
+ * The input value is in the range [0,4p-1]. After this
+ * conditional subtraction, the value is in the range
+ * [0,2p-1].
+ */
+ x25519_reduce_by ( &x25519_2p, &value->value );
+
+ /* Conditionally subtract p
+ *
+ * Subtract the field prime, discarding the result (in
+ * constant time) if the subtraction underflows.
+ *
+ * The value is already in the range [0,2p-1]. After this
+ * conditional subtraction, the value is in the range [0,p-1]
+ * and is therefore the canonical representation.
+ */
+ x25519_reduce_by ( &x25519_p, &value->value );
+}
+
+/**
+ * Compute next step of the Montgomery ladder
+ *
+ * @v base Base point
+ * @v bit Bit value
+ * @v step Ladder step
+ */
+static void x25519_step ( const union x25519_quad257 *base, int bit,
+ struct x25519_step *step ) {
+ union x25519_quad257 *a = &step->x_n.X;
+ union x25519_quad257 *b = &step->x_n1.X;
+ union x25519_quad257 *c = &step->x_n.Z;
+ union x25519_quad257 *d = &step->x_n1.Z;
+ union x25519_oct258 e;
+ union x25519_quad257 f;
+ union x25519_oct258 *v1_e;
+ union x25519_oct258 *v2_a;
+ union x25519_oct258 *v3_c;
+ union x25519_oct258 *v4_b;
+ union x25519_quad257 *v5_d;
+ union x25519_quad257 *v6_f;
+ union x25519_quad257 *v7_a;
+ union x25519_quad257 *v8_c;
+ union x25519_oct258 *v9_e;
+ union x25519_oct258 *v10_a;
+ union x25519_quad257 *v11_b;
+ union x25519_oct258 *v12_c;
+ union x25519_quad257 *v13_a;
+ union x25519_oct258 *v14_a;
+ union x25519_quad257 *v15_c;
+ union x25519_quad257 *v16_a;
+ union x25519_quad257 *v17_d;
+ union x25519_quad257 *v18_b;
+
+ /* See the referenced paper "Implementing Curve25519/X25519: A
+ * Tutorial on Elliptic Curve Cryptography" for the reasoning
+ * behind this calculation.
+ */
+
+ /* Reuse storage locations for intermediate results where possible */
+ v1_e = &e;
+ v2_a = container_of ( &a->value, union x25519_oct258, value );
+ v3_c = container_of ( &c->value, union x25519_oct258, value );
+ v4_b = container_of ( &b->value, union x25519_oct258, value );
+ v5_d = d;
+ v6_f = &f;
+ v7_a = a;
+ v8_c = c;
+ v9_e = &e;
+ v10_a = container_of ( &a->value, union x25519_oct258, value );
+ v11_b = b;
+ v12_c = container_of ( &c->value, union x25519_oct258, value );
+ v13_a = a;
+ v14_a = container_of ( &a->value, union x25519_oct258, value );
+ v15_c = c;
+ v16_a = a;
+ v17_d = d;
+ v18_b = b;
+
+ /* Select inputs */
+ bigint_swap ( &a->value, &b->value, bit );
+ bigint_swap ( &c->value, &d->value, bit );
+
+ /* v1 = a + c */
+ x25519_add ( a, c, v1_e );
+
+ /* v2 = a - c */
+ x25519_subtract ( a, c, v2_a );
+
+ /* v3 = b + d */
+ x25519_add ( b, d, v3_c );
+
+ /* v4 = b - d */
+ x25519_subtract ( b, d, v4_b );
+
+ /* v5 = v1^2 = (a + c)^2 = a^2 + 2ac + c^2 */
+ x25519_multiply ( v1_e, v1_e, v5_d );
+
+ /* v6 = v2^2 = (a - c)^2 = a^2 - 2ac + c^2 */
+ x25519_multiply ( v2_a, v2_a, v6_f );
+
+ /* v7 = v3 * v2 = (b + d) * (a - c) = ab - bc + ad - cd */
+ x25519_multiply ( v3_c, v2_a, v7_a );
+
+ /* v8 = v4 * v1 = (b - d) * (a + c) = ab + bc - ad - cd */
+ x25519_multiply ( v4_b, v1_e, v8_c );
+
+ /* v9 = v7 + v8 = 2 * (ab - cd) */
+ x25519_add ( v7_a, v8_c, v9_e );
+
+ /* v10 = v7 - v8 = 2 * (ad - bc) */
+ x25519_subtract ( v7_a, v8_c, v10_a );
+
+ /* v11 = v10^2 = 4 * (ad - bc)^2 */
+ x25519_multiply ( v10_a, v10_a, v11_b );
+
+ /* v12 = v5 - v6 = (a + c)^2 - (a - c)^2 = 4ac */
+ x25519_subtract ( v5_d, v6_f, v12_c );
+
+ /* v13 = v12 * 121665 = 486660ac = (A-2) * ac */
+ x25519_multiply ( v12_c, &x25519_121665, v13_a );
+
+ /* v14 = v13 + v5 = (A-2) * ac + a^2 + 2ac + c^2 = a^2 + A * ac + c^2 */
+ x25519_add ( v13_a, v5_d, v14_a );
+
+ /* v15 = v12 * v14 = 4ac * (a^2 + A * ac + c^2) */
+ x25519_multiply ( v12_c, v14_a, v15_c );
+
+ /* v16 = v5 * v6 = (a + c)^2 * (a - c)^2 = (a^2 - c^2)^2 */
+ x25519_multiply ( &v5_d->oct258, &v6_f->oct258, v16_a );
+
+ /* v17 = v11 * base = 4 * base * (ad - bc)^2 */
+ x25519_multiply ( &v11_b->oct258, &base->oct258, v17_d );
+
+ /* v18 = v9^2 = 4 * (ab - cd)^2 */
+ x25519_multiply ( v9_e, v9_e, v18_b );
+
+ /* Select outputs */
+ bigint_swap ( &a->value, &b->value, bit );
+ bigint_swap ( &c->value, &d->value, bit );
+}
+
+/**
+ * Multiply X25519 elliptic curve point
+ *
+ * @v base Base point
+ * @v scalar Scalar multiple
+ * @v result Point to hold result (may overlap base point)
+ */
+static void x25519_ladder ( const union x25519_quad257 *base,
+ struct x25519_value *scalar,
+ union x25519_quad257 *result ) {
+ static const uint8_t zero[] = { 0 };
+ static const uint8_t one[] = { 1 };
+ struct x25519_step step;
+ union x25519_quad257 *tmp;
+ int bit;
+ int i;
+
+ /* Initialise ladder */
+ bigint_init ( &step.x_n.X.value, one, sizeof ( one ) );
+ bigint_init ( &step.x_n.Z.value, zero, sizeof ( zero ) );
+ bigint_copy ( &base->value, &step.x_n1.X.value );
+ bigint_init ( &step.x_n1.Z.value, one, sizeof ( one ) );
+
+ /* Use ladder */
+ for ( i = 254 ; i >= 0 ; i-- ) {
+ bit = ( ( scalar->raw[ i / 8 ] >> ( i % 8 ) ) & 1 );
+ x25519_step ( base, bit, &step );
+ }
+
+ /* Convert back to affine coordinate */
+ tmp = &step.x_n1.X;
+ x25519_invert ( &step.x_n.Z.oct258, tmp );
+ x25519_multiply ( &step.x_n.X.oct258, &tmp->oct258, result );
+ x25519_reduce ( result );
+}
+
+/**
+ * Reverse X25519 value endianness
+ *
+ * @v value Value to reverse
+ */
+static void x25519_reverse ( struct x25519_value *value ) {
+ uint8_t *low = value->raw;
+ uint8_t *high = &value->raw[ sizeof ( value->raw ) - 1 ];
+ uint8_t tmp;
+
+ /* Reverse bytes */
+ do {
+ tmp = *low;
+ *low = *high;
+ *high = tmp;
+ } while ( ++low < --high );
+}
+
+/**
+ * Calculate X25519 key
+ *
+ * @v base Base point
+ * @v scalar Scalar multiple
+ * @v result Point to hold result (may overlap base point)
+ * @ret rc Return status code
+ */
+int x25519_key ( const struct x25519_value *base,
+ const struct x25519_value *scalar,
+ struct x25519_value *result ) {
+ struct x25519_value *tmp = result;
+ union x25519_quad257 point;
+
+ /* Reverse base point and clear high bit as required by RFC7748 */
+ memcpy ( tmp, base, sizeof ( *tmp ) );
+ x25519_reverse ( tmp );
+ tmp->raw[0] &= 0x7f;
+ bigint_init ( &point.value, tmp->raw, sizeof ( tmp->raw ) );
+
+ /* Clamp scalar as required by RFC7748 */
+ memcpy ( tmp, scalar, sizeof ( *tmp ) );
+ tmp->raw[0] &= 0xf8;
+ tmp->raw[31] |= 0x40;
+
+ /* Multiply elliptic curve point */
+ x25519_ladder ( &point, tmp, &point );
+
+ /* Reverse result */
+ bigint_done ( &point.value, result->raw, sizeof ( result->raw ) );
+ x25519_reverse ( result );
+
+ /* Fail if result was all zeros (as required by RFC8422) */
+ return ( bigint_is_zero ( &point.value ) ? -EPERM : 0 );
+}
+
+/**
+ * Multiply scalar by curve point
+ *
+ * @v base Base point (or NULL to use generator)
+ * @v scalar Scalar multiple
+ * @v result Result point to fill in
+ * @ret rc Return status code
+ */
+static int x25519_curve_multiply ( const void *base, const void *scalar,
+ void *result ) {
+
+ /* Use base point if applicable */
+ if ( ! base )
+ base = &x25519_generator;
+
+ return x25519_key ( base, scalar, result );
+}
+
+/** X25519 elliptic curve */
+struct elliptic_curve x25519_curve = {
+ .name = "x25519",
+ .keysize = sizeof ( struct x25519_value ),
+ .multiply = x25519_curve_multiply,
+};
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
index 1f017eb0..92318093 100644
--- a/src/crypto/x509.c
+++ b/src/crypto/x509.c
@@ -1603,19 +1603,12 @@ int x509_check_name ( struct x509_certificate *cert, const char *name ) {
static void x509_free_chain ( struct refcnt *refcnt ) {
struct x509_chain *chain =
container_of ( refcnt, struct x509_chain, refcnt );
- struct x509_link *link;
- struct x509_link *tmp;
DBGC2 ( chain, "X509 chain %p freed\n", chain );
- /* Free each link in the chain */
- list_for_each_entry_safe ( link, tmp, &chain->links, list ) {
- x509_put ( link->cert );
- list_del ( &link->list );
- free ( link );
- }
-
/* Free chain */
+ x509_truncate ( chain, NULL );
+ assert ( list_empty ( &chain->links ) );
free ( chain );
}
@@ -1697,6 +1690,27 @@ int x509_append_raw ( struct x509_chain *chain, const void *data,
}
/**
+ * Truncate X.509 certificate chain
+ *
+ * @v chain X.509 certificate chain
+ * @v link Link after which to truncate chain, or NULL
+ */
+void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) {
+ struct x509_link *tmp;
+
+ /* Truncate entire chain if no link is specified */
+ if ( ! link )
+ link = list_entry ( &chain->links, struct x509_link, list );
+
+ /* Free each link in the chain */
+ list_for_each_entry_safe_continue ( link, tmp, &chain->links, list ) {
+ x509_put ( link->cert );
+ list_del ( &link->list );
+ free ( link );
+ }
+}
+
+/**
* Identify X.509 certificate by subject
*
* @v certs X.509 certificate list