tls: add support for TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 cipher
function old new delta xwrite_encrypted 209 605 +396 GHASH - 395 +395 aes_encrypt_1 - 382 +382 GMULT - 192 +192 tls_xread_record 489 659 +170 aes_encrypt_one_block - 65 +65 aesgcm_setkey - 58 +58 FlattenSzInBits - 52 +52 tls_handshake 1890 1941 +51 xwrite_and_update_handshake_hash 46 81 +35 xorbuf - 24 +24 aes_setkey - 16 +16 psRsaEncryptPub 413 421 +8 stty_main 1221 1227 +6 ssl_client_main 138 143 +5 next_token 841 845 +4 spawn_ssl_client 218 219 +1 volume_id_probe_hfs_hfsplus 564 563 -1 read_package_field 232 230 -2 i2cdetect_main 674 672 -2 fail_hunk 139 136 -3 parse_expr 891 883 -8 curve25519 802 793 -9 aes_cbc_decrypt 971 958 -13 xwrite_handshake_record 43 - -43 aes_cbc_encrypt 644 172 -472 ------------------------------------------------------------------------------ (add/remove: 9/1 grow/shrink: 9/8 up/down: 1860/-553) Total: 1307 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
03ad7ae081
commit
83e5c627e1
@ -736,10 +736,17 @@ struct hostent *xgethostbyname(const char *name) FAST_FUNC;
|
|||||||
// + inet_common.c has additional IPv4-only stuff
|
// + inet_common.c has additional IPv4-only stuff
|
||||||
|
|
||||||
|
|
||||||
|
struct tls_aes {
|
||||||
|
uint32_t key[60];
|
||||||
|
unsigned rounds;
|
||||||
|
};
|
||||||
#define TLS_MAX_MAC_SIZE 32
|
#define TLS_MAX_MAC_SIZE 32
|
||||||
#define TLS_MAX_KEY_SIZE 32
|
#define TLS_MAX_KEY_SIZE 32
|
||||||
|
#define TLS_MAX_IV_SIZE 4
|
||||||
struct tls_handshake_data; /* opaque */
|
struct tls_handshake_data; /* opaque */
|
||||||
typedef struct tls_state {
|
typedef struct tls_state {
|
||||||
|
unsigned flags;
|
||||||
|
|
||||||
int ofd;
|
int ofd;
|
||||||
int ifd;
|
int ifd;
|
||||||
|
|
||||||
@ -748,6 +755,7 @@ typedef struct tls_state {
|
|||||||
uint8_t encrypt_on_write;
|
uint8_t encrypt_on_write;
|
||||||
unsigned MAC_size;
|
unsigned MAC_size;
|
||||||
unsigned key_size;
|
unsigned key_size;
|
||||||
|
unsigned IV_size;
|
||||||
|
|
||||||
uint8_t *outbuf;
|
uint8_t *outbuf;
|
||||||
int outbuf_size;
|
int outbuf_size;
|
||||||
@ -769,12 +777,21 @@ typedef struct tls_state {
|
|||||||
/*uint64_t read_seq64_be;*/
|
/*uint64_t read_seq64_be;*/
|
||||||
uint64_t write_seq64_be;
|
uint64_t write_seq64_be;
|
||||||
|
|
||||||
|
/*uint8_t *server_write_MAC_key;*/
|
||||||
uint8_t *client_write_key;
|
uint8_t *client_write_key;
|
||||||
uint8_t *server_write_key;
|
uint8_t *server_write_key;
|
||||||
|
uint8_t *client_write_IV;
|
||||||
|
uint8_t *server_write_IV;
|
||||||
uint8_t client_write_MAC_key[TLS_MAX_MAC_SIZE];
|
uint8_t client_write_MAC_key[TLS_MAX_MAC_SIZE];
|
||||||
uint8_t server_write_MAC_k__[TLS_MAX_MAC_SIZE];
|
uint8_t server_write_MAC_k__[TLS_MAX_MAC_SIZE];
|
||||||
uint8_t client_write_k__[TLS_MAX_KEY_SIZE];
|
uint8_t client_write_k__[TLS_MAX_KEY_SIZE];
|
||||||
uint8_t server_write_k__[TLS_MAX_KEY_SIZE];
|
uint8_t server_write_k__[TLS_MAX_KEY_SIZE];
|
||||||
|
uint8_t client_write_I_[TLS_MAX_IV_SIZE];
|
||||||
|
uint8_t server_write_I_[TLS_MAX_IV_SIZE];
|
||||||
|
|
||||||
|
struct tls_aes aes_encrypt;
|
||||||
|
struct tls_aes aes_decrypt;
|
||||||
|
uint8_t H[16]; //used by AES_GCM
|
||||||
} tls_state_t;
|
} tls_state_t;
|
||||||
|
|
||||||
static inline tls_state_t *new_tls_state(void)
|
static inline tls_state_t *new_tls_state(void)
|
||||||
|
306
networking/tls.c
306
networking/tls.c
@ -13,16 +13,17 @@
|
|||||||
//kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o
|
//kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o
|
||||||
//kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o
|
//kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o
|
||||||
//kbuild:lib-$(CONFIG_TLS) += tls_aes.o
|
//kbuild:lib-$(CONFIG_TLS) += tls_aes.o
|
||||||
|
//kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o
|
||||||
//kbuild:lib-$(CONFIG_TLS) += tls_rsa.o
|
//kbuild:lib-$(CONFIG_TLS) += tls_rsa.o
|
||||||
//kbuild:lib-$(CONFIG_TLS) += tls_fe.o
|
//kbuild:lib-$(CONFIG_TLS) += tls_fe.o
|
||||||
////kbuild:lib-$(CONFIG_TLS) += tls_aes_gcm.o
|
|
||||||
|
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
|
||||||
//Tested against kernel.org:
|
|
||||||
//TLS 1.2
|
//TLS 1.2
|
||||||
#define TLS_MAJ 3
|
#define TLS_MAJ 3
|
||||||
#define TLS_MIN 3
|
#define TLS_MIN 3
|
||||||
|
|
||||||
|
//Tested against kernel.org:
|
||||||
//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box
|
//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box
|
||||||
//#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE
|
//#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE
|
||||||
//#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE
|
//#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE
|
||||||
@ -36,7 +37,7 @@
|
|||||||
//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
|
//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
|
||||||
//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE
|
//#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_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_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE
|
||||||
|
|
||||||
// works against "openssl s_server -cipher NULL"
|
// works against "openssl s_server -cipher NULL"
|
||||||
// and against wolfssl-3.9.10-stable/examples/server/server.c:
|
// and against wolfssl-3.9.10-stable/examples/server/server.c:
|
||||||
@ -60,6 +61,11 @@
|
|||||||
// bug #11456: host is.gd accepts only ECDHE-ECDSA-foo (the simplest which works: ECDHE-ECDSA-AES128-SHA 0xC009)
|
// bug #11456: host is.gd accepts only ECDHE-ECDSA-foo (the simplest which works: ECDHE-ECDSA-AES128-SHA 0xC009)
|
||||||
#define CIPHER_ID3 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
#define CIPHER_ID3 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
||||||
|
|
||||||
|
// ftp.openbsd.org only supports ECDHE-RSA-AESnnn-GCM-SHAnnn or ECDHE-RSA-CHACHA20-POLY1305
|
||||||
|
#define CIPHER_ID4 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
|
|
||||||
|
#define NUM_CIPHERS 4
|
||||||
|
|
||||||
|
|
||||||
#define TLS_DEBUG 0
|
#define TLS_DEBUG 0
|
||||||
#define TLS_DEBUG_HASH 0
|
#define TLS_DEBUG_HASH 0
|
||||||
@ -207,7 +213,6 @@ enum {
|
|||||||
SHA1_OUTSIZE = 20,
|
SHA1_OUTSIZE = 20,
|
||||||
SHA256_OUTSIZE = 32,
|
SHA256_OUTSIZE = 32,
|
||||||
|
|
||||||
AES_BLOCKSIZE = 16,
|
|
||||||
AES128_KEYSIZE = 16,
|
AES128_KEYSIZE = 16,
|
||||||
AES256_KEYSIZE = 32,
|
AES256_KEYSIZE = 32,
|
||||||
|
|
||||||
@ -216,7 +221,7 @@ enum {
|
|||||||
RECHDR_LEN = 5,
|
RECHDR_LEN = 5,
|
||||||
|
|
||||||
/* 8 = 3+5. 3 extra bytes result in record data being 32-bit aligned */
|
/* 8 = 3+5. 3 extra bytes result in record data being 32-bit aligned */
|
||||||
OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */
|
OUTBUF_PFX = 8 + AES_BLOCK_SIZE, /* header + IV */
|
||||||
OUTBUF_SFX = TLS_MAX_MAC_SIZE + TLS_MAX_CRYPTBLOCK_SIZE, /* MAC + padding */
|
OUTBUF_SFX = TLS_MAX_MAC_SIZE + TLS_MAX_CRYPTBLOCK_SIZE, /* MAC + padding */
|
||||||
|
|
||||||
// RFC 5246
|
// RFC 5246
|
||||||
@ -263,8 +268,11 @@ struct record_hdr {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_ALG_RSA,
|
NEED_EC_KEY = 1 << 0,
|
||||||
KEY_ALG_ECDSA,
|
GOT_CERT_RSA_KEY_ALG = 1 << 1,
|
||||||
|
GOT_CERT_ECDSA_KEY_ALG = 1 << 2,
|
||||||
|
GOT_EC_KEY = 1 << 3,
|
||||||
|
ENCRYPTION_AESGCM = 1 << 4,
|
||||||
};
|
};
|
||||||
struct tls_handshake_data {
|
struct tls_handshake_data {
|
||||||
/* In bbox, md5/sha1/sha256 ctx's are the same structure */
|
/* In bbox, md5/sha1/sha256 ctx's are the same structure */
|
||||||
@ -273,14 +281,14 @@ struct tls_handshake_data {
|
|||||||
uint8_t client_and_server_rand32[2 * 32];
|
uint8_t client_and_server_rand32[2 * 32];
|
||||||
uint8_t master_secret[48];
|
uint8_t master_secret[48];
|
||||||
|
|
||||||
smallint key_alg;
|
|
||||||
//TODO: store just the DER key here, parse/use/delete it when sending client key
|
//TODO: store just the DER key here, parse/use/delete it when sending client key
|
||||||
//this way it will stay key type agnostic here.
|
//this way it will stay key type agnostic here.
|
||||||
psRsaKey_t server_rsa_pub_key;
|
psRsaKey_t server_rsa_pub_key;
|
||||||
uint8_t ecc_pub_key32[32];
|
uint8_t ecc_pub_key32[32];
|
||||||
|
|
||||||
unsigned saved_client_hello_size;
|
/* HANDSHAKE HASH: */
|
||||||
uint8_t saved_client_hello[1];
|
//unsigned saved_client_hello_size;
|
||||||
|
//uint8_t saved_client_hello[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -609,7 +617,7 @@ static void *tls_get_zeroed_outbuf(tls_state_t *tls, int len)
|
|||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
|
static void xwrite_encrypted_and_hmac_signed(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;
|
||||||
@ -619,7 +627,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
|
|||||||
if (CIPHER_ID1 != TLS_RSA_WITH_NULL_SHA256 /* if "no encryption" can't be selected */
|
if (CIPHER_ID1 != TLS_RSA_WITH_NULL_SHA256 /* if "no encryption" can't be selected */
|
||||||
|| tls->cipher_id != TLS_RSA_WITH_NULL_SHA256 /* or if it wasn't selected */
|
|| tls->cipher_id != TLS_RSA_WITH_NULL_SHA256 /* or if it wasn't selected */
|
||||||
) {
|
) {
|
||||||
xhdr = (void*)(buf - RECHDR_LEN - AES_BLOCKSIZE); /* place for IV */
|
xhdr = (void*)(buf - RECHDR_LEN - AES_BLOCK_SIZE); /* place for IV */
|
||||||
}
|
}
|
||||||
|
|
||||||
xhdr->type = type;
|
xhdr->type = type;
|
||||||
@ -722,7 +730,7 @@ 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
|
||||||
|
|
||||||
tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */
|
tls_get_random(buf - AES_BLOCK_SIZE, AES_BLOCK_SIZE); /* IV */
|
||||||
dbg("before crypt: 5 hdr + %u data + %u hash bytes\n",
|
dbg("before crypt: 5 hdr + %u data + %u hash bytes\n",
|
||||||
size - tls->MAC_size, tls->MAC_size);
|
size - tls->MAC_size, tls->MAC_size);
|
||||||
|
|
||||||
@ -742,23 +750,24 @@ 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.
|
||||||
padding_length = (~size) & (AES_BLOCKSIZE - 1);
|
padding_length = (~size) & (AES_BLOCK_SIZE - 1);
|
||||||
do {
|
do {
|
||||||
buf[size++] = padding_length; /* padding */
|
buf[size++] = padding_length; /* padding */
|
||||||
} while ((size & (AES_BLOCKSIZE - 1)) != 0);
|
} while ((size & (AES_BLOCK_SIZE - 1)) != 0);
|
||||||
|
|
||||||
/* Encrypt content+MAC+padding in place */
|
/* Encrypt content+MAC+padding in place */
|
||||||
|
//optimize key setup
|
||||||
aes_cbc_encrypt(
|
aes_cbc_encrypt(
|
||||||
tls->client_write_key, tls->key_size, /* selects 128/256 */
|
tls->client_write_key, tls->key_size, /* selects 128/256 */
|
||||||
buf - AES_BLOCKSIZE, /* IV */
|
buf - AES_BLOCK_SIZE, /* IV */
|
||||||
buf, size, /* plaintext */
|
buf, size, /* plaintext */
|
||||||
buf /* ciphertext */
|
buf /* ciphertext */
|
||||||
);
|
);
|
||||||
|
|
||||||
/* 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",
|
||||||
AES_BLOCKSIZE, size, padding_length);
|
AES_BLOCK_SIZE, size, padding_length);
|
||||||
size += AES_BLOCKSIZE; /* + IV */
|
size += AES_BLOCK_SIZE; /* + IV */
|
||||||
xhdr->len16_hi = size >> 8;
|
xhdr->len16_hi = size >> 8;
|
||||||
xhdr->len16_lo = size & 0xff;
|
xhdr->len16_lo = size & 0xff;
|
||||||
dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
|
dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
|
||||||
@ -766,9 +775,98 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
|
|||||||
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
|
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Example how GCM encryption combines nonce, aad, input and generates
|
||||||
|
* "header | exp_nonce | encrypted output | tag":
|
||||||
|
* nonce:0d 6a 26 31 00 00 00 00 00 00 00 01 (implicit 4 bytes (derived from master secret), then explicit 8 bytes)
|
||||||
|
* aad: 00 00 00 00 00 00 00 01 17 03 03 00 1c
|
||||||
|
* in: 47 45 54 20 2f 69 6e 64 65 78 2e 68 74 6d 6c 20 48 54 54 50 2f 31 2e 30 0d 0a 0d 0a "GET /index.html HTTP/1.0\r\n\r\n" (0x1c bytes)
|
||||||
|
* out: f7 8a b2 8f 78 0e f6 d5 76 17 2e b5 6d 46 59 56 8b 46 9f 0b d9 2c 35 28 13 66 19 be
|
||||||
|
* tag: c2 86 ce 4a 50 4a d0 aa 50 b3 76 5c 49 2a 3f 33
|
||||||
|
* sent: 17 03 03 00 34|00 00 00 00 00 00 00 01|f7 8a b2 8f 78 0e f6 d5 76 17 2e b5 6d 46 59 56 8b 46 9f 0b d9 2c 35 28 13 66 19 be|c2 86 ce 4a 50 4a d0 aa 50 b3 76 5c 49 2a 3f 33
|
||||||
|
* .............................................^^ buf points here
|
||||||
|
*/
|
||||||
|
static void xwrite_encrypted_aesgcm(tls_state_t *tls, unsigned size, unsigned type)
|
||||||
|
{
|
||||||
|
//go for [16]
|
||||||
|
uint8_t aad[13];
|
||||||
|
uint8_t nonce[12 + 4]; /* +4 creates space for AES block counter */
|
||||||
|
uint8_t scratch[AES_BLOCK_SIZE]; //[16]
|
||||||
|
uint8_t authtag[AES_BLOCK_SIZE]; //[16]
|
||||||
|
uint8_t *buf;
|
||||||
|
struct record_hdr *xhdr;
|
||||||
|
unsigned remaining;
|
||||||
|
unsigned cnt;
|
||||||
|
|
||||||
|
buf = tls->outbuf + OUTBUF_PFX; /* see above for the byte it points to */
|
||||||
|
dump_hex("xwrite_encrypted_aesgcm plaintext:%s\n", buf, size);
|
||||||
|
|
||||||
|
xhdr = (void*)(buf - 8 - RECHDR_LEN);
|
||||||
|
xhdr->type = type; /* do it here so that "type" param no longer used */
|
||||||
|
|
||||||
|
aad[8] = type;
|
||||||
|
aad[9] = TLS_MAJ;
|
||||||
|
aad[10] = TLS_MIN;
|
||||||
|
aad[11] = size >> 8;
|
||||||
|
aad[12] = size & 0xff;
|
||||||
|
|
||||||
|
memcpy(nonce, tls->client_write_IV, 4);
|
||||||
|
memcpy(nonce + 4, &tls->write_seq64_be, 8);
|
||||||
|
memcpy(aad, &tls->write_seq64_be, 8);
|
||||||
|
memcpy(buf - 8, &tls->write_seq64_be, 8);
|
||||||
|
//optimize
|
||||||
|
/* seq64 is not used later in this func, can increment here */
|
||||||
|
tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(tls->write_seq64_be));
|
||||||
|
|
||||||
|
#define COUNTER(v) (*(uint32_t*)(v + 12))
|
||||||
|
|
||||||
|
cnt = 1;
|
||||||
|
remaining = size;
|
||||||
|
while (remaining != 0) {
|
||||||
|
unsigned n;
|
||||||
|
|
||||||
|
cnt++;
|
||||||
|
COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */
|
||||||
|
aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch);
|
||||||
|
n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining;
|
||||||
|
xorbuf(buf, scratch, n);
|
||||||
|
buf += n;
|
||||||
|
remaining -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//optimize fixed sizes
|
||||||
|
aesgcm_GHASH(tls->H, aad, sizeof(aad), tls->outbuf + OUTBUF_PFX, size, authtag, sizeof(authtag));
|
||||||
|
COUNTER(nonce) = htonl(1);
|
||||||
|
aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch);
|
||||||
|
xorbuf(authtag, scratch, sizeof(authtag));
|
||||||
|
|
||||||
|
memcpy(buf, authtag, sizeof(authtag));
|
||||||
|
#undef COUNTER
|
||||||
|
|
||||||
|
/* Write out */
|
||||||
|
xhdr = (void*)(tls->outbuf + OUTBUF_PFX - 8 - RECHDR_LEN);
|
||||||
|
size += 8 + sizeof(authtag);
|
||||||
|
/*xhdr->type = type; - already is */
|
||||||
|
xhdr->proto_maj = TLS_MAJ;
|
||||||
|
xhdr->proto_min = TLS_MIN;
|
||||||
|
xhdr->len16_hi = size >> 8;
|
||||||
|
xhdr->len16_lo = size & 0xff;
|
||||||
|
size += RECHDR_LEN;
|
||||||
|
dump_raw_out(">> %s\n", xhdr, size);
|
||||||
|
xwrite(tls->ofd, xhdr, size);
|
||||||
|
dbg("wrote %u bytes\n", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
|
||||||
|
{
|
||||||
|
if (!(tls->flags & ENCRYPTION_AESGCM)) {
|
||||||
|
xwrite_encrypted_and_hmac_signed(tls, size, type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xwrite_encrypted_aesgcm(tls, size, type);
|
||||||
|
}
|
||||||
|
|
||||||
static void xwrite_handshake_record(tls_state_t *tls, unsigned size)
|
static void xwrite_handshake_record(tls_state_t *tls, unsigned size)
|
||||||
{
|
{
|
||||||
//if (!tls->encrypt_on_write) {
|
|
||||||
uint8_t *buf = tls->outbuf + OUTBUF_PFX;
|
uint8_t *buf = tls->outbuf + OUTBUF_PFX;
|
||||||
struct record_hdr *xhdr = (void*)(buf - RECHDR_LEN);
|
struct record_hdr *xhdr = (void*)(buf - RECHDR_LEN);
|
||||||
|
|
||||||
@ -780,9 +878,6 @@ static void xwrite_handshake_record(tls_state_t *tls, unsigned size)
|
|||||||
dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
|
dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
|
||||||
xwrite(tls->ofd, xhdr, RECHDR_LEN + size);
|
xwrite(tls->ofd, xhdr, RECHDR_LEN + size);
|
||||||
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
|
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
//xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -826,6 +921,52 @@ static const char *alert_text(int code)
|
|||||||
return itoa(code);
|
return itoa(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tls_aesgcm_decrypt(tls_state_t *tls, uint8_t *buf, int size)
|
||||||
|
{
|
||||||
|
//go for [16]
|
||||||
|
//uint8_t aad[13];
|
||||||
|
uint8_t nonce[12 + 4]; /* +4 creates space for AES block counter */
|
||||||
|
uint8_t scratch[AES_BLOCK_SIZE]; //[16]
|
||||||
|
//uint8_t authtag[AES_BLOCK_SIZE]; //[16]
|
||||||
|
unsigned remaining;
|
||||||
|
unsigned cnt;
|
||||||
|
|
||||||
|
//aad[8] = type;
|
||||||
|
//aad[9] = TLS_MAJ;
|
||||||
|
//aad[10] = TLS_MIN;
|
||||||
|
//aad[11] = size >> 8;
|
||||||
|
//aad[12] = size & 0xff;
|
||||||
|
|
||||||
|
memcpy(nonce, tls->server_write_IV, 4);
|
||||||
|
memcpy(nonce + 4, buf, 8);
|
||||||
|
buf += 8;
|
||||||
|
|
||||||
|
#define COUNTER(v) (*(uint32_t*)(v + 12))
|
||||||
|
|
||||||
|
cnt = 1;
|
||||||
|
remaining = size;
|
||||||
|
while (remaining != 0) {
|
||||||
|
unsigned n;
|
||||||
|
|
||||||
|
cnt++;
|
||||||
|
COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */
|
||||||
|
aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch);
|
||||||
|
n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining;
|
||||||
|
xorbuf(buf, scratch, n);
|
||||||
|
buf += n;
|
||||||
|
remaining -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
////optimize fixed sizes
|
||||||
|
//aesgcm_GHASH(tls->H, aad, sizeof(aad), tls->outbuf + OUTBUF_PFX, size, authtag, sizeof(authtag));
|
||||||
|
//COUNTER(nonce) = htonl(1);
|
||||||
|
//aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch);
|
||||||
|
//xorbuf(authtag, scratch, sizeof(authtag));
|
||||||
|
|
||||||
|
//memcmp(buf, authtag, sizeof(authtag)) || DIE("HASH DOES NOT MATCH!");
|
||||||
|
#undef COUNTER
|
||||||
|
}
|
||||||
|
|
||||||
static int tls_xread_record(tls_state_t *tls, const char *expected)
|
static int tls_xread_record(tls_state_t *tls, const char *expected)
|
||||||
{
|
{
|
||||||
struct record_hdr *xhdr;
|
struct record_hdr *xhdr;
|
||||||
@ -896,35 +1037,45 @@ static int tls_xread_record(tls_state_t *tls, const char *expected)
|
|||||||
sz = target - RECHDR_LEN;
|
sz = target - RECHDR_LEN;
|
||||||
|
|
||||||
/* Needs to be decrypted? */
|
/* Needs to be decrypted? */
|
||||||
|
if (tls->min_encrypted_len_on_read != 0) {
|
||||||
|
if (sz < (int)tls->min_encrypted_len_on_read)
|
||||||
|
bb_error_msg_and_die("bad encrypted len:%u", sz);
|
||||||
|
|
||||||
|
if (tls->flags & ENCRYPTION_AESGCM) {
|
||||||
|
/* AESGCM */
|
||||||
|
uint8_t *p = tls->inbuf + RECHDR_LEN;
|
||||||
|
|
||||||
|
sz -= 8 + AES_BLOCK_SIZE; /* we will overwrite nonce, drop hash */
|
||||||
|
tls_aesgcm_decrypt(tls, p, sz);
|
||||||
|
memmove(p, p + 8, sz);
|
||||||
|
dbg("encrypted size:%u\n", sz);
|
||||||
|
} else
|
||||||
if (tls->min_encrypted_len_on_read > tls->MAC_size) {
|
if (tls->min_encrypted_len_on_read > tls->MAC_size) {
|
||||||
|
/* AES+SHA */
|
||||||
uint8_t *p = tls->inbuf + RECHDR_LEN;
|
uint8_t *p = tls->inbuf + RECHDR_LEN;
|
||||||
int padding_len;
|
int padding_len;
|
||||||
|
|
||||||
if (sz & (AES_BLOCKSIZE-1)
|
if (sz & (AES_BLOCK_SIZE-1))
|
||||||
|| sz < (int)tls->min_encrypted_len_on_read
|
bb_error_msg_and_die("bad encrypted len:%u", sz);
|
||||||
) {
|
|
||||||
bb_error_msg_and_die("bad encrypted len:%u < %u",
|
|
||||||
sz, tls->min_encrypted_len_on_read);
|
|
||||||
}
|
|
||||||
/* Decrypt content+MAC+padding, moving it over IV in the process */
|
/* Decrypt content+MAC+padding, moving it over IV in the process */
|
||||||
sz -= AES_BLOCKSIZE; /* we will overwrite IV now */
|
sz -= AES_BLOCK_SIZE; /* we will overwrite IV now */
|
||||||
aes_cbc_decrypt(
|
aes_cbc_decrypt(
|
||||||
tls->server_write_key, tls->key_size, /* selects 128/256 */
|
tls->server_write_key, tls->key_size, /* selects 128/256 */
|
||||||
p, /* IV */
|
p, /* IV */
|
||||||
p + AES_BLOCKSIZE, sz, /* ciphertext */
|
p + AES_BLOCK_SIZE, sz, /* ciphertext */
|
||||||
p /* plaintext */
|
p /* plaintext */
|
||||||
);
|
);
|
||||||
padding_len = p[sz - 1];
|
padding_len = p[sz - 1];
|
||||||
dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[0], padding_len);
|
dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[0], padding_len);
|
||||||
padding_len++;
|
padding_len++;
|
||||||
sz -= tls->MAC_size + padding_len; /* drop MAC and padding */
|
sz -= tls->MAC_size + padding_len; /* drop MAC and padding */
|
||||||
//if (sz < 0)
|
|
||||||
// bb_error_msg_and_die("bad padding size:%u", padding_len);
|
|
||||||
} else {
|
} else {
|
||||||
/* if nonzero, then it's TLS_RSA_WITH_NULL_SHA256: drop MAC */
|
/* if nonzero, then it's TLS_RSA_WITH_NULL_SHA256: drop MAC */
|
||||||
/* else: no encryption yet on input, subtract zero = NOP */
|
/* else: no encryption yet on input, subtract zero = NOP */
|
||||||
sz -= tls->min_encrypted_len_on_read;
|
sz -= tls->min_encrypted_len_on_read;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (sz < 0)
|
if (sz < 0)
|
||||||
bb_error_msg_and_die("encrypted data too short");
|
bb_error_msg_and_die("encrypted data too short");
|
||||||
|
|
||||||
@ -964,7 +1115,8 @@ static int tls_xread_record(tls_state_t *tls, const char *expected)
|
|||||||
* in our FINISHED record must include data of incoming packets too!
|
* in our FINISHED record must include data of incoming packets too!
|
||||||
*/
|
*/
|
||||||
if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE
|
if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE
|
||||||
&& tls->MAC_size != 0 /* do we know which hash to use? (server_hello() does not!) */
|
/* HANDSHAKE HASH: */
|
||||||
|
// && do_we_know_which_hash_to_use /* server_hello() might not know it in the future! */
|
||||||
) {
|
) {
|
||||||
hash_handshake(tls, "<< hash:%s", tls->inbuf + RECHDR_LEN, sz);
|
hash_handshake(tls, "<< hash:%s", tls->inbuf + RECHDR_LEN, sz);
|
||||||
}
|
}
|
||||||
@ -1198,16 +1350,16 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
|
|||||||
};
|
};
|
||||||
if (memcmp(der, OID_RSA_KEY_ALG, sizeof(OID_RSA_KEY_ALG)) == 0) {
|
if (memcmp(der, OID_RSA_KEY_ALG, sizeof(OID_RSA_KEY_ALG)) == 0) {
|
||||||
dbg("RSA key\n");
|
dbg("RSA key\n");
|
||||||
tls->hsd->key_alg = KEY_ALG_RSA;
|
tls->flags |= GOT_CERT_RSA_KEY_ALG;
|
||||||
} else
|
} else
|
||||||
if (memcmp(der, OID_ECDSA_KEY_ALG, sizeof(OID_ECDSA_KEY_ALG)) == 0) {
|
if (memcmp(der, OID_ECDSA_KEY_ALG, sizeof(OID_ECDSA_KEY_ALG)) == 0) {
|
||||||
dbg("ECDSA key\n");
|
dbg("ECDSA key\n");
|
||||||
tls->hsd->key_alg = KEY_ALG_ECDSA;
|
tls->flags |= GOT_CERT_ECDSA_KEY_ALG;
|
||||||
} else
|
} else
|
||||||
bb_error_msg_and_die("not RSA or ECDSA key");
|
bb_error_msg_and_die("not RSA or ECDSA cert");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tls->hsd->key_alg == KEY_ALG_RSA) {
|
if (tls->flags & GOT_CERT_RSA_KEY_ALG) {
|
||||||
/* parse RSA key: */
|
/* parse RSA key: */
|
||||||
//based on getAsnRsaPubKey(), pkcs1ParsePrivBin() is also of note
|
//based on getAsnRsaPubKey(), pkcs1ParsePrivBin() is also of note
|
||||||
/* skip subjectPublicKeyInfo.algorithm */
|
/* skip subjectPublicKeyInfo.algorithm */
|
||||||
@ -1301,7 +1453,7 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
|
|||||||
uint8_t session_id_len;
|
uint8_t session_id_len;
|
||||||
/* uint8_t session_id[]; */
|
/* uint8_t session_id[]; */
|
||||||
uint8_t cipherid_len16_hi, cipherid_len16_lo;
|
uint8_t cipherid_len16_hi, cipherid_len16_lo;
|
||||||
uint8_t cipherid[2 * (2 + !!CIPHER_ID2 + !!CIPHER_ID3)]; /* actually variable */
|
uint8_t cipherid[2 * (1 + NUM_CIPHERS)]; /* actually variable */
|
||||||
uint8_t comprtypes_len;
|
uint8_t comprtypes_len;
|
||||||
uint8_t comprtypes[1]; /* actually variable */
|
uint8_t comprtypes[1]; /* actually variable */
|
||||||
/* Extensions (SNI shown):
|
/* Extensions (SNI shown):
|
||||||
@ -1364,6 +1516,10 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
|
|||||||
if ((CIPHER_ID3 >> 8) != 0) record->cipherid[6] = CIPHER_ID3 >> 8;
|
if ((CIPHER_ID3 >> 8) != 0) record->cipherid[6] = CIPHER_ID3 >> 8;
|
||||||
/*************************/ record->cipherid[7] = CIPHER_ID3 & 0xff;
|
/*************************/ record->cipherid[7] = CIPHER_ID3 & 0xff;
|
||||||
#endif
|
#endif
|
||||||
|
#if CIPHER_ID4
|
||||||
|
if ((CIPHER_ID4 >> 8) != 0) record->cipherid[6] = CIPHER_ID4 >> 8;
|
||||||
|
/*************************/ record->cipherid[7] = CIPHER_ID4 & 0xff;
|
||||||
|
#endif
|
||||||
|
|
||||||
record->comprtypes_len = 1;
|
record->comprtypes_len = 1;
|
||||||
/* record->comprtypes[0] = 0; */
|
/* record->comprtypes[0] = 0; */
|
||||||
@ -1385,15 +1541,23 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
|
|||||||
}
|
}
|
||||||
memcpy(ptr, supported_groups, sizeof(supported_groups));
|
memcpy(ptr, supported_groups, sizeof(supported_groups));
|
||||||
|
|
||||||
dbg(">> CLIENT_HELLO\n");
|
tls->hsd = xzalloc(sizeof(*tls->hsd));
|
||||||
/* Can hash it only when we know which MAC hash to use */
|
/* HANDSHAKE HASH: ^^^ + len if need to save saved_client_hello */
|
||||||
/*xwrite_and_update_handshake_hash(tls, len); - WRONG! */
|
memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32));
|
||||||
xwrite_handshake_record(tls, len);
|
/* HANDSHAKE HASH:
|
||||||
|
|
||||||
tls->hsd = xzalloc(sizeof(*tls->hsd) + len);
|
|
||||||
tls->hsd->saved_client_hello_size = len;
|
tls->hsd->saved_client_hello_size = len;
|
||||||
memcpy(tls->hsd->saved_client_hello, record, len);
|
memcpy(tls->hsd->saved_client_hello, record, len);
|
||||||
memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32));
|
*/
|
||||||
|
dbg(">> CLIENT_HELLO\n");
|
||||||
|
/* Can hash immediately only if we know which MAC hash to use.
|
||||||
|
* So far we do know: it's sha256:
|
||||||
|
*/
|
||||||
|
sha256_begin(&tls->hsd->handshake_hash_ctx);
|
||||||
|
xwrite_and_update_handshake_hash(tls, len);
|
||||||
|
/* if this would become infeasible: save tls->hsd->saved_client_hello,
|
||||||
|
* use "xwrite_handshake_record(tls, len)" here,
|
||||||
|
* and hash saved_client_hello later.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_server_hello(tls_state_t *tls)
|
static void get_server_hello(tls_state_t *tls)
|
||||||
@ -1463,18 +1627,28 @@ static void get_server_hello(tls_state_t *tls)
|
|||||||
if (cipher == TLS_RSA_WITH_AES_128_CBC_SHA
|
if (cipher == TLS_RSA_WITH_AES_128_CBC_SHA
|
||||||
|| cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
|| cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
||||||
) {
|
) {
|
||||||
|
if (cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
|
||||||
|
tls->flags |= NEED_EC_KEY;
|
||||||
tls->key_size = AES128_KEYSIZE;
|
tls->key_size = AES128_KEYSIZE;
|
||||||
tls->MAC_size = SHA1_OUTSIZE;
|
tls->MAC_size = SHA1_OUTSIZE;
|
||||||
}
|
}
|
||||||
else { /* TLS_RSA_WITH_AES_256_CBC_SHA256 */
|
else
|
||||||
|
if (cipher == TLS_RSA_WITH_AES_256_CBC_SHA256) {
|
||||||
tls->key_size = AES256_KEYSIZE;
|
tls->key_size = AES256_KEYSIZE;
|
||||||
tls->MAC_size = SHA256_OUTSIZE;
|
tls->MAC_size = SHA256_OUTSIZE;
|
||||||
}
|
}
|
||||||
|
else { /* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 */
|
||||||
|
tls->flags |= NEED_EC_KEY | ENCRYPTION_AESGCM;
|
||||||
|
tls->key_size = AES128_KEYSIZE;
|
||||||
|
/* tls->MAC_size = 0; */
|
||||||
|
tls->IV_size = 4;
|
||||||
|
}
|
||||||
/* Handshake hash eventually destined to FINISHED record
|
/* Handshake hash eventually destined to FINISHED record
|
||||||
* is sha256 regardless of cipher
|
* is sha256 regardless of cipher
|
||||||
* (at least for all ciphers defined by RFC5246).
|
* (at least for all ciphers defined by RFC5246).
|
||||||
* It's not sha1 for AES_128_CBC_SHA - only MAC is sha1, not this hash.
|
* It's not sha1 for AES_128_CBC_SHA - only MAC is sha1, not this hash.
|
||||||
*/
|
*/
|
||||||
|
/* HANDSHAKE HASH:
|
||||||
sha256_begin(&tls->hsd->handshake_hash_ctx);
|
sha256_begin(&tls->hsd->handshake_hash_ctx);
|
||||||
hash_handshake(tls, ">> client hello hash:%s",
|
hash_handshake(tls, ">> client hello hash:%s",
|
||||||
tls->hsd->saved_client_hello, tls->hsd->saved_client_hello_size
|
tls->hsd->saved_client_hello, tls->hsd->saved_client_hello_size
|
||||||
@ -1482,6 +1656,7 @@ static void get_server_hello(tls_state_t *tls)
|
|||||||
hash_handshake(tls, "<< server hello hash:%s",
|
hash_handshake(tls, "<< server hello hash:%s",
|
||||||
tls->inbuf + RECHDR_LEN, len
|
tls->inbuf + RECHDR_LEN, len
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_server_cert(tls_state_t *tls)
|
static void get_server_cert(tls_state_t *tls)
|
||||||
@ -1548,7 +1723,7 @@ static void process_server_key(tls_state_t *tls, int len)
|
|||||||
// 64523d6216cb94c43c9b20e377d8c52c55be6703fd6730a155930c705eaf3af6 //32bytes
|
// 64523d6216cb94c43c9b20e377d8c52c55be6703fd6730a155930c705eaf3af6 //32bytes
|
||||||
//same about this item ^^^^^
|
//same about this item ^^^^^
|
||||||
|
|
||||||
//seen from www.openbsd.org
|
//seen from ftp.openbsd.org
|
||||||
//(which only accepts ECDHE-RSA-AESnnn-GCM-SHAnnn and ECDHE-RSA-CHACHA20-POLY1305 ciphers):
|
//(which only accepts ECDHE-RSA-AESnnn-GCM-SHAnnn and ECDHE-RSA-CHACHA20-POLY1305 ciphers):
|
||||||
// 0c 000228 //SERVER_KEY_EXCHANGE, len
|
// 0c 000228 //SERVER_KEY_EXCHANGE, len
|
||||||
// 03 //curve_type: named curve
|
// 03 //curve_type: named curve
|
||||||
@ -1572,6 +1747,7 @@ static void process_server_key(tls_state_t *tls, int len)
|
|||||||
bb_error_msg_and_die("elliptic curve is not x25519");
|
bb_error_msg_and_die("elliptic curve is not x25519");
|
||||||
|
|
||||||
memcpy(tls->hsd->ecc_pub_key32, keybuf + 4, 32);
|
memcpy(tls->hsd->ecc_pub_key32, keybuf + 4, 32);
|
||||||
|
tls->flags |= GOT_EC_KEY;
|
||||||
dbg("got eccPubKey\n");
|
dbg("got eccPubKey\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1612,7 +1788,11 @@ static void send_client_key_exchange(tls_state_t *tls)
|
|||||||
int premaster_size;
|
int premaster_size;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (tls->hsd->key_alg == KEY_ALG_RSA) {
|
if (!(tls->flags & NEED_EC_KEY)) {
|
||||||
|
/* RSA */
|
||||||
|
if (!(tls->flags & GOT_CERT_RSA_KEY_ALG))
|
||||||
|
bb_error_msg("server cert is not RSA");
|
||||||
|
|
||||||
tls_get_random(rsa_premaster, sizeof(rsa_premaster));
|
tls_get_random(rsa_premaster, sizeof(rsa_premaster));
|
||||||
if (TLS_DEBUG_FIXED_SECRETS)
|
if (TLS_DEBUG_FIXED_SECRETS)
|
||||||
memset(rsa_premaster, 0x44, sizeof(rsa_premaster));
|
memset(rsa_premaster, 0x44, sizeof(rsa_premaster));
|
||||||
@ -1636,10 +1816,13 @@ static void send_client_key_exchange(tls_state_t *tls)
|
|||||||
premaster = rsa_premaster;
|
premaster = rsa_premaster;
|
||||||
premaster_size = sizeof(rsa_premaster);
|
premaster_size = sizeof(rsa_premaster);
|
||||||
} else {
|
} else {
|
||||||
/* KEY_ALG_ECDSA */
|
/* ECDHE */
|
||||||
static const uint8_t basepoint9[CURVE25519_KEYSIZE] = {9};
|
static const uint8_t basepoint9[CURVE25519_KEYSIZE] = {9};
|
||||||
uint8_t privkey[CURVE25519_KEYSIZE]; //[32]
|
uint8_t privkey[CURVE25519_KEYSIZE]; //[32]
|
||||||
|
|
||||||
|
if (!(tls->flags & GOT_EC_KEY))
|
||||||
|
bb_error_msg("server did not provide EC key");
|
||||||
|
|
||||||
/* Generate random private key, see RFC 7748 */
|
/* Generate random private key, see RFC 7748 */
|
||||||
tls_get_random(privkey, sizeof(privkey));
|
tls_get_random(privkey, sizeof(privkey));
|
||||||
privkey[0] &= 0xf8;
|
privkey[0] &= 0xf8;
|
||||||
@ -1727,23 +1910,32 @@ static void send_client_key_exchange(tls_state_t *tls)
|
|||||||
memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32);
|
memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32);
|
||||||
|
|
||||||
prf_hmac_sha256(/*tls,*/
|
prf_hmac_sha256(/*tls,*/
|
||||||
tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size),
|
tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size + tls->IV_size),
|
||||||
// also fills:
|
// also fills:
|
||||||
// server_write_MAC_key[]
|
// server_write_MAC_key[]
|
||||||
// client_write_key[]
|
// client_write_key[]
|
||||||
// server_write_key[]
|
// server_write_key[]
|
||||||
|
// client_write_IV[]
|
||||||
|
// server_write_IV[]
|
||||||
tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
|
tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
|
||||||
"key expansion",
|
"key expansion",
|
||||||
tmp64, 64
|
tmp64, 64
|
||||||
);
|
);
|
||||||
tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size);
|
tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size);
|
||||||
tls->server_write_key = tls->client_write_key + tls->key_size;
|
tls->server_write_key = tls->client_write_key + tls->key_size;
|
||||||
|
tls->client_write_IV = tls->server_write_key + tls->key_size;
|
||||||
|
tls->server_write_IV = tls->client_write_IV + tls->IV_size;
|
||||||
dump_hex("client_write_MAC_key:%s\n",
|
dump_hex("client_write_MAC_key:%s\n",
|
||||||
tls->client_write_MAC_key, tls->MAC_size
|
tls->client_write_MAC_key, tls->MAC_size
|
||||||
);
|
);
|
||||||
dump_hex("client_write_key:%s\n",
|
dump_hex("client_write_key:%s\n",
|
||||||
tls->client_write_key, tls->key_size
|
tls->client_write_key, tls->key_size
|
||||||
);
|
);
|
||||||
|
dump_hex("client_write_IV:%s\n",
|
||||||
|
tls->client_write_IV, tls->IV_size
|
||||||
|
);
|
||||||
|
aesgcm_setkey(tls->H, &tls->aes_encrypt, tls->client_write_key, tls->key_size);
|
||||||
|
aes_setkey(&tls->aes_decrypt, tls->server_write_key, tls->key_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1876,7 +2068,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
|
|||||||
// client.
|
// client.
|
||||||
dbg("<< SERVER_KEY_EXCHANGE len:%u\n", len);
|
dbg("<< SERVER_KEY_EXCHANGE len:%u\n", len);
|
||||||
dump_raw_in("<< %s\n", tls->inbuf, RECHDR_LEN + len);
|
dump_raw_in("<< %s\n", tls->inbuf, RECHDR_LEN + len);
|
||||||
if (tls->hsd->key_alg == KEY_ALG_ECDSA)
|
if (tls->flags & NEED_EC_KEY)
|
||||||
process_server_key(tls, len);
|
process_server_key(tls, len);
|
||||||
|
|
||||||
// read next handshake block
|
// read next handshake block
|
||||||
@ -1922,18 +2114,22 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
|
|||||||
if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
|
if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
|
||||||
bad_record_die(tls, "switch to encrypted traffic", len);
|
bad_record_die(tls, "switch to encrypted traffic", len);
|
||||||
dbg("<< CHANGE_CIPHER_SPEC\n");
|
dbg("<< CHANGE_CIPHER_SPEC\n");
|
||||||
|
|
||||||
if (CIPHER_ID1 == TLS_RSA_WITH_NULL_SHA256
|
if (CIPHER_ID1 == TLS_RSA_WITH_NULL_SHA256
|
||||||
&& tls->cipher_id == TLS_RSA_WITH_NULL_SHA256
|
&& tls->cipher_id == TLS_RSA_WITH_NULL_SHA256
|
||||||
) {
|
) {
|
||||||
tls->min_encrypted_len_on_read = tls->MAC_size;
|
tls->min_encrypted_len_on_read = tls->MAC_size;
|
||||||
} else {
|
} else
|
||||||
unsigned mac_blocks = (unsigned)(tls->MAC_size + AES_BLOCKSIZE-1) / AES_BLOCKSIZE;
|
if (!(tls->flags & ENCRYPTION_AESGCM)) {
|
||||||
|
unsigned mac_blocks = (unsigned)(tls->MAC_size + AES_BLOCK_SIZE-1) / AES_BLOCK_SIZE;
|
||||||
/* all incoming packets now should be encrypted and have
|
/* all incoming packets now should be encrypted and have
|
||||||
* at least IV + (MAC padded to blocksize):
|
* at least IV + (MAC padded to blocksize):
|
||||||
*/
|
*/
|
||||||
tls->min_encrypted_len_on_read = AES_BLOCKSIZE + (mac_blocks * AES_BLOCKSIZE);
|
tls->min_encrypted_len_on_read = AES_BLOCK_SIZE + (mac_blocks * AES_BLOCK_SIZE);
|
||||||
dbg("min_encrypted_len_on_read: %u", tls->min_encrypted_len_on_read);
|
} else {
|
||||||
|
tls->min_encrypted_len_on_read = 8 + AES_BLOCK_SIZE;
|
||||||
}
|
}
|
||||||
|
dbg("min_encrypted_len_on_read: %u\n", tls->min_encrypted_len_on_read);
|
||||||
|
|
||||||
/* Get (encrypted) FINISHED from the server */
|
/* Get (encrypted) FINISHED from the server */
|
||||||
len = tls_xread_record(tls, "'server finished'");
|
len = tls_xread_record(tls, "'server finished'");
|
||||||
|
@ -78,6 +78,8 @@ typedef int16_t int16;
|
|||||||
#define PUBKEY_TYPE 0x01
|
#define PUBKEY_TYPE 0x01
|
||||||
#define PRIVKEY_TYPE 0x02
|
#define PRIVKEY_TYPE 0x02
|
||||||
|
|
||||||
|
#define AES_BLOCK_SIZE 16
|
||||||
|
|
||||||
void tls_get_random(void *buf, unsigned len);
|
void tls_get_random(void *buf, unsigned len);
|
||||||
|
|
||||||
#define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS)
|
#define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS)
|
||||||
@ -96,5 +98,6 @@ void tls_get_random(void *buf, unsigned len);
|
|||||||
#include "tls_pstm.h"
|
#include "tls_pstm.h"
|
||||||
#include "tls_symmetric.h"
|
#include "tls_symmetric.h"
|
||||||
#include "tls_aes.h"
|
#include "tls_aes.h"
|
||||||
|
#include "tls_aesgcm.h"
|
||||||
#include "tls_rsa.h"
|
#include "tls_rsa.h"
|
||||||
#include "tls_fe.h"
|
#include "tls_fe.h"
|
||||||
|
@ -340,8 +340,12 @@ static void aes_encrypt_1(unsigned astate[16], unsigned rounds, const uint32_t *
|
|||||||
AddRoundKey(astate, RoundKey);
|
AddRoundKey(astate, RoundKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // UNUSED
|
void FAST_FUNC aes_setkey(struct tls_aes *aes, const void *key, unsigned key_len)
|
||||||
static void aes_encrypt_one_block(unsigned rounds, const uint32_t *RoundKey, const void *data, void *dst)
|
{
|
||||||
|
aes->rounds = KeyExpansion(aes->key, key, key_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FAST_FUNC aes_encrypt_one_block(struct tls_aes *aes, const void *data, void *dst)
|
||||||
{
|
{
|
||||||
unsigned astate[16];
|
unsigned astate[16];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@ -351,13 +355,12 @@ static void aes_encrypt_one_block(unsigned rounds, const uint32_t *RoundKey, con
|
|||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
astate[i] = pt[i];
|
astate[i] = pt[i];
|
||||||
aes_encrypt_1(astate, rounds, RoundKey);
|
aes_encrypt_1(astate, aes->rounds, aes->key);
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
ct[i] = astate[i];
|
ct[i] = astate[i];
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst)
|
void FAST_FUNC aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst)
|
||||||
{
|
{
|
||||||
uint32_t RoundKey[60];
|
uint32_t RoundKey[60];
|
||||||
uint8_t iv2[16];
|
uint8_t iv2[16];
|
||||||
@ -420,7 +423,7 @@ static void aes_decrypt_one_block(unsigned rounds, const uint32_t *RoundKey, con
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void aes_cbc_decrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst)
|
void FAST_FUNC aes_cbc_decrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst)
|
||||||
{
|
{
|
||||||
uint32_t RoundKey[60];
|
uint32_t RoundKey[60];
|
||||||
uint8_t iv2[16];
|
uint8_t iv2[16];
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
* Selected few declarations for AES.
|
* Selected few declarations for AES.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst);
|
void aes_setkey(struct tls_aes *aes, const void *key, unsigned key_len) FAST_FUNC;
|
||||||
void aes_cbc_decrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst);
|
|
||||||
|
void aes_encrypt_one_block(struct tls_aes *aes, const void *data, void *dst) FAST_FUNC;
|
||||||
|
|
||||||
|
void aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst) FAST_FUNC;
|
||||||
|
void aes_cbc_decrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst) FAST_FUNC;
|
||||||
|
148
networking/tls_aesgcm.c
Normal file
148
networking/tls_aesgcm.c
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Denys Vlasenko
|
||||||
|
*
|
||||||
|
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tls.h"
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
typedef uint32_t word32;
|
||||||
|
#define XMEMSET memset
|
||||||
|
#define XMEMCPY memcpy
|
||||||
|
|
||||||
|
#define TLS_MAJ 3
|
||||||
|
#define TLS_MIN 3
|
||||||
|
#define RECHDR_LEN 5
|
||||||
|
#define OUTBUF_PFX (8 + AES_BLOCK_SIZE)
|
||||||
|
|
||||||
|
void FAST_FUNC xorbuf(void* buf, const void* mask, unsigned count)
|
||||||
|
{
|
||||||
|
word32 i;
|
||||||
|
byte* b = (byte*)buf;
|
||||||
|
const byte* m = (const byte*)mask;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
b[i] ^= m[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wolfssl-3.15.3/wolfcrypt/src/aes.c */
|
||||||
|
|
||||||
|
static void FlattenSzInBits(byte* buf, word32 sz)
|
||||||
|
{
|
||||||
|
/* Multiply the sz by 8 */
|
||||||
|
word32 szHi = (sz >> (8*sizeof(sz) - 3));
|
||||||
|
sz <<= 3;
|
||||||
|
|
||||||
|
/* copy over the words of the sz into the destination buffer */
|
||||||
|
buf[0] = (szHi >> 24) & 0xff;
|
||||||
|
buf[1] = (szHi >> 16) & 0xff;
|
||||||
|
buf[2] = (szHi >> 8) & 0xff;
|
||||||
|
buf[3] = szHi & 0xff;
|
||||||
|
buf[4] = (sz >> 24) & 0xff;
|
||||||
|
buf[5] = (sz >> 16) & 0xff;
|
||||||
|
buf[6] = (sz >> 8) & 0xff;
|
||||||
|
buf[7] = sz & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RIGHTSHIFTX(byte* x)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int carryOut = 0;
|
||||||
|
int carryIn = 0;
|
||||||
|
int borrow = x[15] & 0x01;
|
||||||
|
|
||||||
|
for (i = 0; i < AES_BLOCK_SIZE; i++) {
|
||||||
|
carryOut = x[i] & 0x01;
|
||||||
|
x[i] = (x[i] >> 1) | (carryIn ? 0x80 : 0);
|
||||||
|
carryIn = carryOut;
|
||||||
|
}
|
||||||
|
if (borrow) x[0] ^= 0xE1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GMULT(byte* X, byte* Y)
|
||||||
|
{
|
||||||
|
byte Z[AES_BLOCK_SIZE];
|
||||||
|
byte V[AES_BLOCK_SIZE];
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
XMEMSET(Z, 0, AES_BLOCK_SIZE);
|
||||||
|
XMEMCPY(V, X, AES_BLOCK_SIZE);
|
||||||
|
for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||||
|
{
|
||||||
|
byte y = Y[i];
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
if (y & 0x80) {
|
||||||
|
xorbuf(Z, V, AES_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
RIGHTSHIFTX(V);
|
||||||
|
y = y << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XMEMCPY(X, Z, AES_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FAST_FUNC aesgcm_GHASH(byte* h, const byte* a, unsigned aSz, const byte* c,
|
||||||
|
unsigned cSz, byte* s, unsigned sSz)
|
||||||
|
{
|
||||||
|
byte x[AES_BLOCK_SIZE];
|
||||||
|
byte scratch[AES_BLOCK_SIZE];
|
||||||
|
word32 blocks, partial;
|
||||||
|
//was: byte* h = aes->H;
|
||||||
|
|
||||||
|
XMEMSET(x, 0, AES_BLOCK_SIZE);
|
||||||
|
|
||||||
|
/* Hash in A, the Additional Authentication Data */
|
||||||
|
if (aSz != 0 && a != NULL) {
|
||||||
|
blocks = aSz / AES_BLOCK_SIZE;
|
||||||
|
partial = aSz % AES_BLOCK_SIZE;
|
||||||
|
while (blocks--) {
|
||||||
|
xorbuf(x, a, AES_BLOCK_SIZE);
|
||||||
|
GMULT(x, h);
|
||||||
|
a += AES_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
if (partial != 0) {
|
||||||
|
XMEMSET(scratch, 0, AES_BLOCK_SIZE);
|
||||||
|
XMEMCPY(scratch, a, partial);
|
||||||
|
xorbuf(x, scratch, AES_BLOCK_SIZE);
|
||||||
|
GMULT(x, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hash in C, the Ciphertext */
|
||||||
|
if (cSz != 0 && c != NULL) {
|
||||||
|
blocks = cSz / AES_BLOCK_SIZE;
|
||||||
|
partial = cSz % AES_BLOCK_SIZE;
|
||||||
|
while (blocks--) {
|
||||||
|
xorbuf(x, c, AES_BLOCK_SIZE);
|
||||||
|
GMULT(x, h);
|
||||||
|
c += AES_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
if (partial != 0) {
|
||||||
|
XMEMSET(scratch, 0, AES_BLOCK_SIZE);
|
||||||
|
XMEMCPY(scratch, c, partial);
|
||||||
|
xorbuf(x, scratch, AES_BLOCK_SIZE);
|
||||||
|
GMULT(x, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hash in the lengths of A and C in bits */
|
||||||
|
FlattenSzInBits(&scratch[0], aSz);
|
||||||
|
FlattenSzInBits(&scratch[8], cSz);
|
||||||
|
xorbuf(x, scratch, AES_BLOCK_SIZE);
|
||||||
|
GMULT(x, h);
|
||||||
|
|
||||||
|
/* Copy the result into s. */
|
||||||
|
XMEMCPY(s, x, sSz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FAST_FUNC aesgcm_setkey(uint8_t H[16], struct tls_aes *aes, const byte* key, unsigned len)
|
||||||
|
{
|
||||||
|
byte iv[AES_BLOCK_SIZE];
|
||||||
|
|
||||||
|
aes_setkey(aes, key, len);
|
||||||
|
|
||||||
|
memset(iv, 0, AES_BLOCK_SIZE);
|
||||||
|
aes_encrypt_one_block(aes, iv, H);
|
||||||
|
}
|
15
networking/tls_aesgcm.h
Normal file
15
networking/tls_aesgcm.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Denys Vlasenko
|
||||||
|
*
|
||||||
|
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void xorbuf(void* buf, const void* mask, unsigned count) FAST_FUNC;
|
||||||
|
|
||||||
|
void aesgcm_GHASH(uint8_t* h,
|
||||||
|
const uint8_t* a, unsigned aSz,
|
||||||
|
const uint8_t* c, unsigned cSz,
|
||||||
|
uint8_t* s, unsigned sSz
|
||||||
|
) FAST_FUNC;
|
||||||
|
|
||||||
|
void aesgcm_setkey(uint8_t H[16], struct tls_aes *aes, const uint8_t* key, unsigned len) FAST_FUNC;
|
@ -554,7 +554,7 @@ static void xc_double(byte *x3, byte *z3,
|
|||||||
fe_mul_c(z3, x1sq, 4);
|
fe_mul_c(z3, x1sq, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void curve25519(byte *result, const byte *e, const byte *q)
|
void FAST_FUNC curve25519(byte *result, const byte *e, const byte *q)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -4,4 +4,4 @@
|
|||||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||||
*/
|
*/
|
||||||
#define CURVE25519_KEYSIZE 32
|
#define CURVE25519_KEYSIZE 32
|
||||||
void curve25519(uint8_t *result, const uint8_t *e, const uint8_t *q);
|
void curve25519(uint8_t *result, const uint8_t *e, const uint8_t *q) FAST_FUNC;
|
||||||
|
@ -179,7 +179,7 @@ done:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key,
|
int32 FAST_FUNC psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key,
|
||||||
unsigned char *in, uint32 inlen,
|
unsigned char *in, uint32 inlen,
|
||||||
unsigned char *out, uint32 outlen, void *data)
|
unsigned char *out, uint32 outlen, void *data)
|
||||||
{
|
{
|
||||||
|
@ -17,4 +17,4 @@ typedef struct {
|
|||||||
psRsaEncryptPub( key, in, inlen, out, outlen)
|
psRsaEncryptPub( key, in, inlen, out, outlen)
|
||||||
int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key,
|
int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key,
|
||||||
unsigned char *in, uint32 inlen,
|
unsigned char *in, uint32 inlen,
|
||||||
unsigned char *out, uint32 outlen, void *data);
|
unsigned char *out, uint32 outlen, void *data) FAST_FUNC;
|
||||||
|
Loading…
Reference in New Issue
Block a user