[crypto] Ensure that a closed channel is left with unusable ciphers

We currently protect against a consumer that erroneously uses values
generated from the ephemeral master secret after closing a previously
opened channel, by deliberately replacing the ephemeral master secret
rather than zeroing it when the channel is closed.

Extend this concept to protect against a consumer that erroneously
uses the ciphers after closing a previously opened channel (or that
erroneously uses the ciphers from a channel that failed to open
successfully), by using the dead ciphers by default and by enabling
the plaintext (null) ciphers when and only when the channel has been
successfully opened.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/crypto/channel.c b/src/crypto/channel.c
index c2252cd..36e2254 100644
--- a/src/crypto/channel.c
+++ b/src/crypto/channel.c
@@ -1070,7 +1070,7 @@
  * cipher-related failure, to guard against code paths that may fail
  * to check for cipher errors.
  */
-static struct cipher_algorithm channel_dead_cipher = {
+struct cipher_algorithm channel_dead_cipher = {
 	.name = "dead",
 	.ctxsize = 0,
 	.blocksize = 1,
@@ -1197,29 +1197,6 @@
  */
 
 /**
- * Reset secure channel
- *
- * @v channel		Secure channel
- */
-static void channel_reset ( struct secure_channel *channel ) {
-
-	/* Reset ciphers to plaintext */
-	channel_clear_cipher ( &channel->tx );
-	channel_clear_cipher ( &channel->rx );
-	channel->tx.cipher = &cipher_null;
-	channel->rx.cipher = &cipher_null;
-	assert ( channel->tx.ctx == NULL );
-	assert ( channel->rx.ctx == NULL );
-
-	/* Clear security properties */
-	channel_unkey ( channel );
-	assert ( channel->props.keyed == 0 );
-	assert ( channel->props.bound == NULL );
-	assert ( channel->props.confirmed == NULL );
-	assert ( channel->props.established == NULL );
-}
-
-/**
  * Open secure channel
  *
  * @v channel		Secure channel
@@ -1234,16 +1211,34 @@
 	assert ( channel->op->reset != NULL );
 	assert ( channel->op->apply != NULL );
 	assert ( channel->op->verify != NULL );
+
+	/* Clear security properties (which should already be clear) */
+	assert ( channel->props.keyed == 0 );
+	assert ( channel->props.bound == NULL );
+	assert ( channel->props.confirmed == NULL );
+	assert ( channel->props.established == NULL );
+	channel_unkey ( channel );
+	assert ( channel->props.keyed == 0 );
+	assert ( channel->props.bound == NULL );
+	assert ( channel->props.confirmed == NULL );
+	assert ( channel->props.established == NULL );
+
+	/* Reset ciphers (which should already have no contexts) */
 	assert ( channel->tx.ctx == NULL );
 	assert ( channel->rx.ctx == NULL );
-
-	/* Reset ciphers and security properties */
-	channel_reset ( channel );
+	channel_clear_cipher ( &channel->tx );
+	channel_clear_cipher ( &channel->rx );
+	assert ( channel->tx.ctx == NULL );
+	assert ( channel->rx.ctx == NULL );
 
 	/* Initialise ephemeral master secret */
 	if ( ( rc = channel_ephemeral_init ( channel ) ) != 0 )
 		return rc;
 
+	/* Enable initial plaintext ciphers */
+	channel->tx.cipher = &cipher_null;
+	channel->rx.cipher = &cipher_null;
+
 	DBGC ( channel, "CHANNEL %p opened\n", channel );
 	return 0;
 }
@@ -1275,6 +1270,10 @@
 
 	/* Clear security properties */
 	channel_unkey ( channel );
+	assert ( channel->props.keyed == 0 );
+	assert ( channel->props.bound == NULL );
+	assert ( channel->props.confirmed == NULL );
+	assert ( channel->props.established == NULL );
 
 	/* Replace ephemeral master secret
 	 *
@@ -1301,8 +1300,18 @@
  */
 void channel_close ( struct secure_channel *channel ) {
 
-	/* Reset channel */
-	channel_reset ( channel );
+	/* Clear security properties */
+	channel_unkey ( channel );
+	assert ( channel->props.keyed == 0 );
+	assert ( channel->props.bound == NULL );
+	assert ( channel->props.confirmed == NULL );
+	assert ( channel->props.established == NULL );
+
+	/* Reset ciphers */
+	channel_clear_cipher ( &channel->tx );
+	channel_clear_cipher ( &channel->rx );
+	assert ( channel->tx.ctx == NULL );
+	assert ( channel->rx.ctx == NULL );
 
 	/* Replace ephemeral master secret
 	 *
diff --git a/src/include/ipxe/channel.h b/src/include/ipxe/channel.h
index fb90cf9..570ac2f 100644
--- a/src/include/ipxe/channel.h
+++ b/src/include/ipxe/channel.h
@@ -245,6 +245,8 @@
 			   const void *auth, size_t len );
 };
 
+extern struct cipher_algorithm channel_dead_cipher;
+
 /**
  * Initialise secure channel
  *
@@ -255,6 +257,8 @@
 				  struct secure_channel_operations *op ) {
 
 	channel->op = op;
+	channel->tx.cipher = &channel_dead_cipher;
+	channel->rx.cipher = &channel_dead_cipher;
 }
 
 /**