diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-19 00:20:45 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-19 00:20:45 +0100 |
commit | cccf8e735da9eb62f1de021534ca50255d82e931 (patch) | |
tree | 8a2f9965d8000e507056ebb934686fb8f4161f14 | |
parent | a9e186680668056e2c35ce5a99769a7ff0df44cd (diff) | |
download | busybox-cccf8e735da9eb62f1de021534ca50255d82e931.tar.gz |
tls: teach it to decrypt AES256-encrypted data
This adds decryption only.
There is no MAC verification, code simply throws away MAC.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/tls.c | 73 |
1 files changed, 53 insertions, 20 deletions
diff --git a/networking/tls.c b/networking/tls.c index 6928582df..f3d0bde90 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -181,7 +181,7 @@ typedef struct tls_state { uint8_t master_secret[48]; uint8_t encrypt_on_write; - uint8_t decrypt_on_read; + int min_encrypted_len_on_read; uint8_t client_write_MAC_key[SHA256_OUTSIZE]; uint8_t server_write_MAC_key[SHA256_OUTSIZE]; uint8_t client_write_key[AES256_KEYSIZE]; @@ -634,7 +634,7 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size static int xread_tls_block(tls_state_t *tls) { struct record_hdr *xhdr; - int len; + int sz; int total; int target; @@ -658,24 +658,57 @@ static int xread_tls_block(tls_state_t *tls) /* if total >= target, we have a full packet (and possibly more)... */ if (total - target >= 0) break; - len = safe_read(tls->fd, tls->inbuf + total, sizeof(tls->inbuf) - total); - if (len <= 0) + sz = safe_read(tls->fd, tls->inbuf + total, sizeof(tls->inbuf) - total); + if (sz <= 0) bb_perror_msg_and_die("short read"); - total += len; + total += sz; } tls->tail = total - target; tls->insize = target; - target -= sizeof(*xhdr); + sz = target - sizeof(*xhdr); + + /* Needs to be decrypted? */ + if (tls->min_encrypted_len_on_read) { + psCipherContext_t ctx; + uint8_t *p = tls->inbuf + sizeof(*xhdr); + int padding_len; + + if (sz & (AES_BLOCKSIZE-1) + || sz < tls->min_encrypted_len_on_read + ) { + bb_error_msg_and_die("bad encrypted len:%u", sz); + } + /* Decrypt content+MAC+padding in place */ + psAesInit(&ctx, p, /* IV */ + tls->server_write_key, sizeof(tls->server_write_key) + ); + psAesDecrypt(&ctx, + p + AES_BLOCKSIZE, /* ciphertext */ + p + AES_BLOCKSIZE, /* plaintext */ + sz + ); + padding_len = p[sz - 1]; + dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[AES_BLOCKSIZE], padding_len); + padding_len++; + sz -= AES_BLOCKSIZE + SHA256_OUTSIZE + padding_len; + if (sz < 0) { + bb_error_msg_and_die("bad padding size:%u", padding_len); + } + if (sz != 0) { + /* Skip IV */ + memmove(tls->inbuf + 5, tls->inbuf + 5 + AES_BLOCKSIZE, sz); + } + } /* RFC 5246 is not saying it explicitly, but sha256 hash * in our FINISHED record must include data of incoming packets too! */ if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE) { - sha256_hash_dbg("<< sha256:%s", &tls->handshake_sha256_ctx, tls->inbuf + 5, target); + sha256_hash_dbg("<< sha256:%s", &tls->handshake_sha256_ctx, tls->inbuf + 5, sz); } - dbg("got block len:%u\n", target); - return target; + dbg("got block len:%u\n", sz); + return sz; } /* @@ -1194,9 +1227,6 @@ static void send_change_cipher_spec(tls_state_t *tls) /* Not "xwrite_and_hash": this is not a handshake message */ dbg(">> CHANGE_CIPHER_SPEC\n"); xwrite(tls->fd, rec_CHANGE_CIPHER_SPEC, sizeof(rec_CHANGE_CIPHER_SPEC)); - - /* tls->write_seq64_be = 0; - already is */ - tls->encrypt_on_write = 1; } // 7.4.9. Finished @@ -1335,7 +1365,9 @@ static void tls_handshake(tls_state_t *tls) send_client_key_exchange(tls); send_change_cipher_spec(tls); - /* we now should send encrypted... as soon as we grok AES. */ + /* from now on we should send encrypted */ + /* tls->write_seq64_be = 0; - already is */ + tls->encrypt_on_write = 1; send_client_finished(tls); @@ -1344,8 +1376,8 @@ static void tls_handshake(tls_state_t *tls) if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) tls_error_die(tls); dbg("<< CHANGE_CIPHER_SPEC\n"); - tls->decrypt_on_read = 1; - /* we now should receive encrypted */ + /* all incoming packets now should be encrypted and have IV + MAC + padding */ + tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE; /* Get (encrypted) FINISHED from the server */ len = xread_tls_block(tls); @@ -1356,8 +1388,13 @@ static void tls_handshake(tls_state_t *tls) } // To run a test server using openssl: +// openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 +// +// Unencryped SHA256 example: // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' +// openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL +// openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256 int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tls_main(int argc UNUSED_PARAM, char **argv) @@ -1381,12 +1418,8 @@ int tls_main(int argc UNUSED_PARAM, char **argv) return EXIT_SUCCESS; } - /* Unencryped SHA256 example: - * $ openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' - * $ openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL - * $ openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256 - * s_client says: + * s_client says: write to 0x1d750b0 [0x1e6f153] (99 bytes => 99 (0x63)) 0000 - 16 03 01 005e 01 00005a 0303 [4d ef 5c 82 3e ....^...Z..M.\.> >> ClHello |