|
@@ -102,6 +102,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
102
|
102
|
#define EINFO_EINVAL_MAC \
|
103
|
103
|
__einfo_uniqify ( EINFO_EINVAL, 0x0d, \
|
104
|
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
|
109
|
#define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
|
106
|
110
|
#define EINFO_EIO_ALERT \
|
107
|
111
|
__einfo_uniqify ( EINFO_EIO, 0x01, \
|
|
@@ -326,6 +330,9 @@ static void free_tls_session ( struct refcnt *refcnt ) {
|
326
|
330
|
/* Remove from list of sessions */
|
327
|
331
|
list_del ( &session->list );
|
328
|
332
|
|
|
333
|
+ /* Free session ticket */
|
|
334
|
+ free ( session->ticket );
|
|
335
|
+
|
329
|
336
|
/* Free session */
|
330
|
337
|
free ( session );
|
331
|
338
|
}
|
|
@@ -343,6 +350,7 @@ static void free_tls ( struct refcnt *refcnt ) {
|
343
|
350
|
struct io_buffer *tmp;
|
344
|
351
|
|
345
|
352
|
/* Free dynamically-allocated resources */
|
|
353
|
+ free ( tls->new_session_ticket );
|
346
|
354
|
tls_clear_cipher ( tls, &tls->tx_cipherspec );
|
347
|
355
|
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
|
348
|
356
|
tls_clear_cipher ( tls, &tls->rx_cipherspec );
|
|
@@ -1007,7 +1015,7 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
|
1007
|
1015
|
uint16_t version;
|
1008
|
1016
|
uint8_t random[32];
|
1009
|
1017
|
uint8_t session_id_len;
|
1010
|
|
- uint8_t session_id[session->id_len];
|
|
1018
|
+ uint8_t session_id[tls->session_id_len];
|
1011
|
1019
|
uint16_t cipher_suite_len;
|
1012
|
1020
|
uint16_t cipher_suites[TLS_NUM_CIPHER_SUITES];
|
1013
|
1021
|
uint8_t compression_methods_len;
|
|
@@ -1043,18 +1051,17 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
|
1043
|
1051
|
uint8_t data[ tls->secure_renegotiation ?
|
1044
|
1052
|
sizeof ( tls->verify.client ) :0];
|
1045
|
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
|
1059
|
} __attribute__ (( packed )) extensions;
|
1047
|
1060
|
} __attribute__ (( packed )) hello;
|
1048
|
1061
|
struct tls_cipher_suite *suite;
|
1049
|
1062
|
struct tls_signature_hash_algorithm *sighash;
|
1050
|
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
|
1065
|
/* Construct record */
|
1059
|
1066
|
memset ( &hello, 0, sizeof ( hello ) );
|
1060
|
1067
|
hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
|
|
@@ -1102,6 +1109,11 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
|
1102
|
1109
|
= sizeof ( hello.extensions.renegotiation_info.data );
|
1103
|
1110
|
memcpy ( hello.extensions.renegotiation_info.data, tls->verify.client,
|
1104
|
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
|
1118
|
return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
|
1107
|
1119
|
}
|
|
@@ -1631,6 +1643,57 @@ static int tls_new_server_hello ( struct tls_connection *tls,
|
1631
|
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
|
1698
|
* Parse certificate chain
|
1636
|
1699
|
*
|
|
@@ -1863,12 +1926,21 @@ static int tls_new_finished ( struct tls_connection *tls,
|
1863
|
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
|
1934
|
if ( tls->session_id_len ) {
|
1868
|
1935
|
session->id_len = tls->session_id_len;
|
1869
|
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
|
1946
|
/* Move to end of session's connection list and allow other
|
|
@@ -1933,6 +2005,10 @@ static int tls_new_handshake ( struct tls_connection *tls,
|
1933
|
2005
|
case TLS_SERVER_HELLO:
|
1934
|
2006
|
rc = tls_new_server_hello ( tls, payload, payload_len );
|
1935
|
2007
|
break;
|
|
2008
|
+ case TLS_NEW_SESSION_TICKET:
|
|
2009
|
+ rc = tls_new_session_ticket ( tls, payload,
|
|
2010
|
+ payload_len );
|
|
2011
|
+ break;
|
1936
|
2012
|
case TLS_CERTIFICATE:
|
1937
|
2013
|
rc = tls_new_certificate ( tls, payload, payload_len );
|
1938
|
2014
|
break;
|
|
@@ -2804,16 +2880,31 @@ static void tls_tx_step ( struct tls_connection *tls ) {
|
2804
|
2880
|
|
2805
|
2881
|
/* Send first pending transmission */
|
2806
|
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
|
2909
|
/* Send Client Hello */
|
2819
|
2910
|
if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
|