summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown2013-01-30 17:58:17 +0100
committerMichael Brown2013-01-31 10:59:36 +0100
commit0acc52519de732f4f010e1029e1308cee825eaed (patch)
treefec736bad239f85a595b08e7251a4808eae35cbb /src
parent[src] Fix spelling in comments, debug messages and local variable names (diff)
downloadipxe-0acc52519de732f4f010e1029e1308cee825eaed.tar.gz
ipxe-0acc52519de732f4f010e1029e1308cee825eaed.tar.xz
ipxe-0acc52519de732f4f010e1029e1308cee825eaed.zip
[tls] Concatenate received non-data records before processing
Allow non-data records to be split across multiple received I/O buffers, to accommodate large certificate chains. Reported-by: Nicola Volpini <Nicola.Volpini@kambi.com> Tested-by: Nicola Volpini <Nicola.Volpini@kambi.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r--src/core/iobuf.c42
-rw-r--r--src/include/ipxe/iobuf.h1
-rw-r--r--src/net/tls.c22
3 files changed, 53 insertions, 12 deletions
diff --git a/src/core/iobuf.c b/src/core/iobuf.c
index 3f67d2f5..afc91d15 100644
--- a/src/core/iobuf.c
+++ b/src/core/iobuf.c
@@ -158,3 +158,45 @@ int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
return -ENOBUFS;
}
+/**
+ * Concatenate I/O buffers into a single buffer
+ *
+ * @v list List of I/O buffers
+ * @ret iobuf Concatenated I/O buffer, or NULL on allocation failure
+ *
+ * After a successful concatenation, the list will be empty.
+ */
+struct io_buffer * iob_concatenate ( struct list_head *list ) {
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+ struct io_buffer *concatenated;
+ size_t len = 0;
+
+ /* If the list contains only a single entry, avoid an
+ * unnecessary additional allocation.
+ */
+ if ( list_is_singular ( list ) ) {
+ iobuf = list_first_entry ( list, struct io_buffer, list );
+ INIT_LIST_HEAD ( list );
+ return iobuf;
+ }
+
+ /* Calculate total length */
+ list_for_each_entry ( iobuf, list, list )
+ len += iob_len ( iobuf );
+
+ /* Allocate new I/O buffer */
+ concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
+ if ( ! concatenated )
+ return NULL;
+
+ /* Move data to new I/O buffer */
+ list_for_each_entry_safe ( iobuf, tmp, list, list ) {
+ list_del ( &iobuf->list );
+ memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
+ iobuf->data, iob_len ( iobuf ) );
+ free_iob ( iobuf );
+ }
+
+ return concatenated;
+}
diff --git a/src/include/ipxe/iobuf.h b/src/include/ipxe/iobuf.h
index 65a8e80d..b2b0cb44 100644
--- a/src/include/ipxe/iobuf.h
+++ b/src/include/ipxe/iobuf.h
@@ -216,5 +216,6 @@ extern struct io_buffer * __malloc alloc_iob ( size_t len );
extern void free_iob ( struct io_buffer *iobuf );
extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
+extern struct io_buffer * iob_concatenate ( struct list_head *list );
#endif /* _IPXE_IOBUF_H */
diff --git a/src/net/tls.c b/src/net/tls.c
index 4ad131c8..5e18f726 100644
--- a/src/net/tls.c
+++ b/src/net/tls.c
@@ -105,10 +105,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_EINVAL_MAC \
__einfo_uniqify ( EINFO_EINVAL, 0x0d, \
"Invalid MAC" )
-#define EINVAL_NON_DATA __einfo_error ( EINFO_EINVAL_NON_DATA )
-#define EINFO_EINVAL_NON_DATA \
- __einfo_uniqify ( EINFO_EINVAL, 0x0e, \
- "Overlength non-data record" )
#define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
#define EINFO_EIO_ALERT \
__einfo_uniqify ( EINFO_EINVAL, 0x01, \
@@ -137,6 +133,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_ENOMEM_RX_DATA \
__einfo_uniqify ( EINFO_ENOMEM, 0x07, \
"Not enough space for received data" )
+#define ENOMEM_RX_CONCAT __einfo_error ( EINFO_ENOMEM_RX_CONCAT )
+#define EINFO_ENOMEM_RX_CONCAT \
+ __einfo_uniqify ( EINFO_ENOMEM, 0x08, \
+ "Not enough space to concatenate received data" )
#define ENOTSUP_CIPHER __einfo_error ( EINFO_ENOTSUP_CIPHER )
#define EINFO_ENOTSUP_CIPHER \
__einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
@@ -1743,14 +1743,12 @@ static int tls_new_record ( struct tls_session *tls, unsigned int type,
return 0;
}
- /* For all other records, fail unless we have exactly one I/O buffer */
- iobuf = list_first_entry ( rx_data, struct io_buffer, list );
- assert ( iobuf != NULL );
- list_del ( &iobuf->list );
- if ( ! list_empty ( rx_data ) ) {
- DBGC ( tls, "TLS %p overlength non-data record\n", tls );
- free_iob ( iobuf );
- return -EINVAL_NON_DATA;
+ /* For all other records, merge into a single I/O buffer */
+ iobuf = iob_concatenate ( rx_data );
+ if ( ! iobuf ) {
+ DBGC ( tls, "TLS %p could not concatenate non-data record "
+ "type %d\n", tls, type );
+ return -ENOMEM_RX_CONCAT;
}
/* Determine handler */