diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-18 20:37:24 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-18 20:37:24 +0100 |
commit | b5dfc3dfd69ec20358827f8ecb2a42ca4b290f03 (patch) | |
tree | 33eb3dbcb3fef142cdb55e7f45085a7041c77aec | |
parent | b7e9ae6e9f8b1683774e2a69b943cec31c94f5a2 (diff) |
tls: teach it to send AES256-encrypted data
>> CLIENT_HELLO
wrote 50 bytes
insize:0 tail:0
got block len:74
got HANDSHAKE
<< SERVER_HELLO
insize:79 tail:0
got block len:2397
got HANDSHAKE
<< CERTIFICATE
key bytes:271, first:0x00
server_rsa_pub_key.size:256
insize:2402 tail:0
got block len:4
got HANDSHAKE
<< SERVER_HELLO_DONE
>> CLIENT_KEY_EXCHANGE
wrote 267 bytes
master secret:c51df5b1e3b3f57373cdd8ea28e8ce562059636cf9f585d0b89c7f4bacec97e674d7b91f93e7b500cb64637f240c3b78
client_write_MAC_key:3b0b7e2bab241b629c37eb3a3824f09b39fe71a00876b0c8026dda16ef0d2f82
client_write_key:d36e801470ed2f0a8fc886ac25df57ffbe4265d06e3192122c4ef4df1e32fab2
>> CHANGE_CIPHER_SPEC
from secret: c51df5b1e3b3f57373cdd8ea28e8ce562059636cf9f585d0b89c7f4bacec97e674d7b91f93e7b500cb64637f240c3b78
from labelSeed: 636c69656e742066696e6973686564b22e0e6008b8ee218cc02e4a93e4a42b570535f9b57662e262d43b379d125b69
=> digest: a45bfee8ed6507a2a9920d0c
>> FINISHED
before crypt: 5 hdr + 16 data + 32 hash bytes
writing 5 + 16 IV + 64 encrypted bytes, padding_length:0x0f
wrote 85 bytes
insize:9 tail:0
got block len:1
<< CHANGE_CIPHER_SPEC
insize:6 tail:0
got block len:80
< hdr_type:22 ver:3.3 len:80 type:21 len24:9541723 |1591985b...a3da|
The last line is the server's FINISHED response, encrypted.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/tls.c | 159 |
1 files changed, 148 insertions, 11 deletions
diff --git a/networking/tls.c b/networking/tls.c index 4986c991d..2b1e36110 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -143,14 +143,25 @@ //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE //#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE //#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this? -#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) //#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE //^^^^^^^^^^^^^^^^^^^^^^^ (tested b/c this one doesn't req server certs... no luck) -//test TLS_RSA_WITH_AES_128_CBC_SHA, in tls 1.2 it's mandated to be always supported +//test TLS_RSA_WITH_AES_128_CBC_SHA, in TLS 1.2 it's mandated to be always supported + +// works against "openssl s_server -cipher NULL" +// and against wolfssl-3.9.10-stable/examples/server/server.c: +//#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) +// "works", meaning +// "can send encrypted FINISHED to wolfssl-3.9.10-stable/examples/server/server.c", +// don't yet read its encrypted answers: +#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE enum { SHA256_INSIZE = 64, SHA256_OUTSIZE = 32, + + AES_BLOCKSIZE = 16, + AES128_KEYSIZE = 16, + AES256_KEYSIZE = 32, }; struct record_hdr { @@ -172,6 +183,9 @@ typedef struct tls_state { uint8_t encrypt_on_write; uint8_t decrypt_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]; + uint8_t server_write_key[AES256_KEYSIZE]; // RFC 5246 // sequence number // Each connection state contains a sequence number, which is @@ -208,7 +222,10 @@ typedef struct tls_state { // Since our buffer also contains 5-byte headers, make it a bit bigger: int insize; int tail; - uint8_t inbuf[18*1024]; +//needed? + uint64_t align____; + uint8_t inbuf[20*1024]; + uint8_t outbuf[20*1024]; } tls_state_t; @@ -512,13 +529,114 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size NULL); tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(tls->write_seq64_be)); - xhdr->len16_lo += SHA256_OUTSIZE; - xwrite(tls->fd, buf, size); - xhdr->len16_lo -= SHA256_OUTSIZE; - dbg("wrote %u bytes\n", size); + if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) { + /* No encryption, only signing */ + xhdr->len16_lo += SHA256_OUTSIZE; +//FIXME: overflow into len16_hi? + xwrite(tls->fd, buf, size); + xhdr->len16_lo -= SHA256_OUTSIZE; + dbg("wrote %u bytes\n", size); + + xwrite(tls->fd, mac_hash, sizeof(mac_hash)); + dbg("wrote %u bytes of hash\n", (int)sizeof(mac_hash)); + 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 + // TLSCiphertext.fragment structures. + // struct { + // opaque IV[SecurityParameters.record_iv_length]; + // block-ciphered struct { + // opaque content[TLSCompressed.length]; + // opaque MAC[SecurityParameters.mac_length]; + // uint8 padding[GenericBlockCipher.padding_length]; + // uint8 padding_length; + // }; + // } GenericBlockCipher; + //... + // IV + // The Initialization Vector (IV) SHOULD be chosen at random, and + // MUST be unpredictable. Note that in versions of TLS prior to 1.1, + // there was no IV field (...). For block ciphers, the IV length is + // of length SecurityParameters.record_iv_length, which is equal to the + // SecurityParameters.block_size. + // padding + // Padding that is added to force the length of the plaintext to be + // an integral multiple of the block cipher's block length. + // padding_length + // The padding length MUST be such that the total size of the + // GenericBlockCipher structure is a multiple of the cipher's block + // length. Legal values range from zero to 255, inclusive. + //... + // Appendix C. Cipher Suite Definitions + //... + // Key IV Block + // Cipher Type Material Size Size + // ------------ ------ -------- ---- ----- + // NULL Stream 0 0 N/A + // RC4_128 Stream 16 0 N/A + // 3DES_EDE_CBC Block 24 8 8 + // 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(tls->outbuf, AES_BLOCKSIZE); /* IV */ + p = tls->outbuf + AES_BLOCKSIZE; + size -= sizeof(*xhdr); + dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, sizeof(mac_hash)); + p = mempcpy(p, buf + sizeof(*xhdr), size); /* content */ + p = mempcpy(p, mac_hash, sizeof(mac_hash)); /* MAC */ + size += sizeof(mac_hash); + // RFC is talking nonsense: + // Padding that is added to force the length of the plaintext to be + // an integral multiple of the block cipher's block length. + // WRONG. _padding+padding_length_, not just _padding_, + // pads the data. + // IOW: padding_length is the last byte of padding[] array, + // contrary to what RFC depicts. + // + // What actually happens is that there is always padding. + // If you need one byte to reach BLOCKSIZE, this byte is 0x00. + // If you need two bytes, they are both 0x01. + // If you need three, they are 0x02,0x02,0x02. And so on. + // 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. + padding_length = (~size) & (AES_BLOCKSIZE - 1); + do { + *p++ = padding_length; /* padding */ + size++; + } while ((size & (AES_BLOCKSIZE - 1)) != 0); + + /* Encrypt content+MAC+padding in place */ + psAesInit(&ctx, tls->outbuf, /* IV */ + tls->client_write_key, sizeof(tls->client_write_key) + ); + psAesEncrypt(&ctx, + tls->outbuf + AES_BLOCKSIZE, /* plaintext */ + tls->outbuf + AES_BLOCKSIZE, /* ciphertext */ + size + ); - xwrite(tls->fd, mac_hash, sizeof(mac_hash)); - dbg("wrote %u bytes of hash\n", (int)sizeof(mac_hash)); + /* Write out */ + dbg("writing 5 + %u IV + %u encrypted bytes, padding_length:0x%02x\n", + AES_BLOCKSIZE, size, padding_length); + size += AES_BLOCKSIZE; /* + IV */ + xhdr->len16_hi = size >> 8; + xhdr->len16_lo = size & 0xff; + xwrite(tls->fd, xhdr, sizeof(*xhdr)); + xwrite(tls->fd, tls->outbuf, size); + dbg("wrote %u bytes\n", sizeof(*xhdr) + size); +//restore xhdr->len16_hi = ; +//restore xhdr->len16_lo = ; + } } static int xread_tls_block(tls_state_t *tls) @@ -1048,14 +1166,30 @@ static void send_client_key_exchange(tls_state_t *tls) // server_write_key[SecurityParameters.enc_key_length] // client_write_IV[SecurityParameters.fixed_iv_length] // server_write_IV[SecurityParameters.fixed_iv_length] + + + // Key IV Block + // Cipher Type Material Size Size + // ------------ ------ -------- ---- ----- + // NULL Stream 0 0 N/A + // RC4_128 Stream 16 0 N/A + // 3DES_EDE_CBC Block 24 8 8 + // AES_128_CBC Block 16 16 16 + // AES_256_CBC Block 32 16 16 + { uint8_t tmp64[64]; - /* make server_rand32 + client_rand32 */ + + /* make "server_rand32 + client_rand32" */ memcpy(&tmp64[0] , &tls->client_and_server_rand32[32], 32); memcpy(&tmp64[32], &tls->client_and_server_rand32[0] , 32); prf_hmac_sha256( - tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key), + tls->client_write_MAC_key, 2 * (SHA256_OUTSIZE + AES256_KEYSIZE), + // also fills: + // server_write_MAC_key[SHA256_OUTSIZE] + // client_write_key[AES256_KEYSIZE] + // server_write_key[AES256_KEYSIZE] tls->master_secret, sizeof(tls->master_secret), "key expansion", tmp64, 64 @@ -1063,6 +1197,9 @@ static void send_client_key_exchange(tls_state_t *tls) dump_hex("client_write_MAC_key:%s\n", tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key) ); + dump_hex("client_write_key:%s\n", + tls->client_write_key, sizeof(tls->client_write_key) + ); } } |