|
@@ -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 );
|