Browse Source

[tls] Support stateless session resumption

Add support for RFC5077 session ticket extensions to allow for
stateless TLS session resumption.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 5 years ago
parent
commit
eaba1a22b8
2 changed files with 122 additions and 19 deletions
  1. 12
    0
      src/include/ipxe/tls.h
  2. 110
    19
      src/net/tls.c

+ 12
- 0
src/include/ipxe/tls.h View File

63
 #define TLS_HELLO_REQUEST 0
63
 #define TLS_HELLO_REQUEST 0
64
 #define TLS_CLIENT_HELLO 1
64
 #define TLS_CLIENT_HELLO 1
65
 #define TLS_SERVER_HELLO 2
65
 #define TLS_SERVER_HELLO 2
66
+#define TLS_NEW_SESSION_TICKET 4
66
 #define TLS_CERTIFICATE 11
67
 #define TLS_CERTIFICATE 11
67
 #define TLS_SERVER_KEY_EXCHANGE 12
68
 #define TLS_SERVER_KEY_EXCHANGE 12
68
 #define TLS_CERTIFICATE_REQUEST 13
69
 #define TLS_CERTIFICATE_REQUEST 13
108
 /* TLS signature algorithms extension */
109
 /* TLS signature algorithms extension */
109
 #define TLS_SIGNATURE_ALGORITHMS 13
110
 #define TLS_SIGNATURE_ALGORITHMS 13
110
 
111
 
112
+/* TLS session ticket extension */
113
+#define TLS_SESSION_TICKET 35
114
+
111
 /* TLS renegotiation information extension */
115
 /* TLS renegotiation information extension */
112
 #define TLS_RENEGOTIATION_INFO 0xff01
116
 #define TLS_RENEGOTIATION_INFO 0xff01
113
 
117
 
255
 	uint8_t id[32];
259
 	uint8_t id[32];
256
 	/** Length of session ID */
260
 	/** Length of session ID */
257
 	size_t id_len;
261
 	size_t id_len;
262
+	/** Session ticket */
263
+	void *ticket;
264
+	/** Length of session ticket */
265
+	size_t ticket_len;
258
 	/** Master secret */
266
 	/** Master secret */
259
 	uint8_t master_secret[48];
267
 	uint8_t master_secret[48];
260
 
268
 
275
 	uint8_t session_id[32];
283
 	uint8_t session_id[32];
276
 	/** Length of session ID */
284
 	/** Length of session ID */
277
 	size_t session_id_len;
285
 	size_t session_id_len;
286
+	/** New session ticket */
287
+	void *new_session_ticket;
288
+	/** Length of new session ticket */
289
+	size_t new_session_ticket_len;
278
 
290
 
279
 	/** Plaintext stream */
291
 	/** Plaintext stream */
280
 	struct interface plainstream;
292
 	struct interface plainstream;

+ 110
- 19
src/net/tls.c View File

102
 #define EINFO_EINVAL_MAC						\
102
 #define EINFO_EINVAL_MAC						\
103
 	__einfo_uniqify ( EINFO_EINVAL, 0x0d,				\
103
 	__einfo_uniqify ( EINFO_EINVAL, 0x0d,				\
104
 			  "Invalid MAC" )
104
 			  "Invalid MAC" )
105
+#define EINVAL_TICKET __einfo_error ( EINFO_EINVAL_TICKET )
106
+#define EINFO_EINVAL_TICKET						\
107
+	__einfo_uniqify ( EINFO_EINVAL, 0x0e,				\
108
+			  "Invalid New Session Ticket record")
105
 #define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
109
 #define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
106
 #define EINFO_EIO_ALERT							\
110
 #define EINFO_EIO_ALERT							\
107
 	__einfo_uniqify ( EINFO_EIO, 0x01,				\
111
 	__einfo_uniqify ( EINFO_EIO, 0x01,				\
326
 	/* Remove from list of sessions */
330
 	/* Remove from list of sessions */
327
 	list_del ( &session->list );
331
 	list_del ( &session->list );
328
 
332
 
333
+	/* Free session ticket */
334
+	free ( session->ticket );
335
+
329
 	/* Free session */
336
 	/* Free session */
330
 	free ( session );
337
 	free ( session );
331
 }
338
 }
343
 	struct io_buffer *tmp;
350
 	struct io_buffer *tmp;
344
 
351
 
345
 	/* Free dynamically-allocated resources */
352
 	/* Free dynamically-allocated resources */
353
+	free ( tls->new_session_ticket );
346
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
354
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
347
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
355
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
348
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
356
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
1007
 		uint16_t version;
1015
 		uint16_t version;
1008
 		uint8_t random[32];
1016
 		uint8_t random[32];
1009
 		uint8_t session_id_len;
1017
 		uint8_t session_id_len;
1010
-		uint8_t session_id[session->id_len];
1018
+		uint8_t session_id[tls->session_id_len];
1011
 		uint16_t cipher_suite_len;
1019
 		uint16_t cipher_suite_len;
1012
 		uint16_t cipher_suites[TLS_NUM_CIPHER_SUITES];
1020
 		uint16_t cipher_suites[TLS_NUM_CIPHER_SUITES];
1013
 		uint8_t compression_methods_len;
1021
 		uint8_t compression_methods_len;
1043
 				uint8_t data[ tls->secure_renegotiation ?
1051
 				uint8_t data[ tls->secure_renegotiation ?
1044
 					      sizeof ( tls->verify.client ) :0];
1052
 					      sizeof ( tls->verify.client ) :0];
1045
 			} __attribute__ (( packed )) renegotiation_info;
1053
 			} __attribute__ (( packed )) renegotiation_info;
1054
+			uint16_t session_ticket_type;
1055
+			uint16_t session_ticket_len;
1056
+			struct {
1057
+				uint8_t data[session->ticket_len];
1058
+			} __attribute__ (( packed )) session_ticket;
1046
 		} __attribute__ (( packed )) extensions;
1059
 		} __attribute__ (( packed )) extensions;
1047
 	} __attribute__ (( packed )) hello;
1060
 	} __attribute__ (( packed )) hello;
1048
 	struct tls_cipher_suite *suite;
1061
 	struct tls_cipher_suite *suite;
1049
 	struct tls_signature_hash_algorithm *sighash;
1062
 	struct tls_signature_hash_algorithm *sighash;
1050
 	unsigned int i;
1063
 	unsigned int i;
1051
 
1064
 
1052
-	/* Record requested session ID and associated master secret */
1053
-	memcpy ( tls->session_id, session->id, sizeof ( tls->session_id ) );
1054
-	tls->session_id_len = session->id_len;
1055
-	memcpy ( tls->master_secret, session->master_secret,
1056
-		 sizeof ( tls->master_secret ) );
1057
-
1058
 	/* Construct record */
1065
 	/* Construct record */
1059
 	memset ( &hello, 0, sizeof ( hello ) );
1066
 	memset ( &hello, 0, sizeof ( hello ) );
1060
 	hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
1067
 	hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
1102
 		= sizeof ( hello.extensions.renegotiation_info.data );
1109
 		= sizeof ( hello.extensions.renegotiation_info.data );
1103
 	memcpy ( hello.extensions.renegotiation_info.data, tls->verify.client,
1110
 	memcpy ( hello.extensions.renegotiation_info.data, tls->verify.client,
1104
 		 sizeof ( hello.extensions.renegotiation_info.data ) );
1111
 		 sizeof ( hello.extensions.renegotiation_info.data ) );
1112
+	hello.extensions.session_ticket_type = htons ( TLS_SESSION_TICKET );
1113
+	hello.extensions.session_ticket_len
1114
+		= htons ( sizeof ( hello.extensions.session_ticket ) );
1115
+	memcpy ( hello.extensions.session_ticket.data, session->ticket,
1116
+		 sizeof ( hello.extensions.session_ticket.data ) );
1105
 
1117
 
1106
 	return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
1118
 	return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
1107
 }
1119
 }
1631
 	return 0;
1643
 	return 0;
1632
 }
1644
 }
1633
 
1645
 
1646
+/**
1647
+ * Receive New Session Ticket handshake record
1648
+ *
1649
+ * @v tls		TLS connection
1650
+ * @v data		Plaintext handshake record
1651
+ * @v len		Length of plaintext handshake record
1652
+ * @ret rc		Return status code
1653
+ */
1654
+static int tls_new_session_ticket ( struct tls_connection *tls,
1655
+				    const void *data, size_t len ) {
1656
+	const struct {
1657
+		uint32_t lifetime;
1658
+		uint16_t len;
1659
+		uint8_t ticket[0];
1660
+	} __attribute__ (( packed )) *new_session_ticket = data;
1661
+	size_t ticket_len;
1662
+
1663
+	/* Parse header */
1664
+	if ( sizeof ( *new_session_ticket ) > len ) {
1665
+		DBGC ( tls, "TLS %p received underlength New Session Ticket\n",
1666
+		       tls );
1667
+		DBGC_HD ( tls, data, len );
1668
+		return -EINVAL_TICKET;
1669
+	}
1670
+	ticket_len = ntohs ( new_session_ticket->len );
1671
+	if ( ticket_len > ( len - sizeof ( *new_session_ticket ) ) ) {
1672
+		DBGC ( tls, "TLS %p received overlength New Session Ticket\n",
1673
+		       tls );
1674
+		DBGC_HD ( tls, data, len );
1675
+		return -EINVAL_TICKET;
1676
+	}
1677
+
1678
+	/* Free any unapplied new session ticket */
1679
+	free ( tls->new_session_ticket );
1680
+	tls->new_session_ticket = NULL;
1681
+	tls->new_session_ticket_len = 0;
1682
+
1683
+	/* Record ticket */
1684
+	tls->new_session_ticket = malloc ( ticket_len );
1685
+	if ( ! tls->new_session_ticket )
1686
+		return -ENOMEM;
1687
+	memcpy ( tls->new_session_ticket, new_session_ticket->ticket,
1688
+		 ticket_len );
1689
+	tls->new_session_ticket_len = ticket_len;
1690
+	DBGC ( tls, "TLS %p new session ticket:\n", tls );
1691
+	DBGC_HDA ( tls, 0, tls->new_session_ticket,
1692
+		   tls->new_session_ticket_len );
1693
+
1694
+	return 0;
1695
+}
1696
+
1634
 /**
1697
 /**
1635
  * Parse certificate chain
1698
  * Parse certificate chain
1636
  *
1699
  *
1863
 		tls_tx_resume ( tls );
1926
 		tls_tx_resume ( tls );
1864
 	}
1927
 	}
1865
 
1928
 
1866
-	/* Record session ID and master secret, if applicable */
1929
+	/* Record session ID, ticket, and master secret, if applicable */
1930
+	if ( tls->session_id_len || tls->new_session_ticket_len ) {
1931
+		memcpy ( session->master_secret, tls->master_secret,
1932
+			 sizeof ( session->master_secret ) );
1933
+	}
1867
 	if ( tls->session_id_len ) {
1934
 	if ( tls->session_id_len ) {
1868
 		session->id_len = tls->session_id_len;
1935
 		session->id_len = tls->session_id_len;
1869
 		memcpy ( session->id, tls->session_id, sizeof ( session->id ) );
1936
 		memcpy ( session->id, tls->session_id, sizeof ( session->id ) );
1870
-		memcpy ( session->master_secret, tls->master_secret,
1871
-			 sizeof ( session->master_secret ) );
1937
+	}
1938
+	if ( tls->new_session_ticket_len ) {
1939
+		free ( session->ticket );
1940
+		session->ticket = tls->new_session_ticket;
1941
+		session->ticket_len = tls->new_session_ticket_len;
1942
+		tls->new_session_ticket = NULL;
1943
+		tls->new_session_ticket_len = 0;
1872
 	}
1944
 	}
1873
 
1945
 
1874
 	/* Move to end of session's connection list and allow other
1946
 	/* Move to end of session's connection list and allow other
1933
 		case TLS_SERVER_HELLO:
2005
 		case TLS_SERVER_HELLO:
1934
 			rc = tls_new_server_hello ( tls, payload, payload_len );
2006
 			rc = tls_new_server_hello ( tls, payload, payload_len );
1935
 			break;
2007
 			break;
2008
+		case TLS_NEW_SESSION_TICKET:
2009
+			rc = tls_new_session_ticket ( tls, payload,
2010
+						      payload_len );
2011
+			break;
1936
 		case TLS_CERTIFICATE:
2012
 		case TLS_CERTIFICATE:
1937
 			rc = tls_new_certificate ( tls, payload, payload_len );
2013
 			rc = tls_new_certificate ( tls, payload, payload_len );
1938
 			break;
2014
 			break;
2804
 
2880
 
2805
 	/* Send first pending transmission */
2881
 	/* Send first pending transmission */
2806
 	if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) {
2882
 	if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) {
2807
-		/* Wait for session ID to become available unless we
2808
-		 * are the lead connection within the session.
2883
+		/* Serialise server negotiations within a session, to
2884
+		 * provide a consistent view of session IDs and
2885
+		 * session tickets.
2809
 		 */
2886
 		 */
2810
-		if ( session->id_len == 0 ) {
2811
-			list_for_each_entry ( conn, &session->conn, list ) {
2812
-				if ( conn == tls )
2813
-					break;
2814
-				if ( is_pending ( &conn->server_negotiation ) )
2815
-					return;
2816
-			}
2887
+		list_for_each_entry ( conn, &session->conn, list ) {
2888
+			if ( conn == tls )
2889
+				break;
2890
+			if ( is_pending ( &conn->server_negotiation ) )
2891
+				return;
2892
+		}
2893
+		/* Record or generate session ID and associated master secret */
2894
+		if ( session->id_len ) {
2895
+			/* Attempt to resume an existing session */
2896
+			memcpy ( tls->session_id, session->id,
2897
+				 sizeof ( tls->session_id ) );
2898
+			tls->session_id_len = session->id_len;
2899
+			memcpy ( tls->master_secret, session->master_secret,
2900
+				 sizeof ( tls->master_secret ) );
2901
+		} else {
2902
+			/* No existing session: use a random session ID */
2903
+			assert ( sizeof ( tls->session_id ) ==
2904
+				 sizeof ( tls->client_random ) );
2905
+			memcpy ( tls->session_id, &tls->client_random,
2906
+				 sizeof ( tls->session_id ) );
2907
+			tls->session_id_len = sizeof ( tls->session_id );
2817
 		}
2908
 		}
2818
 		/* Send Client Hello */
2909
 		/* Send Client Hello */
2819
 		if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
2910
 		if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {

Loading…
Cancel
Save