mirror of
https://github.com/sheumann/hush.git
synced 2025-01-24 16:30:54 +00:00
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:
parent
6e511393f9
commit
e7863f394e
136
networking/tls.c
136
networking/tls.c
@ -26,7 +26,7 @@
|
|||||||
//#include "common_bufsiz.h"
|
//#include "common_bufsiz.h"
|
||||||
|
|
||||||
#define TLS_DEBUG 1
|
#define TLS_DEBUG 1
|
||||||
#define TLS_DEBUG_HASH 1
|
#define TLS_DEBUG_HASH 0
|
||||||
#define TLS_DEBUG_DER 0
|
#define TLS_DEBUG_DER 0
|
||||||
#define TLS_DEBUG_FIXED_SECRETS 0
|
#define TLS_DEBUG_FIXED_SECRETS 0
|
||||||
|
|
||||||
@ -42,6 +42,18 @@
|
|||||||
# define dbg_der(...) ((void)0)
|
# define dbg_der(...) ((void)0)
|
||||||
#endif
|
#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_CHANGE_CIPHER_SPEC 20
|
||||||
#define RECORD_TYPE_ALERT 21
|
#define RECORD_TYPE_ALERT 21
|
||||||
#define RECORD_TYPE_HANDSHAKE 22
|
#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;
|
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)
|
static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
|
||||||
{
|
{
|
||||||
uint8_t *buf = tls->outbuf + OUTBUF_PFX;
|
uint8_t *buf = tls->outbuf + OUTBUF_PFX;
|
||||||
struct record_hdr *xhdr;
|
struct record_hdr *xhdr;
|
||||||
|
uint8_t padding_length;
|
||||||
|
|
||||||
xhdr = (void*)(buf - RECHDR_LEN);
|
xhdr = (void*)(buf - RECHDR_LEN);
|
||||||
if (CIPHER_ID != TLS_RSA_WITH_NULL_SHA256)
|
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;
|
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) {
|
if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) {
|
||||||
/* No encryption, only signing */
|
/* No encryption, only signing */
|
||||||
xhdr->len16_hi = size >> 8;
|
xhdr->len16_hi = size >> 8;
|
||||||
xhdr->len16_lo = size & 0xff;
|
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);
|
xwrite(tls->fd, xhdr, RECHDR_LEN + size);
|
||||||
dbg("wrote %u bytes (NULL crypt, SHA256 hash)\n", size);
|
dbg("wrote %u bytes (NULL crypt, SHA256 hash)\n", size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RFC 5246
|
|
||||||
// 6.2.3.2. CBC Block Cipher
|
// 6.2.3.2. CBC Block Cipher
|
||||||
// For block ciphers (such as 3DES or AES), the encryption and MAC
|
// For block ciphers (such as 3DES or AES), the encryption and MAC
|
||||||
// functions convert TLSCompressed.fragment structures to and from block
|
// 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_128_CBC Block 16 16 16
|
||||||
// AES_256_CBC Block 32 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 */
|
/* Build IV+content+MAC+padding in outbuf */
|
||||||
tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */
|
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
|
// If you need no bytes to reach BLOCKSIZE, you have to pad a full
|
||||||
// BLOCKSIZE with bytes of value (BLOCKSIZE-1).
|
// BLOCKSIZE with bytes of value (BLOCKSIZE-1).
|
||||||
// It's ok to have more than minimum padding, but we do minimum.
|
// It's ok to have more than minimum padding, but we do minimum.
|
||||||
p = buf + size;
|
|
||||||
padding_length = (~size) & (AES_BLOCKSIZE - 1);
|
padding_length = (~size) & (AES_BLOCKSIZE - 1);
|
||||||
do {
|
do {
|
||||||
*p++ = padding_length; /* padding */
|
buf[size++] = padding_length; /* padding */
|
||||||
size++;
|
|
||||||
} while ((size & (AES_BLOCKSIZE - 1)) != 0);
|
} while ((size & (AES_BLOCKSIZE - 1)) != 0);
|
||||||
|
|
||||||
/* Encrypt content+MAC+padding in place */
|
/* 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)
|
tls->client_write_key, sizeof(tls->client_write_key)
|
||||||
);
|
);
|
||||||
psAesEncrypt(&ctx,
|
psAesEncrypt(&ctx,
|
||||||
buf, /* plaintext */
|
buf, /* plaintext */
|
||||||
buf, /* ciphertext */
|
buf, /* ciphertext */
|
||||||
size
|
size
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* Write out */
|
/* Write out */
|
||||||
dbg("writing 5 + %u IV + %u encrypted bytes, padding_length:0x%02x\n",
|
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 */
|
size += AES_BLOCKSIZE; /* + IV */
|
||||||
xhdr->len16_hi = size >> 8;
|
xhdr->len16_hi = size >> 8;
|
||||||
xhdr->len16_lo = size & 0xff;
|
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);
|
xwrite(tls->fd, xhdr, RECHDR_LEN + size);
|
||||||
dbg("wrote %u bytes\n", (int)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)
|
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->proto_min = TLS_MIN;
|
||||||
xhdr->len16_hi = size >> 8;
|
xhdr->len16_hi = size >> 8;
|
||||||
xhdr->len16_lo = size & 0xff;
|
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);
|
xwrite(tls->fd, xhdr, RECHDR_LEN + size);
|
||||||
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
|
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
|
||||||
/* Handshake hash does not include record headers */
|
/* Handshake hash does not include record headers */
|
||||||
@ -677,10 +679,13 @@ static int xread_tls_block(tls_state_t *tls)
|
|||||||
|
|
||||||
again:
|
again:
|
||||||
dbg("insize:%u tail:%u\n", tls->insize, tls->tail);
|
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;
|
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);
|
target = sizeof(tls->inbuf);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (total >= RECHDR_LEN && target == sizeof(tls->inbuf)) {
|
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->insize = total;
|
||||||
tls_error_die(tls);
|
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, we have a full packet (and possibly more)... */
|
||||||
if (total - target >= 0)
|
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);
|
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;
|
total += sz;
|
||||||
}
|
}
|
||||||
tls->tail = total - target;
|
tls->tail = total - target;
|
||||||
tls->insize = 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;
|
sz = target - RECHDR_LEN;
|
||||||
|
|
||||||
@ -734,7 +744,7 @@ static int xread_tls_block(tls_state_t *tls)
|
|||||||
psAesDecrypt(&ctx,
|
psAesDecrypt(&ctx,
|
||||||
p + AES_BLOCKSIZE, /* ciphertext */
|
p + AES_BLOCKSIZE, /* ciphertext */
|
||||||
p + AES_BLOCKSIZE, /* plaintext */
|
p + AES_BLOCKSIZE, /* plaintext */
|
||||||
sz
|
sz - AES_BLOCKSIZE
|
||||||
);
|
);
|
||||||
padding_len = p[sz - 1];
|
padding_len = p[sz - 1];
|
||||||
dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[AES_BLOCKSIZE], padding_len);
|
dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[AES_BLOCKSIZE], padding_len);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user