[git commit] tls: was psAesDecrypt'ing one block too many, trashing buffered data

Denys Vlasenko vda.linux at googlemail.com
Fri Jan 20 17:04:04 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=e7863f394e6a963d1e2c6af77ea064442d3ef594
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

For the first time

printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | ./busybox tls kernel.org

successfully reads entire server response and TLS shutdown.

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/tls.c | 136 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 73 insertions(+), 63 deletions(-)

diff --git a/networking/tls.c b/networking/tls.c
index 2674997..cdce100 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -26,7 +26,7 @@
 //#include "common_bufsiz.h"
 
 #define TLS_DEBUG      1
-#define TLS_DEBUG_HASH 1
+#define TLS_DEBUG_HASH 0
 #define TLS_DEBUG_DER  0
 #define TLS_DEBUG_FIXED_SECRETS 0
 
@@ -42,6 +42,18 @@
 # define dbg_der(...) ((void)0)
 #endif
 
+#if 0
+# define dump_raw_out(...) dump_hex(__VA_ARGS__)
+#else
+# define dump_raw_out(...) ((void)0)
+#endif
+
+#if 1
+# define dump_raw_in(...) dump_hex(__VA_ARGS__)
+#else
+# define dump_raw_in(...) ((void)0)
+#endif
+
 #define RECORD_TYPE_CHANGE_CIPHER_SPEC  20
 #define RECORD_TYPE_ALERT               21
 #define RECORD_TYPE_HANDSHAKE           22
@@ -482,49 +494,11 @@ static void *tls_get_outbuf(tls_state_t *tls, int len)
 	return tls->outbuf + OUTBUF_PFX;
 }
 
-// RFC 5246
-// 6.2.3.1.  Null or Standard Stream Cipher
-//
-// Stream ciphers (including BulkCipherAlgorithm.null; see Appendix A.6)
-// convert TLSCompressed.fragment structures to and from stream
-// TLSCiphertext.fragment structures.
-//
-//    stream-ciphered struct {
-//        opaque content[TLSCompressed.length];
-//        opaque MAC[SecurityParameters.mac_length];
-//    } GenericStreamCipher;
-//
-// The MAC is generated as:
-//    MAC(MAC_write_key, seq_num +
-//                          TLSCompressed.type +
-//                          TLSCompressed.version +
-//                          TLSCompressed.length +
-//                          TLSCompressed.fragment);
-// where "+" denotes concatenation.
-// seq_num
-//    The sequence number for this record.
-// MAC
-//    The MAC algorithm specified by SecurityParameters.mac_algorithm.
-//
-// Note that the MAC is computed before encryption.  The stream cipher
-// encrypts the entire block, including the MAC.
-//...
-// Appendix C.  Cipher Suite Definitions
-//...
-//                         Key      IV   Block
-// Cipher        Type    Material  Size  Size
-// ------------  ------  --------  ----  -----
-// AES_128_CBC   Block      16      16     16
-// AES_256_CBC   Block      32      16     16
-//
-// MAC       Algorithm    mac_length  mac_key_length
-// --------  -----------  ----------  --------------
-// SHA       HMAC-SHA1       20            20
-// SHA256    HMAC-SHA256     32            32
 static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
 {
 	uint8_t *buf = tls->outbuf + OUTBUF_PFX;
 	struct record_hdr *xhdr;
+	uint8_t padding_length;
 
 	xhdr = (void*)(buf - RECHDR_LEN);
 	if (CIPHER_ID != TLS_RSA_WITH_NULL_SHA256)
@@ -549,17 +523,49 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
 
 	size += SHA256_OUTSIZE;
 
+	// RFC 5246
+	// 6.2.3.1.  Null or Standard Stream Cipher
+	//
+	// Stream ciphers (including BulkCipherAlgorithm.null; see Appendix A.6)
+	// convert TLSCompressed.fragment structures to and from stream
+	// TLSCiphertext.fragment structures.
+	//
+	//    stream-ciphered struct {
+	//        opaque content[TLSCompressed.length];
+	//        opaque MAC[SecurityParameters.mac_length];
+	//    } GenericStreamCipher;
+	//
+	// The MAC is generated as:
+	//    MAC(MAC_write_key, seq_num +
+	//                          TLSCompressed.type +
+	//                          TLSCompressed.version +
+	//                          TLSCompressed.length +
+	//                          TLSCompressed.fragment);
+	// where "+" denotes concatenation.
+	// seq_num
+	//    The sequence number for this record.
+	// MAC
+	//    The MAC algorithm specified by SecurityParameters.mac_algorithm.
+	//
+	// Note that the MAC is computed before encryption.  The stream cipher
+	// encrypts the entire block, including the MAC.
+	//...
+	// Appendix C.  Cipher Suite Definitions
+	//...
+	// MAC       Algorithm    mac_length  mac_key_length
+	// --------  -----------  ----------  --------------
+	// SHA       HMAC-SHA1       20            20
+	// SHA256    HMAC-SHA256     32            32
 	if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) {
 		/* No encryption, only signing */
 		xhdr->len16_hi = size >> 8;
 		xhdr->len16_lo = size & 0xff;
-		dump_hex(">> %s\n", xhdr, RECHDR_LEN + size);
+		dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
 		xwrite(tls->fd, xhdr, RECHDR_LEN + size);
 		dbg("wrote %u bytes (NULL crypt, SHA256 hash)\n", size);
 		return;
 	}
 
-	// RFC 5246
 	// 6.2.3.2.  CBC Block Cipher
 	// For block ciphers (such as 3DES or AES), the encryption and MAC
 	// functions convert TLSCompressed.fragment structures to and from block
@@ -595,10 +601,6 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
 	// ------------  ------  --------  ----  -----
 	// AES_128_CBC   Block      16      16     16
 	// AES_256_CBC   Block      32      16     16
-    {
-	psCipherContext_t ctx;
-	uint8_t *p;
-	uint8_t padding_length;
 
 	/* Build IV+content+MAC+padding in outbuf */
 	tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */
@@ -618,22 +620,23 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
 	// If you need no bytes to reach BLOCKSIZE, you have to pad a full
 	// BLOCKSIZE with bytes of value (BLOCKSIZE-1).
 	// It's ok to have more than minimum padding, but we do minimum.
-	p = buf + size;
 	padding_length = (~size) & (AES_BLOCKSIZE - 1);
 	do {
-		*p++ = padding_length;              /* padding */
-		size++;
+		buf[size++] = padding_length;              /* padding */
 	} while ((size & (AES_BLOCKSIZE - 1)) != 0);
 
 	/* Encrypt content+MAC+padding in place */
-	psAesInit(&ctx, buf - AES_BLOCKSIZE, /* IV */
+	{
+		psCipherContext_t ctx;
+		psAesInit(&ctx, buf - AES_BLOCKSIZE, /* IV */
 			tls->client_write_key, sizeof(tls->client_write_key)
-	);
-	psAesEncrypt(&ctx,
+		);
+		psAesEncrypt(&ctx,
 			buf, /* plaintext */
 			buf, /* ciphertext */
 			size
-	);
+		);
+	}
 
 	/* Write out */
 	dbg("writing 5 + %u IV + %u encrypted bytes, padding_length:0x%02x\n",
@@ -641,10 +644,9 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
 	size += AES_BLOCKSIZE;     /* + IV */
 	xhdr->len16_hi = size >> 8;
 	xhdr->len16_lo = size & 0xff;
-	dump_hex(">> %s\n", xhdr, RECHDR_LEN + size);
+	dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
 	xwrite(tls->fd, xhdr, RECHDR_LEN + size);
 	dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
-    }
 }
 
 static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
@@ -658,7 +660,7 @@ static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
 		xhdr->proto_min = TLS_MIN;
 		xhdr->len16_hi = size >> 8;
 		xhdr->len16_lo = size & 0xff;
-		dump_hex(">> %s\n", xhdr, RECHDR_LEN + size);
+		dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
 		xwrite(tls->fd, xhdr, RECHDR_LEN + size);
 		dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
 		/* Handshake hash does not include record headers */
@@ -677,10 +679,13 @@ static int xread_tls_block(tls_state_t *tls)
 
  again:
 	dbg("insize:%u tail:%u\n", tls->insize, tls->tail);
-	if (tls->tail != 0)
-		memmove(tls->inbuf, tls->inbuf + tls->insize, tls->tail);
-	errno = 0;
 	total = tls->tail;
+	if (total != 0) {
+		memmove(tls->inbuf, tls->inbuf + tls->insize, total);
+		//dbg("<< remaining at %d [%d] ", tls->insize, total);
+		//dump_raw_in("<< %s\n", tls->inbuf, total);
+	}
+	errno = 0;
 	target = sizeof(tls->inbuf);
 	for (;;) {
 		if (total >= RECHDR_LEN && target == sizeof(tls->inbuf)) {
@@ -692,7 +697,11 @@ static int xread_tls_block(tls_state_t *tls)
 				tls->insize = total;
 				tls_error_die(tls);
 			}
-			// can also check type/proto_maj/proto_min here
+			/* can also check type/proto_maj/proto_min here */
+			dbg("xhdr type:%d ver:%d.%d len:%d\n",
+				xhdr->type, xhdr->proto_maj, xhdr->proto_min,
+				0x100 * xhdr->len16_hi + xhdr->len16_lo
+			);
 		}
 		/* if total >= target, we have a full packet (and possibly more)... */
 		if (total - target >= 0)
@@ -707,12 +716,13 @@ static int xread_tls_block(tls_state_t *tls)
 			}
 			bb_perror_msg_and_die("short read, have only %d", total);
 		}
-		dbg("read():%d\n", sz);
+		dump_raw_in("<< %s\n", tls->inbuf + total, sz);
 		total += sz;
 	}
 	tls->tail = total - target;
 	tls->insize = target;
-	dbg("new insize:%u tail:%u\n", tls->insize, tls->tail);
+	//dbg("<< stashing at %d [%d] ", tls->insize, tls->tail);
+	//dump_hex("<< %s\n", tls->inbuf + tls->insize, tls->tail);
 
 	sz = target - RECHDR_LEN;
 
@@ -734,7 +744,7 @@ static int xread_tls_block(tls_state_t *tls)
 		psAesDecrypt(&ctx,
 			p + AES_BLOCKSIZE, /* ciphertext */
 			p + AES_BLOCKSIZE, /* plaintext */
-			sz
+			sz - AES_BLOCKSIZE
 		);
 		padding_len = p[sz - 1];
 		dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[AES_BLOCKSIZE], padding_len);


More information about the busybox-cvs mailing list