]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[tls] Concatenate received non-data records before processing
authorMichael Brown <mcb30@ipxe.org>
Wed, 30 Jan 2013 16:58:17 +0000 (16:58 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 31 Jan 2013 09:59:36 +0000 (09:59 +0000)
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>
src/core/iobuf.c
src/include/ipxe/iobuf.h
src/net/tls.c

index 3f67d2f5ec0861e7456817caf2b6e36ca0448c36..afc91d150873d59edde42233a9fa0e0b9efb840c 100644 (file)
@@ -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;
+}
index 65a8e80da24b2ac2479bc153aa8f2ccddfe18308..b2b0cb4401d7d8e71099ea5007ea71247fbd9f75 100644 (file)
@@ -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 */
index 4ad131c87efda2261f57165bb3aab45ae98ccc7f..5e18f72665cdd5fd56bc272ac64bb6aaa1e29357 100644 (file)
@@ -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 */