tls: was psAesDecrypt'ing one block too many, trashing buffered data

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@googlemail.com>
This commit is contained in:
Denys Vlasenko 2017-01-20 17:59:25 +01:00
parent 6e511393f9
commit e7863f394e

View File

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