Browse Source

[tls] Split received records over multiple I/O buffers

TLS servers are not obliged to implement the RFC3546 maximum fragment
length extension, and many common servers (including OpenSSL, as used
in Apache's mod_ssl) do not do so.  iPXE may therefore have to cope
with TLS records of up to 16kB.  Allocations for 16kB have a
non-negligible chance of failing, causing the TLS connection to abort.

Fix by maintaining the received record as a linked list of I/O
buffers, rather than a single contiguous buffer.  To reduce memory
pressure, we also decrypt in situ, and deliver the decrypted data via
xfer_deliver_iob() rather than xfer_deliver_raw().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
72db14640c
2 changed files with 304 additions and 168 deletions
  1. 26
    4
      src/include/ipxe/tls.h
  2. 278
    164
      src/net/tls.c

+ 26
- 4
src/include/ipxe/tls.h View File

@@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
19 19
 #include <ipxe/sha256.h>
20 20
 #include <ipxe/x509.h>
21 21
 #include <ipxe/pending.h>
22
+#include <ipxe/iobuf.h>
22 23
 
23 24
 /** A TLS header */
24 25
 struct tls_header {
@@ -264,14 +265,35 @@ struct tls_session {
264 265
 	uint64_t rx_seq;
265 266
 	/** RX state */
266 267
 	enum tls_rx_state rx_state;
267
-	/** Offset within current RX state */
268
-	size_t rx_rcvd;
269 268
 	/** Current received record header */
270 269
 	struct tls_header rx_header;
271
-	/** Current received raw data buffer */
272
-	void *rx_data;
270
+	/** Current received record header (static I/O buffer) */
271
+	struct io_buffer rx_header_iobuf;
272
+	/** List of received data buffers */
273
+	struct list_head rx_data;
273 274
 };
274 275
 
276
+/** RX I/O buffer size
277
+ *
278
+ * The maximum fragment length extension is optional, and many common
279
+ * implementations (including OpenSSL) do not support it.  We must
280
+ * therefore be prepared to receive records of up to 16kB in length.
281
+ * The chance of an allocation of this size failing is non-negligible,
282
+ * so we must split received data into smaller allocations.
283
+ */
284
+#define TLS_RX_BUFSIZE 4096
285
+
286
+/** Minimum RX I/O buffer size
287
+ *
288
+ * To simplify manipulations, we ensure that no RX I/O buffer is
289
+ * smaller than this size.  This allows us to assume that the MAC and
290
+ * padding are entirely contained within the final I/O buffer.
291
+ */
292
+#define TLS_RX_MIN_BUFSIZE 512
293
+
294
+/** RX I/O buffer alignment */
295
+#define TLS_RX_ALIGN 16
296
+
275 297
 extern int add_tls ( struct interface *xfer, const char *name,
276 298
 		     struct interface **next );
277 299
 

+ 278
- 164
src/net/tls.c View File

@@ -101,6 +101,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
101 101
 #define EINFO_EINVAL_RX_STATE						\
102 102
 	__einfo_uniqify ( EINFO_EINVAL, 0x0c,				\
103 103
 			  "Invalid receive state" )
104
+#define EINVAL_MAC __einfo_error ( EINFO_EINVAL_MAC )
105
+#define EINFO_EINVAL_MAC						\
106
+	__einfo_uniqify ( EINFO_EINVAL, 0x0d,				\
107
+			  "Invalid MAC" )
108
+#define EINVAL_NON_DATA __einfo_error ( EINFO_EINVAL_NON_DATA )
109
+#define EINFO_EINVAL_NON_DATA						\
110
+	__einfo_uniqify ( EINFO_EINVAL, 0x0e,				\
111
+			  "Overlength non-data record" )
104 112
 #define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
105 113
 #define EINFO_EIO_ALERT							\
106 114
 	__einfo_uniqify ( EINFO_EINVAL, 0x01,				\
@@ -125,10 +133,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
125 133
 #define EINFO_ENOMEM_TX_CIPHERTEXT					\
126 134
 	__einfo_uniqify ( EINFO_ENOMEM, 0x05,				\
127 135
 			  "Not enough space for transmitted ciphertext" )
128
-#define ENOMEM_RX_PLAINTEXT __einfo_error ( EINFO_ENOMEM_RX_PLAINTEXT )
129
-#define EINFO_ENOMEM_RX_PLAINTEXT					\
130
-	__einfo_uniqify ( EINFO_ENOMEM, 0x06,				\
131
-			  "Not enough space for received plaintext" )
132 136
 #define ENOMEM_RX_DATA __einfo_error ( EINFO_ENOMEM_RX_DATA )
133 137
 #define EINFO_ENOMEM_RX_DATA						\
134 138
 	__einfo_uniqify ( EINFO_ENOMEM, 0x07,				\
@@ -159,7 +163,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
159 163
 			  "Handshake verification failed" )
160 164
 #define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
161 165
 #define EINFO_EPROTO_VERSION						\
162
-	__einfo_uniqify ( EINFO_EINVAL, 0x01,				\
166
+	__einfo_uniqify ( EINFO_EPROTO, 0x01,				\
163 167
 			  "Illegal protocol version upgrade" )
164 168
 
165 169
 static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
@@ -295,13 +299,18 @@ struct rsa_digestinfo_prefix rsa_md5_sha1_prefix __rsa_digestinfo_prefix = {
295 299
 static void free_tls ( struct refcnt *refcnt ) {
296 300
 	struct tls_session *tls =
297 301
 		container_of ( refcnt, struct tls_session, refcnt );
302
+	struct io_buffer *iobuf;
303
+	struct io_buffer *tmp;
298 304
 
299 305
 	/* Free dynamically-allocated resources */
300 306
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
301 307
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
302 308
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
303 309
 	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
304
-	free ( tls->rx_data );
310
+	list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
311
+		list_del ( &iobuf->list );
312
+		free_iob ( iobuf );
313
+	}
305 314
 	x509_chain_put ( tls->chain );
306 315
 
307 316
 	/* Free TLS structure itself */
@@ -1013,7 +1022,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
1013 1022
 	hello.extensions.max_fragment_length_len
1014 1023
 		= htons ( sizeof ( hello.extensions.max_fragment_length ) );
1015 1024
 	hello.extensions.max_fragment_length.max
1016
-		= TLS_MAX_FRAGMENT_LENGTH_2048;
1025
+		= TLS_MAX_FRAGMENT_LENGTH_4096;
1017 1026
 
1018 1027
 	return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
1019 1028
 }
@@ -1703,31 +1712,71 @@ static int tls_new_handshake ( struct tls_session *tls,
1703 1712
  *
1704 1713
  * @v tls		TLS session
1705 1714
  * @v type		Record type
1706
- * @v data		Plaintext record
1707
- * @v len		Length of plaintext record
1715
+ * @v rx_data		List of received data buffers
1708 1716
  * @ret rc		Return status code
1709 1717
  */
1710 1718
 static int tls_new_record ( struct tls_session *tls, unsigned int type,
1711
-			    const void *data, size_t len ) {
1719
+			    struct list_head *rx_data ) {
1720
+	struct io_buffer *iobuf;
1721
+	int ( * handler ) ( struct tls_session *tls, const void *data,
1722
+			    size_t len );
1723
+	int rc;
1724
+
1725
+	/* Deliver data records to the plainstream interface */
1726
+	if ( type == TLS_TYPE_DATA ) {
1727
+
1728
+		/* Fail unless we are ready to receive data */
1729
+		if ( ! tls_ready ( tls ) )
1730
+			return -ENOTCONN;
1712 1731
 
1732
+		/* Deliver each I/O buffer in turn */
1733
+		while ( ( iobuf = list_first_entry ( rx_data, struct io_buffer,
1734
+						     list ) ) ) {
1735
+			list_del ( &iobuf->list );
1736
+			if ( ( rc = xfer_deliver_iob ( &tls->plainstream,
1737
+						       iobuf ) ) != 0 ) {
1738
+				DBGC ( tls, "TLS %p could not deliver data: "
1739
+				       "%s\n", tls, strerror ( rc ) );
1740
+				return rc;
1741
+			}
1742
+		}
1743
+		return 0;
1744
+	}
1745
+
1746
+	/* For all other records, fail unless we have exactly one I/O buffer */
1747
+	iobuf = list_first_entry ( rx_data, struct io_buffer, list );
1748
+	assert ( iobuf != NULL );
1749
+	list_del ( &iobuf->list );
1750
+	if ( ! list_empty ( rx_data ) ) {
1751
+		DBGC ( tls, "TLS %p overlength non-data record\n", tls );
1752
+		return -EINVAL_NON_DATA;
1753
+	}
1754
+
1755
+	/* Determine handler */
1713 1756
 	switch ( type ) {
1714 1757
 	case TLS_TYPE_CHANGE_CIPHER:
1715
-		return tls_new_change_cipher ( tls, data, len );
1758
+		handler = tls_new_change_cipher;
1759
+		break;
1716 1760
 	case TLS_TYPE_ALERT:
1717
-		return tls_new_alert ( tls, data, len );
1761
+		handler = tls_new_alert;
1762
+		break;
1718 1763
 	case TLS_TYPE_HANDSHAKE:
1719
-		return tls_new_handshake ( tls, data, len );
1720
-	case TLS_TYPE_DATA:
1721
-		if ( ! tls_ready ( tls ) )
1722
-			return -ENOTCONN;
1723
-		return xfer_deliver_raw ( &tls->plainstream, data, len );
1764
+		handler = tls_new_handshake;
1765
+		break;
1724 1766
 	default:
1725 1767
 		/* RFC4346 says that we should just ignore unknown
1726 1768
 		 * record types.
1727 1769
 		 */
1770
+		handler = NULL;
1728 1771
 		DBGC ( tls, "TLS %p ignoring record type %d\n", tls, type );
1729
-		return 0;
1772
+		break;
1730 1773
 	}
1774
+
1775
+	/* Handle record and free I/O buffer */
1776
+	if ( handler )
1777
+		rc = handler ( tls, iobuf->data, iob_len ( iobuf ) );
1778
+	free_iob ( iobuf );
1779
+	return rc;
1731 1780
 }
1732 1781
 
1733 1782
 /******************************************************************************
@@ -1737,10 +1786,57 @@ static int tls_new_record ( struct tls_session *tls, unsigned int type,
1737 1786
  ******************************************************************************
1738 1787
  */
1739 1788
 
1789
+/**
1790
+ * Initialise HMAC
1791
+ *
1792
+ * @v cipherspec	Cipher specification
1793
+ * @v ctx		Context
1794
+ * @v seq		Sequence number
1795
+ * @v tlshdr		TLS header
1796
+ */
1797
+static void tls_hmac_init ( struct tls_cipherspec *cipherspec, void *ctx,
1798
+			    uint64_t seq, struct tls_header *tlshdr ) {
1799
+	struct digest_algorithm *digest = cipherspec->suite->digest;
1800
+
1801
+	hmac_init ( digest, ctx, cipherspec->mac_secret, &digest->digestsize );
1802
+	seq = cpu_to_be64 ( seq );
1803
+	hmac_update ( digest, ctx, &seq, sizeof ( seq ) );
1804
+	hmac_update ( digest, ctx, tlshdr, sizeof ( *tlshdr ) );
1805
+}
1806
+
1807
+/**
1808
+ * Update HMAC
1809
+ *
1810
+ * @v cipherspec	Cipher specification
1811
+ * @v ctx		Context
1812
+ * @v data		Data
1813
+ * @v len		Length of data
1814
+ */
1815
+static void tls_hmac_update ( struct tls_cipherspec *cipherspec, void *ctx,
1816
+			      const void *data, size_t len ) {
1817
+	struct digest_algorithm *digest = cipherspec->suite->digest;
1818
+
1819
+	hmac_update ( digest, ctx, data, len );
1820
+}
1821
+
1822
+/**
1823
+ * Finalise HMAC
1824
+ *
1825
+ * @v cipherspec	Cipher specification
1826
+ * @v ctx		Context
1827
+ * @v mac		HMAC to fill in
1828
+ */
1829
+static void tls_hmac_final ( struct tls_cipherspec *cipherspec, void *ctx,
1830
+			     void *hmac ) {
1831
+	struct digest_algorithm *digest = cipherspec->suite->digest;
1832
+
1833
+	hmac_final ( digest, ctx, cipherspec->mac_secret,
1834
+		     &digest->digestsize, hmac );
1835
+}
1836
+
1740 1837
 /**
1741 1838
  * Calculate HMAC
1742 1839
  *
1743
- * @v tls		TLS session
1744 1840
  * @v cipherspec	Cipher specification
1745 1841
  * @v seq		Sequence number
1746 1842
  * @v tlshdr		TLS header
@@ -1748,21 +1844,15 @@ static int tls_new_record ( struct tls_session *tls, unsigned int type,
1748 1844
  * @v len		Length of data
1749 1845
  * @v mac		HMAC to fill in
1750 1846
  */
1751
-static void tls_hmac ( struct tls_session *tls __unused,
1752
-		       struct tls_cipherspec *cipherspec,
1847
+static void tls_hmac ( struct tls_cipherspec *cipherspec,
1753 1848
 		       uint64_t seq, struct tls_header *tlshdr,
1754 1849
 		       const void *data, size_t len, void *hmac ) {
1755 1850
 	struct digest_algorithm *digest = cipherspec->suite->digest;
1756
-	uint8_t digest_ctx[digest->ctxsize];
1851
+	uint8_t ctx[digest->ctxsize];
1757 1852
 
1758
-	hmac_init ( digest, digest_ctx, cipherspec->mac_secret,
1759
-		    &digest->digestsize );
1760
-	seq = cpu_to_be64 ( seq );
1761
-	hmac_update ( digest, digest_ctx, &seq, sizeof ( seq ) );
1762
-	hmac_update ( digest, digest_ctx, tlshdr, sizeof ( *tlshdr ) );
1763
-	hmac_update ( digest, digest_ctx, data, len );
1764
-	hmac_final ( digest, digest_ctx, cipherspec->mac_secret,
1765
-		     &digest->digestsize, hmac );
1853
+	tls_hmac_init ( cipherspec, ctx, seq, tlshdr );
1854
+	tls_hmac_update ( cipherspec, ctx, data, len );
1855
+	tls_hmac_final ( cipherspec, ctx, hmac );
1766 1856
 }
1767 1857
 
1768 1858
 /**
@@ -1877,8 +1967,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
1877 1967
 	plaintext_tlshdr.length = htons ( len );
1878 1968
 
1879 1969
 	/* Calculate MAC */
1880
-	tls_hmac ( tls, cipherspec, tls->tx_seq, &plaintext_tlshdr,
1881
-		   data, len, mac );
1970
+	tls_hmac ( cipherspec, tls->tx_seq, &plaintext_tlshdr, data, len, mac );
1882 1971
 
1883 1972
 	/* Allocate and assemble plaintext struct */
1884 1973
 	if ( is_stream_cipher ( cipher ) ) {
@@ -1945,36 +2034,25 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
1945 2034
  * Split stream-ciphered record into data and MAC portions
1946 2035
  *
1947 2036
  * @v tls		TLS session
1948
- * @v plaintext		Plaintext record
1949
- * @v plaintext_len	Length of record
1950
- * @ret data		Data
1951
- * @ret len		Length of data
1952
- * @ret digest		MAC digest
2037
+ * @v rx_data		List of received data buffers
2038
+ * @v mac		MAC to fill in
1953 2039
  * @ret rc		Return status code
1954 2040
  */
1955 2041
 static int tls_split_stream ( struct tls_session *tls,
1956
-			      void *plaintext, size_t plaintext_len,
1957
-			      void **data, size_t *len, void **digest ) {
1958
-	void *content;
1959
-	size_t content_len;
1960
-	void *mac;
1961
-	size_t mac_len;
1962
-
1963
-	/* Decompose stream-ciphered data */
1964
-	mac_len = tls->rx_cipherspec.suite->digest->digestsize;
1965
-	if ( plaintext_len < mac_len ) {
1966
-		DBGC ( tls, "TLS %p received underlength record\n", tls );
1967
-		DBGC_HD ( tls, plaintext, plaintext_len );
2042
+			      struct list_head *rx_data, void **mac ) {
2043
+	size_t mac_len = tls->rx_cipherspec.suite->digest->digestsize;
2044
+	struct io_buffer *iobuf;
2045
+
2046
+	/* Extract MAC */
2047
+	iobuf = list_last_entry ( rx_data, struct io_buffer, list );
2048
+	assert ( iobuf != NULL );
2049
+	if ( iob_len ( iobuf ) < mac_len ) {
2050
+		DBGC ( tls, "TLS %p received underlength MAC\n", tls );
2051
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
1968 2052
 		return -EINVAL_STREAM;
1969 2053
 	}
1970
-	content_len = ( plaintext_len - mac_len );
1971
-	content = plaintext;
1972
-	mac = ( content + content_len );
1973
-
1974
-	/* Fill in return values */
1975
-	*data = content;
1976
-	*len = content_len;
1977
-	*digest = mac;
2054
+	iob_unput ( iobuf, mac_len );
2055
+	*mac = iobuf->tail;
1978 2056
 
1979 2057
 	return 0;
1980 2058
 }
@@ -1983,65 +2061,56 @@ static int tls_split_stream ( struct tls_session *tls,
1983 2061
  * Split block-ciphered record into data and MAC portions
1984 2062
  *
1985 2063
  * @v tls		TLS session
1986
- * @v plaintext		Plaintext record
1987
- * @v plaintext_len	Length of record
1988
- * @ret data		Data
1989
- * @ret len		Length of data
1990
- * @ret digest		MAC digest
2064
+ * @v rx_data		List of received data buffers
2065
+ * @v mac		MAC to fill in
1991 2066
  * @ret rc		Return status code
1992 2067
  */
1993 2068
 static int tls_split_block ( struct tls_session *tls,
1994
-			     void *plaintext, size_t plaintext_len,
1995
-			     void **data, size_t *len,
1996
-			     void **digest ) {
1997
-	void *iv;
2069
+			     struct list_head *rx_data, void **mac ) {
2070
+	size_t mac_len = tls->rx_cipherspec.suite->digest->digestsize;
2071
+	struct io_buffer *iobuf;
1998 2072
 	size_t iv_len;
1999
-	void *content;
2000
-	size_t content_len;
2001
-	void *mac;
2002
-	size_t mac_len;
2003
-	void *padding;
2073
+	uint8_t *padding_final;
2074
+	uint8_t *padding;
2004 2075
 	size_t padding_len;
2005
-	unsigned int i;
2006
-
2007
-	/* Sanity check */
2008
-	if ( plaintext_len < 1 ) {
2009
-		DBGC ( tls, "TLS %p received underlength record\n", tls );
2010
-		DBGC_HD ( tls, plaintext, plaintext_len );
2011
-		return -EINVAL_BLOCK;
2012
-	}
2013 2076
 
2014 2077
 	/* TLSv1.1 and later use an explicit IV */
2078
+	iobuf = list_first_entry ( rx_data, struct io_buffer, list );
2015 2079
 	iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ?
2016 2080
 		   tls->rx_cipherspec.suite->cipher->blocksize : 0 );
2017
-
2018
-	/* Decompose block-ciphered data */
2019
-	mac_len = tls->rx_cipherspec.suite->digest->digestsize;
2020
-	padding_len = *( ( uint8_t * ) ( plaintext + plaintext_len - 1 ) );
2021
-	if ( plaintext_len < ( iv_len + mac_len + padding_len + 1 ) ) {
2022
-		DBGC ( tls, "TLS %p received underlength record\n", tls );
2023
-		DBGC_HD ( tls, plaintext, plaintext_len );
2081
+	if ( iob_len ( iobuf ) < iv_len ) {
2082
+		DBGC ( tls, "TLS %p received underlength IV\n", tls );
2083
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
2024 2084
 		return -EINVAL_BLOCK;
2025 2085
 	}
2026
-	content_len = ( plaintext_len - iv_len - mac_len - padding_len - 1 );
2027
-	iv = plaintext;
2028
-	content = ( iv + iv_len );
2029
-	mac = ( content + content_len );
2030
-	padding = ( mac + mac_len );
2031
-
2032
-	/* Verify padding bytes */
2033
-	for ( i = 0 ; i < padding_len ; i++ ) {
2034
-		if ( *( ( uint8_t * ) ( padding + i ) ) != padding_len ) {
2086
+	iob_pull ( iobuf, iv_len );
2087
+
2088
+	/* Extract and verify padding */
2089
+	iobuf = list_last_entry ( rx_data, struct io_buffer, list );
2090
+	padding_final = ( iobuf->tail - 1 );
2091
+	padding_len = *padding_final;
2092
+	if ( ( padding_len + 1 ) > iob_len ( iobuf ) ) {
2093
+		DBGC ( tls, "TLS %p received underlength padding\n", tls );
2094
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
2095
+		return -EINVAL_BLOCK;
2096
+	}
2097
+	iob_unput ( iobuf, ( padding_len + 1 ) );
2098
+	for ( padding = iobuf->tail ; padding < padding_final ; padding++ ) {
2099
+		if ( *padding != padding_len ) {
2035 2100
 			DBGC ( tls, "TLS %p received bad padding\n", tls );
2036
-			DBGC_HD ( tls, plaintext, plaintext_len );
2101
+			DBGC_HD ( tls, padding, padding_len );
2037 2102
 			return -EINVAL_PADDING;
2038 2103
 		}
2039 2104
 	}
2040 2105
 
2041
-	/* Fill in return values */
2042
-	*data = content;
2043
-	*len = content_len;
2044
-	*digest = mac;
2106
+	/* Extract MAC */
2107
+	if ( iob_len ( iobuf ) < mac_len ) {
2108
+		DBGC ( tls, "TLS %p received underlength MAC\n", tls );
2109
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
2110
+		return -EINVAL_BLOCK;
2111
+	}
2112
+	iob_unput ( iobuf, mac_len );
2113
+	*mac = iobuf->tail;
2045 2114
 
2046 2115
 	return 0;
2047 2116
 }
@@ -2051,71 +2120,65 @@ static int tls_split_block ( struct tls_session *tls,
2051 2120
  *
2052 2121
  * @v tls		TLS session
2053 2122
  * @v tlshdr		Record header
2054
- * @v ciphertext	Ciphertext record
2123
+ * @v rx_data		List of received data buffers
2055 2124
  * @ret rc		Return status code
2056 2125
  */
2057 2126
 static int tls_new_ciphertext ( struct tls_session *tls,
2058 2127
 				struct tls_header *tlshdr,
2059
-				const void *ciphertext ) {
2128
+				struct list_head *rx_data ) {
2060 2129
 	struct tls_header plaintext_tlshdr;
2061 2130
 	struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
2062 2131
 	struct cipher_algorithm *cipher = cipherspec->suite->cipher;
2063
-	size_t record_len = ntohs ( tlshdr->length );
2064
-	void *plaintext = NULL;
2065
-	void *data;
2066
-	size_t len;
2132
+	struct digest_algorithm *digest = cipherspec->suite->digest;
2133
+	uint8_t ctx[digest->ctxsize];
2134
+	uint8_t verify_mac[digest->digestsize];
2135
+	struct io_buffer *iobuf;
2067 2136
 	void *mac;
2068
-	size_t mac_len = cipherspec->suite->digest->digestsize;
2069
-	uint8_t verify_mac[mac_len];
2137
+	size_t len = 0;
2070 2138
 	int rc;
2071 2139
 
2072
-	/* Allocate buffer for plaintext */
2073
-	plaintext = malloc ( record_len );
2074
-	if ( ! plaintext ) {
2075
-		DBGC ( tls, "TLS %p could not allocate %zd bytes for "
2076
-		       "decryption buffer\n", tls, record_len );
2077
-		rc = -ENOMEM_RX_PLAINTEXT;
2078
-		goto done;
2140
+	/* Decrypt the received data */
2141
+	list_for_each_entry ( iobuf, &tls->rx_data, list ) {
2142
+		cipher_decrypt ( cipher, cipherspec->cipher_ctx,
2143
+				 iobuf->data, iobuf->data, iob_len ( iobuf ) );
2079 2144
 	}
2080 2145
 
2081
-	/* Decrypt the record */
2082
-	cipher_decrypt ( cipher, cipherspec->cipher_ctx,
2083
-			 ciphertext, plaintext, record_len );
2084
-
2085 2146
 	/* Split record into content and MAC */
2086 2147
 	if ( is_stream_cipher ( cipher ) ) {
2087
-		if ( ( rc = tls_split_stream ( tls, plaintext, record_len,
2088
-					       &data, &len, &mac ) ) != 0 )
2089
-			goto done;
2148
+		if ( ( rc = tls_split_stream ( tls, rx_data, &mac ) ) != 0 )
2149
+			return rc;
2090 2150
 	} else {
2091
-		if ( ( rc = tls_split_block ( tls, plaintext, record_len,
2092
-					      &data, &len, &mac ) ) != 0 )
2093
-			goto done;
2151
+		if ( ( rc = tls_split_block ( tls, rx_data, &mac ) ) != 0 )
2152
+			return rc;
2153
+	}
2154
+
2155
+	/* Calculate total length */
2156
+	DBGC2 ( tls, "Received plaintext data:\n" );
2157
+	list_for_each_entry ( iobuf, rx_data, list ) {
2158
+		DBGC2_HD ( tls, iobuf->data, iob_len ( iobuf ) );
2159
+		len += iob_len ( iobuf );
2094 2160
 	}
2095 2161
 
2096 2162
 	/* Verify MAC */
2097 2163
 	plaintext_tlshdr.type = tlshdr->type;
2098 2164
 	plaintext_tlshdr.version = tlshdr->version;
2099 2165
 	plaintext_tlshdr.length = htons ( len );
2100
-	tls_hmac ( tls, cipherspec, tls->rx_seq, &plaintext_tlshdr,
2101
-		   data, len, verify_mac);
2102
-	if ( memcmp ( mac, verify_mac, mac_len ) != 0 ) {
2166
+	tls_hmac_init ( cipherspec, ctx, tls->rx_seq, &plaintext_tlshdr );
2167
+	list_for_each_entry ( iobuf, rx_data, list ) {
2168
+		tls_hmac_update ( cipherspec, ctx, iobuf->data,
2169
+				  iob_len ( iobuf ) );
2170
+	}
2171
+	tls_hmac_final ( cipherspec, ctx, verify_mac );
2172
+	if ( memcmp ( mac, verify_mac, sizeof ( verify_mac ) ) != 0 ) {
2103 2173
 		DBGC ( tls, "TLS %p failed MAC verification\n", tls );
2104
-		DBGC_HD ( tls, plaintext, record_len );
2105
-		goto done;
2174
+		return -EINVAL_MAC;
2106 2175
 	}
2107 2176
 
2108
-	DBGC2 ( tls, "Received plaintext data:\n" );
2109
-	DBGC2_HD ( tls, data, len );
2110
-
2111 2177
 	/* Process plaintext record */
2112
-	if ( ( rc = tls_new_record ( tls, tlshdr->type, data, len ) ) != 0 )
2113
-		goto done;
2178
+	if ( ( rc = tls_new_record ( tls, tlshdr->type, rx_data ) ) != 0 )
2179
+		return rc;
2114 2180
 
2115
-	rc = 0;
2116
- done:
2117
-	free ( plaintext );
2118
-	return rc;
2181
+	return 0;
2119 2182
 }
2120 2183
 
2121 2184
 /******************************************************************************
@@ -2195,20 +2258,61 @@ static struct interface_descriptor tls_plainstream_desc =
2195 2258
  */
2196 2259
 static int tls_newdata_process_header ( struct tls_session *tls ) {
2197 2260
 	size_t data_len = ntohs ( tls->rx_header.length );
2261
+	size_t remaining = data_len;
2262
+	size_t frag_len;
2263
+	struct io_buffer *iobuf;
2264
+	struct io_buffer *tmp;
2265
+	int rc;
2198 2266
 
2199
-	/* Allocate data buffer now that we know the length */
2200
-	assert ( tls->rx_data == NULL );
2201
-	tls->rx_data = malloc ( data_len );
2202
-	if ( ! tls->rx_data ) {
2203
-		DBGC ( tls, "TLS %p could not allocate %zd bytes "
2204
-		       "for receive buffer\n", tls, data_len );
2205
-		return -ENOMEM_RX_DATA;
2267
+	/* Allocate data buffers now that we know the length */
2268
+	assert ( list_empty ( &tls->rx_data ) );
2269
+	while ( remaining ) {
2270
+
2271
+		/* Calculate fragment length.  Ensure that no block is
2272
+		 * smaller than TLS_RX_MIN_BUFSIZE (by increasing the
2273
+		 * allocation length if necessary).
2274
+		 */
2275
+		frag_len = remaining;
2276
+		if ( frag_len > TLS_RX_BUFSIZE )
2277
+			frag_len = TLS_RX_BUFSIZE;
2278
+		remaining -= frag_len;
2279
+		if ( remaining < TLS_RX_MIN_BUFSIZE ) {
2280
+			frag_len += remaining;
2281
+			remaining = 0;
2282
+		}
2283
+
2284
+		/* Allocate buffer */
2285
+		iobuf = alloc_iob_raw ( frag_len, TLS_RX_ALIGN, 0 );
2286
+		if ( ! iobuf ) {
2287
+			DBGC ( tls, "TLS %p could not allocate %zd of %zd "
2288
+			       "bytes for receive buffer\n", tls,
2289
+			       remaining, data_len );
2290
+			rc = -ENOMEM_RX_DATA;
2291
+			goto err;
2292
+		}
2293
+
2294
+		/* Ensure tailroom is exactly what we asked for.  This
2295
+		 * will result in unaligned I/O buffers when the
2296
+		 * fragment length is unaligned, which can happen only
2297
+		 * before we switch to using a block cipher.
2298
+		 */
2299
+		iob_reserve ( iobuf, ( iob_tailroom ( iobuf ) - frag_len ) );
2300
+
2301
+		/* Add I/O buffer to list */
2302
+		list_add_tail ( &iobuf->list, &tls->rx_data );
2206 2303
 	}
2207 2304
 
2208 2305
 	/* Move to data state */
2209 2306
 	tls->rx_state = TLS_RX_DATA;
2210 2307
 
2211 2308
 	return 0;
2309
+
2310
+ err:
2311
+	list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
2312
+		list_del ( &iobuf->list );
2313
+		free_iob ( iobuf );
2314
+	}
2315
+	return rc;
2212 2316
 }
2213 2317
 
2214 2318
 /**
@@ -2218,22 +2322,31 @@ static int tls_newdata_process_header ( struct tls_session *tls ) {
2218 2322
  * @ret rc		Returned status code
2219 2323
  */
2220 2324
 static int tls_newdata_process_data ( struct tls_session *tls ) {
2325
+	struct io_buffer *iobuf;
2221 2326
 	int rc;
2222 2327
 
2328
+	/* Move current buffer to end of list */
2329
+	iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list );
2330
+	list_del ( &iobuf->list );
2331
+	list_add_tail ( &iobuf->list, &tls->rx_data );
2332
+
2333
+	/* Continue receiving data if any space remains */
2334
+	iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list );
2335
+	if ( iob_tailroom ( iobuf ) )
2336
+		return 0;
2337
+
2223 2338
 	/* Process record */
2224 2339
 	if ( ( rc = tls_new_ciphertext ( tls, &tls->rx_header,
2225
-					 tls->rx_data ) ) != 0 )
2340
+					 &tls->rx_data ) ) != 0 )
2226 2341
 		return rc;
2227 2342
 
2228 2343
 	/* Increment RX sequence number */
2229 2344
 	tls->rx_seq += 1;
2230 2345
 
2231
-	/* Free data buffer */
2232
-	free ( tls->rx_data );
2233
-	tls->rx_data = NULL;
2234
-
2235 2346
 	/* Return to header state */
2347
+	assert ( list_empty ( &tls->rx_data ) );
2236 2348
 	tls->rx_state = TLS_RX_HEADER;
2349
+	iob_unput ( &tls->rx_header_iobuf, sizeof ( tls->rx_header ) );
2237 2350
 
2238 2351
 	return 0;
2239 2352
 }
@@ -2250,22 +2363,22 @@ static int tls_cipherstream_deliver ( struct tls_session *tls,
2250 2363
 				      struct io_buffer *iobuf,
2251 2364
 				      struct xfer_metadata *xfer __unused ) {
2252 2365
 	size_t frag_len;
2253
-	void *buf;
2254
-	size_t buf_len;
2255 2366
 	int ( * process ) ( struct tls_session *tls );
2367
+	struct io_buffer *dest;
2256 2368
 	int rc;
2257 2369
 
2258 2370
 	while ( iob_len ( iobuf ) ) {
2371
+
2259 2372
 		/* Select buffer according to current state */
2260 2373
 		switch ( tls->rx_state ) {
2261 2374
 		case TLS_RX_HEADER:
2262
-			buf = &tls->rx_header;
2263
-			buf_len = sizeof ( tls->rx_header );
2375
+			dest = &tls->rx_header_iobuf;
2264 2376
 			process = tls_newdata_process_header;
2265 2377
 			break;
2266 2378
 		case TLS_RX_DATA:
2267
-			buf = tls->rx_data;
2268
-			buf_len = ntohs ( tls->rx_header.length );
2379
+			dest = list_first_entry ( &tls->rx_data,
2380
+						  struct io_buffer, list );
2381
+			assert ( dest != NULL );
2269 2382
 			process = tls_newdata_process_data;
2270 2383
 			break;
2271 2384
 		default:
@@ -2275,20 +2388,18 @@ static int tls_cipherstream_deliver ( struct tls_session *tls,
2275 2388
 		}
2276 2389
 
2277 2390
 		/* Copy data portion to buffer */
2278
-		frag_len = ( buf_len - tls->rx_rcvd );
2279
-		if ( frag_len > iob_len  ( iobuf ) )
2280
-			frag_len = iob_len ( iobuf );
2281
-		memcpy ( ( buf + tls->rx_rcvd ), iobuf->data, frag_len );
2282
-		tls->rx_rcvd += frag_len;
2391
+		frag_len = iob_len ( iobuf );
2392
+		if ( frag_len > iob_tailroom ( dest ) )
2393
+			frag_len = iob_tailroom ( dest );
2394
+		memcpy ( iob_put ( dest, frag_len ), iobuf->data, frag_len );
2283 2395
 		iob_pull ( iobuf, frag_len );
2284 2396
 
2285 2397
 		/* Process data if buffer is now full */
2286
-		if ( tls->rx_rcvd == buf_len ) {
2398
+		if ( iob_tailroom ( dest ) == 0 ) {
2287 2399
 			if ( ( rc = process ( tls ) ) != 0 ) {
2288 2400
 				tls_close ( tls, rc );
2289 2401
 				goto done;
2290 2402
 			}
2291
-			tls->rx_rcvd = 0;
2292 2403
 		}
2293 2404
 	}
2294 2405
 	rc = 0;
@@ -2521,6 +2632,9 @@ int add_tls ( struct interface *xfer, const char *name,
2521 2632
 	tls->handshake_digest = &sha256_algorithm;
2522 2633
 	tls->handshake_ctx = tls->handshake_sha256_ctx;
2523 2634
 	tls->tx_pending = TLS_TX_CLIENT_HELLO;
2635
+	iob_populate ( &tls->rx_header_iobuf, &tls->rx_header, 0,
2636
+		       sizeof ( tls->rx_header ) );
2637
+	INIT_LIST_HEAD ( &tls->rx_data );
2524 2638
 
2525 2639
 	/* Add pending operations for server and client Finished messages */
2526 2640
 	pending_get ( &tls->client_negotiation );

Loading…
Cancel
Save