[crypto] Use private data field for key exchange algorithms

For historical reasons, TLS versions 1.2 and earlier identify FFDHE
groups by specifying the raw group prime and generator (the "dh_p" and
"dh_g" fields in ServerDHParams), rather than using a numeric code to
identify a named group.

This adds complexity to the process of identifying the internal key
exchange algorithm.  One option would be to extend the definition of
struct tls_key_exchange_algorithm to include the identifying values
for the field prime and generator, but this is undesirable since the
field prime values may be large, and these values are already
available (indirectly) in ffdhe.c.

Extend our definition of a key exchange algorithm to include an opaque
private data field.  This allows us to remove the wrapper functions
currently created by FFDHE_GROUP() and WEIERSTRASS_CURVE(), and opens
up the option of accessing the existing FFDHE field prime and
generator values from within the TLS layer.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/crypto/ffdhe.c b/src/crypto/ffdhe.c
index d6f9449..004170d 100644
--- a/src/crypto/ffdhe.c
+++ b/src/crypto/ffdhe.c
@@ -194,8 +194,8 @@
  * @v shared		Shared result to fill in
  * @ret rc		Return status code
  */
-int ffdhe ( struct ffdhe_group *group, const void *public, const void *private,
-	    void *shared ) {
+static int ffdhe ( struct ffdhe_group *group, const void *public,
+		   const void *private, void *shared ) {
 	unsigned int expsize = group->expsize;
 	unsigned int size = group->size;
 	size_t explen = group->explen;
@@ -253,6 +253,36 @@
 	return 0;
 }
 
+/**
+ * Calculate public key
+ *
+ * @v exchange		Key exchange algorithm
+ * @v private		Private key
+ * @v public		Public key to fill in
+ */
+void ffdhe_public ( struct exchange_algorithm *exchange, const void *private,
+		    void *public ) {
+	struct ffdhe_group *group = exchange->priv;
+
+	ffdhe ( group, NULL, private, public );
+}
+
+/**
+ * Calculate shared secret
+ *
+ * @v exchange		Key exchange algorithm
+ * @v private		Private key
+ * @v partner		Partner public key
+ * @v shared		Shared secret to fill in
+ * @ret rc		Return status code
+ */
+int ffdhe_shared ( struct exchange_algorithm *exchange, const void *private,
+		   const void *partner, void *shared ) {
+	struct ffdhe_group *group = exchange->priv;
+
+	return ffdhe ( group, partner, private, shared );
+}
+
 /* Supported groups */
 FFDHE_GROUP ( ffdhe2048, ffdhe2048_algorithm, euler, 2048, 225, 0x61285c97 );
 FFDHE_GROUP ( ffdhe3072, ffdhe3072_algorithm, euler, 3072, 275, 0x66c62e37 );
diff --git a/src/crypto/weierstrass.c b/src/crypto/weierstrass.c
index ab2df24..7fa18ca 100644
--- a/src/crypto/weierstrass.c
+++ b/src/crypto/weierstrass.c
@@ -1030,12 +1030,13 @@
 /**
  * Calculate public key
  *
- * @v curve		Weierstrass curve
+ * @v exchange		Key exchange algorithm
  * @v private		Private key
  * @v public		Public key to fill in
  */
-void weierstrass_public ( struct weierstrass_curve *curve, const void *private,
-			  void *public ) {
+void weierstrass_public ( struct exchange_algorithm *exchange,
+			  const void *private, void *public ) {
+	struct weierstrass_curve *curve = exchange->priv;
 	size_t len = curve->len;
 	weierstrass_uncompressed_t ( len ) *uncompressed = public;
 	int rc;
@@ -1052,14 +1053,16 @@
 /**
  * Calculate shared secret
  *
- * @v curve		Weierstrass curve
+ * @v exchange		Key exchange algorithm
  * @v private		Private key
  * @v partner		Partner public key
  * @v shared		Shared secret to fill in
  * @ret rc		Return status code
  */
-int weierstrass_shared ( struct weierstrass_curve *curve, const void *private,
-			 const void *partner, void *shared ) {
+int weierstrass_shared ( struct exchange_algorithm *exchange,
+			 const void *private, const void *partner,
+			 void *shared ) {
+	struct weierstrass_curve *curve = exchange->priv;
 	size_t len = curve->len;
 	const weierstrass_uncompressed_t ( len ) *uncompressed = partner;
 	weierstrass_raw_t ( len ) point;
diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c
index 58382bc..5eb74b6 100644
--- a/src/crypto/x25519.c
+++ b/src/crypto/x25519.c
@@ -833,10 +833,12 @@
 /**
  * Calculate public key
  *
+ * @v exchange		Key exchange algorithm
  * @v private		Private key
  * @v public		Public key to fill in
  */
-static void x25519_public ( const void *private, void *public ) {
+static void x25519_public ( struct exchange_algorithm *exchange __unused,
+			    const void *private, void *public ) {
 
 	/* Calculate public key */
 	x25519_key ( &x25519_generator, private, public );
@@ -845,12 +847,14 @@
 /**
  * Calculate shared secret
  *
+ * @v exchange		Key exchange algorithm
  * @v private		Private key
  * @v partner		Partner public key
  * @v shared		Shared secret to fill in
  * @ret rc		Return status code
  */
-static int x25519_shared ( const void *private, const void *partner,
+static int x25519_shared ( struct exchange_algorithm *exchange __unused,
+			   const void *private, const void *partner,
 			   void *shared ) {
 
 	/* Calculate shared secret */
diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h
index ad08553..e512ae0 100644
--- a/src/include/ipxe/crypto.h
+++ b/src/include/ipxe/crypto.h
@@ -187,20 +187,26 @@
 	/**
 	 * Calculate public key
 	 *
+	 * @v exchange		Key exchange algorithm
 	 * @v private		Private key
 	 * @v public		Public key to fill in
 	 */
-	void ( * public ) ( const void *private, void *public );
+	void ( * public ) ( struct exchange_algorithm *exchange,
+			    const void *private, void *public );
 	/**
 	 * Calculate shared secret
 	 *
+	 * @v exchange		Key exchange algorithm
 	 * @v private		Private key
 	 * @v partner		Partner public key
 	 * @v shared		Shared secret to fill in
 	 * @ret rc		Return status code
 	 */
-	int ( * shared ) ( const void *private, const void *partner,
+	int ( * shared ) ( struct exchange_algorithm *exchange,
+			   const void *private, const void *partner,
 			   void *shared );
+	/** Algorithm private data */
+	void *priv;
 };
 
 /** An elliptic curve */
@@ -350,13 +356,13 @@
 static inline __attribute__ (( always_inline )) void
 exchange_public ( struct exchange_algorithm *exchange, const void *private,
 		  void *public ) {
-	exchange->public ( private, public );
+	exchange->public ( exchange, private, public );
 }
 
 static inline __attribute__ (( always_inline )) int
 exchange_shared ( struct exchange_algorithm *exchange, const void *private,
 		  const void *partner, void *shared ) {
-	return exchange->shared ( private, partner, shared );
+	return exchange->shared ( exchange, private, partner, shared );
 }
 
 static inline __attribute__ (( always_inline )) int
diff --git a/src/include/ipxe/ffdhe.h b/src/include/ipxe/ffdhe.h
index 349680f..12e0e31 100644
--- a/src/include/ipxe/ffdhe.h
+++ b/src/include/ipxe/ffdhe.h
@@ -33,8 +33,11 @@
 	uint32_t lsb32;
 };
 
-extern int ffdhe ( struct ffdhe_group *group, const void *public,
-		   const void *private, void *shared );
+extern void ffdhe_public ( struct exchange_algorithm *exchange,
+			   const void *private, void *public );
+extern int ffdhe_shared ( struct exchange_algorithm *exchange,
+			  const void *private, const void *partner,
+			  void *shared );
 
 /** Define a finite field DHE group */
 #define FFDHE_GROUP( _name, _exchange, _constant, _bits, _expbits, _lsb ) \
@@ -47,23 +50,14 @@
 		.expsize = bigint_required_size ( ( _expbits + 7 ) / 8 ), \
 		.lsb32 = cpu_to_be32 ( _lsb ),				  \
 	};								  \
-	static void _name ## _public ( const void *private,		  \
-				       void *public ) {			  \
-		ffdhe ( &_name ## _group, NULL, private, public );	  \
-	}								  \
-	static int _name ## _shared ( const void *private,		  \
-				      const void *partner,		  \
-				      void *shared ) {			  \
-		return ffdhe ( &_name ## _group, partner, private,	  \
-			       shared );				  \
-	}								  \
 	struct exchange_algorithm _exchange = {				  \
 		.name = #_name,						  \
 		.privsize = ( ( _expbits + 7 ) / 8 ),			  \
 		.pubsize = ( _bits / 8 ),				  \
 		.sharedsize = ( _bits / 8 ),				  \
-		.public = _name ## _public,				  \
-		.shared = _name ## _shared,				  \
+		.public = ffdhe_public,					  \
+		.shared = ffdhe_shared,					  \
+		.priv = &_name ## _group,				  \
 	}
 
 extern struct exchange_algorithm ffdhe2048_algorithm;
diff --git a/src/include/ipxe/weierstrass.h b/src/include/ipxe/weierstrass.h
index fa2e53c..4095b4a 100644
--- a/src/include/ipxe/weierstrass.h
+++ b/src/include/ipxe/weierstrass.h
@@ -164,9 +164,9 @@
 extern int weierstrass_add_once ( struct weierstrass_curve *curve,
 				  const void *addend, const void *augend,
 				  void *result );
-extern void weierstrass_public ( struct weierstrass_curve *curve,
+extern void weierstrass_public ( struct exchange_algorithm *exchange,
 				 const void *private, void *public );
-extern int weierstrass_shared ( struct weierstrass_curve *curve,
+extern int weierstrass_shared ( struct exchange_algorithm *exchange,
 				const void *private, const void *partner,
 				void *shared );
 
@@ -209,17 +209,6 @@
 		return weierstrass_add_once ( &_name ## _weierstrass,	\
 					      addend, augend, result );	\
 	}								\
-	static void _name ## _public ( const void *private,		\
-				       void *public ) {			\
-		weierstrass_public ( &_name ## _weierstrass,		\
-				     private, public );			\
-	}								\
-	static int _name ## _shared ( const void *private,		\
-				      const void *partner,		\
-				      void *shared ) {			\
-		return weierstrass_shared ( &_name ## _weierstrass,	\
-					    private, partner, shared );	\
-	}								\
 	struct elliptic_curve _curve = {				\
 		.name = #_name,						\
 		.pointsize = sizeof ( weierstrass_raw_t(_len) ),	\
@@ -235,8 +224,9 @@
 		.privsize = (_len),					\
 		.pubsize = sizeof ( weierstrass_uncompressed_t(_len) ), \
 		.sharedsize = (_len),					\
-		.public = _name ## _public,				\
-		.shared = _name ## _shared,				\
+		.public = weierstrass_public,				\
+		.shared = weierstrass_shared,				\
+		.priv = &_name ## _weierstrass,				\
 	}
 
 #endif /* _IPXE_WEIERSTRASS_H */