Add mtls and chacha20

This commit is contained in:
Sergey Lyubka 2024-06-09 10:21:24 +01:00
parent 71abdc1bda
commit df257a8e8a
9 changed files with 3504 additions and 641 deletions

1923
mongoose.c

File diff suppressed because it is too large Load Diff

View File

@ -1936,6 +1936,116 @@ typedef uint64_t mg_uecc_word_t;
#endif /* _UECC_TYPES_H_ */ #endif /* _UECC_TYPES_H_ */
// End of uecc BSD-2 // End of uecc BSD-2
// portable8439 v1.0.1
// Source: https://github.com/DavyLandman/portable8439
// Licensed under CC0-1.0
// Contains poly1305-donna e6ad6e091d30d7f4ec2d4f978be1fcfcbce72781 (Public
// Domain)
#ifndef __PORTABLE_8439_H
#define __PORTABLE_8439_H
#if defined(__cplusplus)
extern "C" {
#endif
// provide your own decl specificier like -DPORTABLE_8439_DECL=ICACHE_RAM_ATTR
#ifndef PORTABLE_8439_DECL
#define PORTABLE_8439_DECL
#endif
/*
This library implements RFC 8439 a.k.a. ChaCha20-Poly1305 AEAD
You can use this library to avoid attackers mutating or reusing your
encrypted messages. This does assume you never reuse a nonce+key pair and,
if possible, carefully pick your associated data.
*/
// Make sure we are either nested in C++ or running in a C99+ compiler
#if !defined(__cplusplus) && !defined(_MSC_VER) && \
(!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#error "C99 or newer required"
#endif
// #if CHAR_BIT > 8
// # error "Systems without native octals not suppoted"
// #endif
#if defined(_MSC_VER) || defined(__cplusplus)
// add restrict support is possible
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || defined(__clang__) || \
defined(__GNUC__)
#define restrict __restrict
#else
#define restrict
#endif
#endif
#define RFC_8439_TAG_SIZE (16)
#define RFC_8439_KEY_SIZE (32)
#define RFC_8439_NONCE_SIZE (12)
/*
Encrypt/Seal plain text bytes into a cipher text that can only be
decrypted by knowing the key, nonce and associated data.
input:
- key: RFC_8439_KEY_SIZE bytes that all parties have agreed
upon beforehand
- nonce: RFC_8439_NONCE_SIZE bytes that should never be repeated
for the same key. A counter or a pseudo-random value are fine.
- ad: associated data to include with calculating the tag of the
cipher text. Can be null for empty.
- plain_text: data to be encrypted, pointer + size should not overlap
with cipher_text pointer
output:
- cipher_text: encrypted plain_text with a tag appended. Make sure to
allocate at least plain_text_size + RFC_8439_TAG_SIZE
returns:
- size of bytes written to cipher_text, can be -1 if overlapping
pointers are passed for plain_text and cipher_text
*/
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
uint8_t *restrict cipher_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
size_t ad_size, const uint8_t *restrict plain_text, size_t plain_text_size);
/*
Decrypt/unseal cipher text given the right key, nonce, and additional data.
input:
- key: RFC_8439_KEY_SIZE bytes that all parties have agreed
upon beforehand
- nonce: RFC_8439_NONCE_SIZE bytes that should never be repeated for
the same key. A counter or a pseudo-random value are fine.
- ad: associated data to include with calculating the tag of the
cipher text. Can be null for empty.
- cipher_text: encrypted message.
output:
- plain_text: data to be encrypted, pointer + size should not overlap
with cipher_text pointer, leave at least enough room for
cipher_text_size - RFC_8439_TAG_SIZE
returns:
- size of bytes written to plain_text, -1 signals either:
- incorrect key/nonce/ad
- corrupted cipher_text
- overlapping pointers are passed for plain_text and cipher_text
*/
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_SIZE],
const uint8_t *restrict cipher_text, size_t cipher_text_size);
#if defined(__cplusplus)
}
#endif
#endif
struct mg_connection; struct mg_connection;
@ -2940,49 +3050,6 @@ struct mg_tcpip_driver_tm4c_data {
#endif #endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500
#undef MG_ENABLE_TCPIP_DRIVER_INIT
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7
struct mg_tcpip_driver_xmc7_data {
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
uint8_t phy_addr;
};
#ifndef MG_TCPIP_PHY_ADDR
#define MG_TCPIP_PHY_ADDR 0
#endif
#ifndef MG_DRIVER_MDC_CR
#define MG_DRIVER_MDC_CR 3
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_xmc7_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_xmc7; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC
struct mg_tcpip_driver_xmc_data { struct mg_tcpip_driver_xmc_data {
@ -3029,6 +3096,41 @@ struct mg_tcpip_driver_xmc_data {
#endif #endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7
struct mg_tcpip_driver_xmc7_data {
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
uint8_t phy_addr;
};
#ifndef MG_TCPIP_PHY_ADDR
#define MG_TCPIP_PHY_ADDR 0
#endif
#ifndef MG_DRIVER_MDC_CR
#define MG_DRIVER_MDC_CR 3
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_xmc7_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_xmc7; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -85,7 +85,7 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
if ((str.buf[i] >= '0' && str.buf[i] <= '9') || if ((str.buf[i] >= '0' && str.buf[i] <= '9') ||
(str.buf[i] >= 'a' && str.buf[i] <= 'f') || (str.buf[i] >= 'a' && str.buf[i] <= 'f') ||
(str.buf[i] >= 'A' && str.buf[i] <= 'F')) { (str.buf[i] >= 'A' && str.buf[i] <= 'F')) {
unsigned long val; // TODO(): This loops on chars, refactor unsigned long val = 0; // TODO(): This loops on chars, refactor
if (i > j + 3) return false; if (i > j + 3) return false;
// MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j])); // MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j]));
mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val)); mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val));

View File

@ -1,9 +1,17 @@
#include "base64.h"
#include "config.h"
#include "printf.h"
#include "sha256.h"
#include "tls.h" #include "tls.h"
#include "tls_aes128.h" #include "tls_aes128.h"
#include "tls_chacha20.h"
#include "tls_uecc.h"
#include "tls_x25519.h" #include "tls_x25519.h"
#if MG_TLS == MG_TLS_BUILTIN #if MG_TLS == MG_TLS_BUILTIN
#define CHACHA20 1
/* TLS 1.3 Record Content Type (RFC8446 B.1) */ /* TLS 1.3 Record Content Type (RFC8446 B.1) */
#define MG_TLS_CHANGE_CIPHER 20 #define MG_TLS_CHANGE_CIPHER 20
#define MG_TLS_ALERT 21 #define MG_TLS_ALERT 21
@ -16,6 +24,7 @@
#define MG_TLS_SERVER_HELLO 2 #define MG_TLS_SERVER_HELLO 2
#define MG_TLS_ENCRYPTED_EXTENSIONS 8 #define MG_TLS_ENCRYPTED_EXTENSIONS 8
#define MG_TLS_CERTIFICATE 11 #define MG_TLS_CERTIFICATE 11
#define MG_TLS_CERTIFICATE_REQUEST 13
#define MG_TLS_CERTIFICATE_VERIFY 15 #define MG_TLS_CERTIFICATE_VERIFY 15
#define MG_TLS_FINISHED 20 #define MG_TLS_FINISHED 20
@ -37,6 +46,20 @@ enum mg_tls_hs_state {
MG_TLS_STATE_SERVER_CONNECTED // Done MG_TLS_STATE_SERVER_CONNECTED // Done
}; };
// encryption keys for a TLS connection
struct tls_enc {
uint32_t sseq; // server sequence number, used in encryption
uint32_t cseq; // client sequence number, used in decryption
// keys for AES encryption or ChaCha20
uint8_t handshake_secret[32];
uint8_t server_write_key[32];
uint8_t server_write_iv[12];
uint8_t server_finished_key[32];
uint8_t client_write_key[32];
uint8_t client_write_iv[12];
uint8_t client_finished_key[32];
};
// per-connection TLS data // per-connection TLS data
struct tls_data { struct tls_data {
enum mg_tls_hs_state state; // keep track of connection handshake progress enum mg_tls_hs_state state; // keep track of connection handshake progress
@ -49,31 +72,22 @@ struct tls_data {
mg_sha256_ctx sha256; // incremental SHA-256 hash for TLS handshake mg_sha256_ctx sha256; // incremental SHA-256 hash for TLS handshake
uint32_t sseq; // server sequence number, used in encryption
uint32_t cseq; // client sequence number, used in decryption
uint8_t random[32]; // client random from ClientHello uint8_t random[32]; // client random from ClientHello
uint8_t session_id[32]; // client session ID between the handshake states uint8_t session_id[32]; // client session ID between the handshake states
uint8_t x25519_cli[32]; // client X25519 key between the handshake states uint8_t x25519_cli[32]; // client X25519 key between the handshake states
uint8_t x25519_sec[32]; // x25519 secret between the handshake states uint8_t x25519_sec[32]; // x25519 secret between the handshake states
int skip_verification; // perform checks on server certificate? int skip_verification; // perform checks on server certificate?
struct mg_str server_cert_der; // server certificate in DER format int cert_requested; // client received a CertificateRequest?
uint8_t server_key[32]; // server EC private key struct mg_str cert_der; // certificate in DER format
char hostname[254]; // server hostname (client extension) uint8_t ec_key[32]; // EC private key
char hostname[254]; // server hostname (client extension)
uint8_t certhash[32]; // certificate message hash uint8_t certhash[32]; // certificate message hash
uint8_t pubkey[64]; // server EC public key to verify cert uint8_t pubkey[64]; // server EC public key to verify cert
uint8_t sighash[32]; // server EC public key to verify cert uint8_t sighash[32]; // server EC public key to verify cert
// keys for AES encryption struct tls_enc enc;
uint8_t handshake_secret[32];
uint8_t server_write_key[16];
uint8_t server_write_iv[12];
uint8_t server_finished_key[32];
uint8_t client_write_key[16];
uint8_t client_write_iv[12];
uint8_t client_finished_key[32];
}; };
#define MG_LOAD_BE16(p) ((uint16_t) ((MG_U8P(p)[0] << 8U) | MG_U8P(p)[1])) #define MG_LOAD_BE16(p) ((uint16_t) ((MG_U8P(p)[0] << 8U) | MG_U8P(p)[1]))
@ -88,15 +102,7 @@ struct tls_data {
#define TLS_RECHDR_SIZE 5 // 1 byte type, 2 bytes version, 2 bytes length #define TLS_RECHDR_SIZE 5 // 1 byte type, 2 bytes version, 2 bytes length
#define TLS_MSGHDR_SIZE 4 // 1 byte type, 3 bytes length #define TLS_MSGHDR_SIZE 4 // 1 byte type, 3 bytes length
#if 1 #ifdef MG_TLS_SSLKEYLOGFILE
static void mg_ssl_key_log(const char *label, uint8_t client_random[32],
uint8_t *secret, size_t secretsz) {
(void) label;
(void) client_random;
(void) secret;
(void) secretsz;
}
#else
#include <stdio.h> #include <stdio.h>
static void mg_ssl_key_log(const char *label, uint8_t client_random[32], static void mg_ssl_key_log(const char *label, uint8_t client_random[32],
uint8_t *secret, size_t secretsz) { uint8_t *secret, size_t secretsz) {
@ -243,14 +249,19 @@ static void mg_tls_generate_handshake_keys(struct mg_connection *c) {
uint8_t hello_hash[32]; uint8_t hello_hash[32];
uint8_t server_hs_secret[32]; uint8_t server_hs_secret[32];
uint8_t client_hs_secret[32]; uint8_t client_hs_secret[32];
#if CHACHA20
const size_t keysz = 32;
#else
const size_t keysz = 16;
#endif
mg_hmac_sha256(early_secret, NULL, 0, zeros, sizeof(zeros)); mg_hmac_sha256(early_secret, NULL, 0, zeros, sizeof(zeros));
mg_tls_derive_secret("tls13 derived", early_secret, 32, zeros_sha256_digest, mg_tls_derive_secret("tls13 derived", early_secret, 32, zeros_sha256_digest,
32, pre_extract_secret, 32); 32, pre_extract_secret, 32);
mg_hmac_sha256(tls->handshake_secret, pre_extract_secret, mg_hmac_sha256(tls->enc.handshake_secret, pre_extract_secret,
sizeof(pre_extract_secret), tls->x25519_sec, sizeof(pre_extract_secret), tls->x25519_sec,
sizeof(tls->x25519_sec)); sizeof(tls->x25519_sec));
mg_tls_hexdump("hs secret", tls->handshake_secret, 32); mg_tls_hexdump("hs secret", tls->enc.handshake_secret, 32);
// mg_sha256_final is not idempotent, need to copy sha256 context to calculate // mg_sha256_final is not idempotent, need to copy sha256 context to calculate
// the digest // the digest
@ -259,37 +270,40 @@ static void mg_tls_generate_handshake_keys(struct mg_connection *c) {
mg_tls_hexdump("hello hash", hello_hash, 32); mg_tls_hexdump("hello hash", hello_hash, 32);
// derive keys needed for the rest of the handshake // derive keys needed for the rest of the handshake
mg_tls_derive_secret("tls13 s hs traffic", tls->handshake_secret, 32, mg_tls_derive_secret("tls13 s hs traffic", tls->enc.handshake_secret, 32,
hello_hash, 32, server_hs_secret, 32); hello_hash, 32, server_hs_secret, 32);
mg_tls_derive_secret("tls13 key", server_hs_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 c hs traffic", tls->enc.handshake_secret, 32,
tls->server_write_key, 16);
mg_tls_derive_secret("tls13 iv", server_hs_secret, 32, NULL, 0,
tls->server_write_iv, 12);
mg_tls_derive_secret("tls13 finished", server_hs_secret, 32, NULL, 0,
tls->server_finished_key, 32);
mg_tls_derive_secret("tls13 c hs traffic", tls->handshake_secret, 32,
hello_hash, 32, client_hs_secret, 32); hello_hash, 32, client_hs_secret, 32);
mg_tls_derive_secret("tls13 key", server_hs_secret, 32, NULL, 0,
tls->enc.server_write_key, keysz);
mg_tls_derive_secret("tls13 iv", server_hs_secret, 32, NULL, 0,
tls->enc.server_write_iv, 12);
mg_tls_derive_secret("tls13 finished", server_hs_secret, 32, NULL, 0,
tls->enc.server_finished_key, 32);
mg_tls_derive_secret("tls13 key", client_hs_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 key", client_hs_secret, 32, NULL, 0,
tls->client_write_key, 16); tls->enc.client_write_key, keysz);
mg_tls_derive_secret("tls13 iv", client_hs_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 iv", client_hs_secret, 32, NULL, 0,
tls->client_write_iv, 12); tls->enc.client_write_iv, 12);
mg_tls_derive_secret("tls13 finished", client_hs_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 finished", client_hs_secret, 32, NULL, 0,
tls->client_finished_key, 32); tls->enc.client_finished_key, 32);
mg_tls_hexdump("s hs traffic", server_hs_secret, 32); mg_tls_hexdump("s hs traffic", server_hs_secret, 32);
mg_tls_hexdump("s key", tls->server_write_key, 16); mg_tls_hexdump("s key", tls->enc.server_write_key, keysz);
mg_tls_hexdump("s iv", tls->server_write_iv, 12); mg_tls_hexdump("s iv", tls->enc.server_write_iv, 12);
mg_tls_hexdump("s finished", tls->server_finished_key, 32); mg_tls_hexdump("s finished", tls->enc.server_finished_key, 32);
mg_tls_hexdump("c hs traffic", client_hs_secret, 32); mg_tls_hexdump("c hs traffic", client_hs_secret, 32);
mg_tls_hexdump("c key", tls->client_write_key, 16); mg_tls_hexdump("c key", tls->enc.client_write_key, keysz);
mg_tls_hexdump("c iv", tls->client_write_iv, 16); mg_tls_hexdump("c iv", tls->enc.client_write_iv, 12);
mg_tls_hexdump("c finished", tls->client_finished_key, 32); mg_tls_hexdump("c finished", tls->enc.client_finished_key, 32);
#ifdef MG_TLS_SSLKEYLOGFILE
mg_ssl_key_log("SERVER_HANDSHAKE_TRAFFIC_SECRET", tls->random, mg_ssl_key_log("SERVER_HANDSHAKE_TRAFFIC_SECRET", tls->random,
server_hs_secret, 32); server_hs_secret, 32);
mg_ssl_key_log("CLIENT_HANDSHAKE_TRAFFIC_SECRET", tls->random, mg_ssl_key_log("CLIENT_HANDSHAKE_TRAFFIC_SECRET", tls->random,
client_hs_secret, 32); client_hs_secret, 32);
#endif
} }
static void mg_tls_generate_application_keys(struct mg_connection *c) { static void mg_tls_generate_application_keys(struct mg_connection *c) {
@ -299,40 +313,47 @@ static void mg_tls_generate_application_keys(struct mg_connection *c) {
uint8_t master_secret[32]; uint8_t master_secret[32];
uint8_t server_secret[32]; uint8_t server_secret[32];
uint8_t client_secret[32]; uint8_t client_secret[32];
#if CHACHA20
const size_t keysz = 32;
#else
const size_t keysz = 16;
#endif
mg_sha256_ctx sha256; mg_sha256_ctx sha256;
memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx));
mg_sha256_final(hash, &sha256); mg_sha256_final(hash, &sha256);
mg_tls_derive_secret("tls13 derived", tls->handshake_secret, 32, mg_tls_derive_secret("tls13 derived", tls->enc.handshake_secret, 32,
zeros_sha256_digest, 32, premaster_secret, 32); zeros_sha256_digest, 32, premaster_secret, 32);
mg_hmac_sha256(master_secret, premaster_secret, 32, zeros, 32); mg_hmac_sha256(master_secret, premaster_secret, 32, zeros, 32);
mg_tls_derive_secret("tls13 s ap traffic", master_secret, 32, hash, 32, mg_tls_derive_secret("tls13 s ap traffic", master_secret, 32, hash, 32,
server_secret, 32); server_secret, 32);
mg_tls_derive_secret("tls13 key", server_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 key", server_secret, 32, NULL, 0,
tls->server_write_key, 16); tls->enc.server_write_key, keysz);
mg_tls_derive_secret("tls13 iv", server_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 iv", server_secret, 32, NULL, 0,
tls->server_write_iv, 12); tls->enc.server_write_iv, 12);
mg_tls_derive_secret("tls13 c ap traffic", master_secret, 32, hash, 32, mg_tls_derive_secret("tls13 c ap traffic", master_secret, 32, hash, 32,
client_secret, 32); client_secret, 32);
mg_tls_derive_secret("tls13 key", client_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 key", client_secret, 32, NULL, 0,
tls->client_write_key, 16); tls->enc.client_write_key, keysz);
mg_tls_derive_secret("tls13 iv", client_secret, 32, NULL, 0, mg_tls_derive_secret("tls13 iv", client_secret, 32, NULL, 0,
tls->client_write_iv, 12); tls->enc.client_write_iv, 12);
mg_tls_hexdump("s ap traffic", server_secret, 32); mg_tls_hexdump("s ap traffic", server_secret, 32);
mg_tls_hexdump("s key", tls->server_write_key, 16); mg_tls_hexdump("s key", tls->enc.server_write_key, keysz);
mg_tls_hexdump("s iv", tls->server_write_iv, 12); mg_tls_hexdump("s iv", tls->enc.server_write_iv, 12);
mg_tls_hexdump("s finished", tls->server_finished_key, 32); mg_tls_hexdump("s finished", tls->enc.server_finished_key, 32);
mg_tls_hexdump("c ap traffic", client_secret, 32); mg_tls_hexdump("c ap traffic", client_secret, 32);
mg_tls_hexdump("c key", tls->client_write_key, 16); mg_tls_hexdump("c key", tls->enc.client_write_key, keysz);
mg_tls_hexdump("c iv", tls->client_write_iv, 16); mg_tls_hexdump("c iv", tls->enc.client_write_iv, 12);
mg_tls_hexdump("c finished", tls->client_finished_key, 32); mg_tls_hexdump("c finished", tls->enc.client_finished_key, 32);
tls->sseq = tls->cseq = 0; tls->enc.sseq = tls->enc.cseq = 0;
#ifdef MG_TLS_SSLKEYLOGFILE
mg_ssl_key_log("SERVER_TRAFFIC_SECRET_0", tls->random, server_secret, 32); mg_ssl_key_log("SERVER_TRAFFIC_SECRET_0", tls->random, server_secret, 32);
mg_ssl_key_log("CLIENT_TRAFFIC_SECRET_0", tls->random, client_secret, 32); mg_ssl_key_log("CLIENT_TRAFFIC_SECRET_0", tls->random, client_secret, 32);
#endif
} }
// AES GCM encryption of the message + put encoded data into the write buffer // AES GCM encryption of the message + put encoded data into the write buffer
@ -350,21 +371,21 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg,
(uint8_t) (encsz & 0xff)}; (uint8_t) (encsz & 0xff)};
uint8_t nonce[12]; uint8_t nonce[12];
mg_gcm_initialize(); uint32_t seq = c->is_client ? tls->enc.cseq : tls->enc.sseq;
uint8_t *key =
c->is_client ? tls->enc.client_write_key : tls->enc.server_write_key;
uint8_t *iv =
c->is_client ? tls->enc.client_write_iv : tls->enc.server_write_iv;
if (c->is_client) { #if !CHACHA20
memmove(nonce, tls->client_write_iv, sizeof(tls->client_write_iv)); mg_gcm_initialize();
nonce[8] ^= (uint8_t) ((tls->cseq >> 24) & 255U); #endif
nonce[9] ^= (uint8_t) ((tls->cseq >> 16) & 255U);
nonce[10] ^= (uint8_t) ((tls->cseq >> 8) & 255U); memmove(nonce, iv, sizeof(nonce));
nonce[11] ^= (uint8_t) ((tls->cseq) & 255U); nonce[8] ^= (uint8_t) ((seq >> 24) & 255U);
} else { nonce[9] ^= (uint8_t) ((seq >> 16) & 255U);
memmove(nonce, tls->server_write_iv, sizeof(tls->server_write_iv)); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U);
nonce[8] ^= (uint8_t) ((tls->sseq >> 24) & 255U); nonce[11] ^= (uint8_t) ((seq) & 255U);
nonce[9] ^= (uint8_t) ((tls->sseq >> 16) & 255U);
nonce[10] ^= (uint8_t) ((tls->sseq >> 8) & 255U);
nonce[11] ^= (uint8_t) ((tls->sseq) & 255U);
}
mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr)); mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr));
mg_iobuf_resize(wio, wio->len + encsz); mg_iobuf_resize(wio, wio->len + encsz);
@ -372,17 +393,18 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg,
tag = wio->buf + wio->len + msgsz + 1; tag = wio->buf + wio->len + msgsz + 1;
memmove(outmsg, msg, msgsz); memmove(outmsg, msg, msgsz);
outmsg[msgsz] = msgtype; outmsg[msgsz] = msgtype;
if (c->is_client) { #if CHACHA20
mg_aes_gcm_encrypt(outmsg, outmsg, msgsz + 1, tls->client_write_key, (void) tag; // tag is only used in aes gcm
sizeof(tls->client_write_key), nonce, sizeof(nonce), uint8_t enc[8192];
associated_data, sizeof(associated_data), tag, 16); size_t n =
tls->cseq++; mg_chacha20_poly1305_encrypt(enc, key, nonce, associated_data,
} else { sizeof(associated_data), outmsg, msgsz + 1);
mg_aes_gcm_encrypt(outmsg, outmsg, msgsz + 1, tls->server_write_key, memmove(outmsg, enc, n);
sizeof(tls->server_write_key), nonce, sizeof(nonce), #else
associated_data, sizeof(associated_data), tag, 16); mg_aes_gcm_encrypt(outmsg, outmsg, msgsz + 1, key, 16, nonce, sizeof(nonce),
tls->sseq++; associated_data, sizeof(associated_data), tag, 16);
} #endif
c->is_client ? tls->enc.cseq++ : tls->enc.sseq++;
wio->len += encsz; wio->len += encsz;
} }
@ -394,6 +416,13 @@ static int mg_tls_recv_record(struct mg_connection *c) {
uint8_t *msg; uint8_t *msg;
uint8_t nonce[12]; uint8_t nonce[12];
int r; int r;
uint32_t seq = c->is_client ? tls->enc.sseq : tls->enc.cseq;
uint8_t *key =
c->is_client ? tls->enc.server_write_key : tls->enc.client_write_key;
uint8_t *iv =
c->is_client ? tls->enc.server_write_iv : tls->enc.client_write_iv;
if (tls->recv.len > 0) { if (tls->recv.len > 0) {
return 0; /* some data from previous record is still present */ return 0; /* some data from previous record is still present */
} }
@ -415,43 +444,47 @@ static int mg_tls_recv_record(struct mg_connection *c) {
} }
} }
#if !CHACHA20
mg_gcm_initialize(); mg_gcm_initialize();
#endif
msgsz = MG_LOAD_BE16(rio->buf + 3); msgsz = MG_LOAD_BE16(rio->buf + 3);
msg = rio->buf + 5; msg = rio->buf + 5;
if (c->is_client) { memmove(nonce, iv, sizeof(nonce));
memmove(nonce, tls->server_write_iv, sizeof(tls->server_write_iv)); nonce[8] ^= (uint8_t) ((seq >> 24) & 255U);
nonce[8] ^= (uint8_t) ((tls->sseq >> 24) & 255U); nonce[9] ^= (uint8_t) ((seq >> 16) & 255U);
nonce[9] ^= (uint8_t) ((tls->sseq >> 16) & 255U); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U);
nonce[10] ^= (uint8_t) ((tls->sseq >> 8) & 255U); nonce[11] ^= (uint8_t) ((seq) & 255U);
nonce[11] ^= (uint8_t) ((tls->sseq) & 255U); #if CHACHA20
mg_aes_gcm_decrypt(msg, msg, msgsz - 16, tls->server_write_key, uint8_t dec[8192];
sizeof(tls->server_write_key), nonce, sizeof(nonce)); size_t n = mg_chacha20_poly1305_decrypt(dec, key, nonce, msg, msgsz);
tls->sseq++; memmove(msg, dec, n);
} else { #else
memmove(nonce, tls->client_write_iv, sizeof(tls->client_write_iv)); mg_aes_gcm_decrypt(msg, msg, msgsz - 16, key, 16, nonce, sizeof(nonce));
nonce[8] ^= (uint8_t) ((tls->cseq >> 24) & 255U); #endif
nonce[9] ^= (uint8_t) ((tls->cseq >> 16) & 255U);
nonce[10] ^= (uint8_t) ((tls->cseq >> 8) & 255U);
nonce[11] ^= (uint8_t) ((tls->cseq) & 255U);
mg_aes_gcm_decrypt(msg, msg, msgsz - 16, tls->client_write_key,
sizeof(tls->client_write_key), nonce, sizeof(nonce));
tls->cseq++;
}
r = msgsz - 16 - 1; r = msgsz - 16 - 1;
tls->content_type = msg[msgsz - 16 - 1]; tls->content_type = msg[msgsz - 16 - 1];
tls->recv.buf = msg; tls->recv.buf = msg;
tls->recv.size = tls->recv.len = msgsz - 16 - 1; tls->recv.size = tls->recv.len = msgsz - 16 - 1;
c->is_client ? tls->enc.sseq++ : tls->enc.cseq++;
return r; return r;
} }
static void mg_tls_calc_cert_verify_hash(struct mg_connection *c, static void mg_tls_calc_cert_verify_hash(struct mg_connection *c,
uint8_t hash[32]) { uint8_t hash[32], int is_client) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
uint8_t sig_content[130] = { uint8_t server_context[34] = "TLS 1.3, server CertificateVerify";
" " uint8_t client_context[34] = "TLS 1.3, client CertificateVerify";
" " uint8_t sig_content[130];
"TLS 1.3, server CertificateVerify\0"};
mg_sha256_ctx sha256; mg_sha256_ctx sha256;
memset(sig_content, 0x20, 64);
if (is_client) {
memmove(sig_content + 64, client_context, sizeof(client_context));
} else {
memmove(sig_content + 64, server_context, sizeof(server_context));
}
memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx));
mg_sha256_final(sig_content + 98, &sha256); mg_sha256_final(sig_content + 98, &sha256);
@ -528,51 +561,28 @@ static void mg_tls_server_send_hello(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
struct mg_iobuf *wio = &tls->send; struct mg_iobuf *wio = &tls->send;
// clang-format off
uint8_t msg_server_hello[122] = { uint8_t msg_server_hello[122] = {
// server hello, tls 1.2 // server hello, tls 1.2
0x02, 0x02, 0x00, 0x00, 0x76, 0x03, 0x03,
0x00, // random (32 bytes)
0x00, PLACEHOLDER_32B,
0x76, // session ID length + session ID (32 bytes)
0x03, 0x20, PLACEHOLDER_32B,
0x03,
// random (32 bytes)
PLACEHOLDER_32B,
// session ID length + session ID (32 bytes)
0x20,
PLACEHOLDER_32B,
#if defined(CHACHA20) && CHACHA20 #if defined(CHACHA20) && CHACHA20
// TLS_CHACHA20_POLY1305_SHA256 + no compression // TLS_CHACHA20_POLY1305_SHA256 + no compression
0x13, 0x13, 0x03, 0x00,
0x03,
0x00,
#else #else
// TLS_AES_128_GCM_SHA256 + no compression // TLS_AES_128_GCM_SHA256 + no compression
0x13, 0x13, 0x01, 0x00,
0x01,
0x00,
#endif #endif
// extensions + keyshare // extensions + keyshare
0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20,
0x2e, // x25519 keyshare
0x00, PLACEHOLDER_32B,
0x33, // supported versions (tls1.3 == 0x304)
0x00, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04};
0x24, // clang-format on
0x00,
0x1d,
0x00,
0x20,
// x25519 keyshare
PLACEHOLDER_32B,
// supported versions (tls1.3 == 0x304)
0x00,
0x2b,
0x00,
0x02,
0x03,
0x04
};
// calculate keyshare // calculate keyshare
uint8_t x25519_pub[X25519_BYTES]; uint8_t x25519_pub[X25519_BYTES];
@ -607,7 +617,7 @@ static void mg_tls_server_send_ext(struct mg_connection *c) {
static void mg_tls_server_send_cert(struct mg_connection *c) { static void mg_tls_server_send_cert(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
// server DER certificate (empty) // server DER certificate (empty)
size_t n = tls->server_cert_der.len; size_t n = tls->cert_der.len;
uint8_t *cert = (uint8_t *) calloc(1, 13 + n); uint8_t *cert = (uint8_t *) calloc(1, 13 + n);
if (cert == NULL) { if (cert == NULL) {
mg_error(c, "tls cert oom"); mg_error(c, "tls cert oom");
@ -626,7 +636,7 @@ static void mg_tls_server_send_cert(struct mg_connection *c) {
cert[9] = (uint8_t) (((n) >> 8) & 255U); cert[9] = (uint8_t) (((n) >> 8) & 255U);
cert[10] = (uint8_t) (n & 255U); cert[10] = (uint8_t) (n & 255U);
// bytes 11+ are certificate in DER format // bytes 11+ are certificate in DER format
memmove(cert + 11, tls->server_cert_der.buf, n); memmove(cert + 11, tls->cert_der.buf, n);
cert[11 + n] = cert[12 + n] = 0; // certificate extensions (none) cert[11 + n] = cert[12 + n] = 0; // certificate extensions (none)
mg_sha256_update(&tls->sha256, cert, 13 + n); mg_sha256_update(&tls->sha256, cert, 13 + n);
mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE); mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE);
@ -655,7 +665,7 @@ static void finish_SHA256(const MG_UECC_HashContext *base,
mg_sha256_final(hash_result, &c->ctx); mg_sha256_final(hash_result, &c->ctx);
} }
static void mg_tls_server_send_cert_verify(struct mg_connection *c) { static void mg_tls_send_cert_verify(struct mg_connection *c, int is_client) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
// server certificate verify packet // server certificate verify packet
uint8_t verify[82] = {0x0f, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00}; uint8_t verify[82] = {0x0f, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00};
@ -667,10 +677,10 @@ static void mg_tls_server_send_cert_verify(struct mg_connection *c) {
int neg1, neg2; int neg1, neg2;
uint8_t sig[64] = {0}; uint8_t sig[64] = {0};
mg_tls_calc_cert_verify_hash(c, (uint8_t *) hash); mg_tls_calc_cert_verify_hash(c, (uint8_t *) hash, is_client);
mg_uecc_sign_deterministic(tls->server_key, hash, sizeof(hash), &ctx.uECC, mg_uecc_sign_deterministic(tls->ec_key, hash, sizeof(hash), &ctx.uECC, sig,
sig, mg_uecc_secp256r1()); mg_uecc_secp256r1());
neg1 = !!(sig[0] & 0x80); neg1 = !!(sig[0] & 0x80);
neg2 = !!(sig[32] & 0x80); neg2 = !!(sig[32] & 0x80);
@ -700,7 +710,7 @@ static void mg_tls_server_send_finish(struct mg_connection *c) {
uint8_t finish[36] = {0x14, 0, 0, 32}; uint8_t finish[36] = {0x14, 0, 0, 32};
memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx));
mg_sha256_final(hash, &sha256); mg_sha256_final(hash, &sha256);
mg_hmac_sha256(finish + 4, tls->server_finished_key, 32, hash, 32); mg_hmac_sha256(finish + 4, tls->enc.server_finished_key, 32, hash, 32);
mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE);
mg_io_send(c, wio->buf, wio->len); mg_io_send(c, wio->buf, wio->len);
wio->len = 0; wio->len = 0;
@ -732,140 +742,73 @@ static void mg_tls_client_send_hello(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
struct mg_iobuf *wio = &tls->send; struct mg_iobuf *wio = &tls->send;
const char *hostname = tls->hostname;
size_t hostnamesz = strlen(tls->hostname);
uint8_t x25519_pub[X25519_BYTES]; uint8_t x25519_pub[X25519_BYTES];
uint8_t msg_client_hello[162 + 32] = { // the only signature algorithm we actually support
// TLS Client Hello header reported as TLS1.2 (5) uint8_t secp256r1_sig_algs[8] = {
0x16, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x02, 0x04, 0x03,
0x03,
0x01,
0x00,
0xfe,
// server hello, tls 1.2 (6)
0x01,
0x00,
0x00,
0x8c,
0x03,
0x03,
// random (32 bytes)
PLACEHOLDER_32B,
// session ID length + session ID (32 bytes)
0x20,
PLACEHOLDER_32B,
#if defined(CHACHA20) && CHACHA20
// TLS_CHACHA20_POLY1305_SHA256 + no compression
0x13,
0x03,
0x00,
#else
0x00,
0x02, // size = 2 bytes
0x13,
0x01, // TLS_AES_128_GCM_SHA256
0x01,
0x00, // no compression
#endif
// extensions + keyshare
0x00,
0xfe,
// x25519 keyshare
0x00,
0x33,
0x00,
0x26,
0x00,
0x24,
0x00,
0x1d,
0x00,
0x20,
PLACEHOLDER_32B,
// supported groups (x25519)
0x00,
0x0a,
0x00,
0x04,
0x00,
0x02,
0x00,
0x1d,
// supported versions (tls1.3 == 0x304)
0x00,
0x2b,
0x00,
0x03,
0x02,
0x03,
0x04,
// session ticket (none)
0x00,
0x23,
0x00,
0x00,
// signature algorithms (we don't care, so list all the common ones)
0x00,
0x0d,
0x00,
0x24,
0x00,
0x22,
0x04,
0x03,
0x05,
0x03,
0x06,
0x03,
0x08,
0x07,
0x08,
0x08,
0x08,
0x1a,
0x08,
0x1b,
0x08,
0x1c,
0x08,
0x09,
0x08,
0x0a,
0x08,
0x0b,
0x08,
0x04,
0x08,
0x05,
0x08,
0x06,
0x04,
0x01,
0x05,
0x01,
0x06,
0x01,
// server name
0x00,
0x00,
0x00,
0xfe,
0x00,
0xfe,
0x00,
0x00,
0xfe
}; };
// all popular signature algorithms (if we don't care about verification)
uint8_t all_sig_algs[34] = {
0x00, 0x0d, 0x00, 0x1e, 0x00, 0x1c, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03,
0x08, 0x07, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04,
0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01};
uint8_t server_name_ext[9] = {0x00, 0x00, 0x00, 0xfe, 0x00,
0xfe, 0x00, 0x00, 0xfe};
// patch ClientHello with correct hostname length + offset: // clang-format off
MG_STORE_BE16(msg_client_hello + 3, hostnamesz + 189); uint8_t msg_client_hello[145] = {
MG_STORE_BE16(msg_client_hello + 7, hostnamesz + 185); // TLS Client Hello header reported as TLS1.2 (5)
MG_STORE_BE16(msg_client_hello + 82, hostnamesz + 110); 0x16, 0x03, 0x03, 0x00, 0xfe,
MG_STORE_BE16(msg_client_hello + 187, hostnamesz + 5); // client hello, tls 1.2 (6)
MG_STORE_BE16(msg_client_hello + 189, hostnamesz + 3); 0x01, 0x00, 0x00, 0x8c, 0x03, 0x03,
MG_STORE_BE16(msg_client_hello + 192, hostnamesz); // random (32 bytes)
PLACEHOLDER_32B,
// session ID length + session ID (32 bytes)
0x20, PLACEHOLDER_32B, 0x00,
0x02, // size = 2 bytes
#if defined(CHACHA20) && CHACHA20
// TLS_CHACHA20_POLY1305_SHA256
0x13, 0x03,
#else
// TLS_AES_128_GCM_SHA256
0x13, 0x01,
#endif
// no compression
0x01, 0x00,
// extensions + keyshare
0x00, 0xfe,
// x25519 keyshare
0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20,
PLACEHOLDER_32B,
// supported groups (x25519)
0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x1d,
// supported versions (tls1.3 == 0x304)
0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04,
// session ticket (none)
0x00, 0x23, 0x00, 0x00, // 144 bytes till here
};
// clang-format on
const char *hostname = tls->hostname;
size_t hostnamesz = strlen(tls->hostname);
size_t hostname_extsz = hostnamesz ? hostnamesz + 9 : 0;
uint8_t *sig_alg = tls->skip_verification ? all_sig_algs : secp256r1_sig_algs;
size_t sig_alg_sz = tls->skip_verification ? sizeof(all_sig_algs)
: sizeof(secp256r1_sig_algs);
// patch ClientHello with correct hostname ext length (if any)
MG_STORE_BE16(msg_client_hello + 3,
hostname_extsz + 183 - 9 - 34 + sig_alg_sz);
MG_STORE_BE16(msg_client_hello + 7,
hostname_extsz + 179 - 9 - 34 + sig_alg_sz);
MG_STORE_BE16(msg_client_hello + 82,
hostname_extsz + 104 - 9 - 34 + sig_alg_sz);
if (hostnamesz > 0) {
MG_STORE_BE16(server_name_ext + 2, hostnamesz + 5);
MG_STORE_BE16(server_name_ext + 4, hostnamesz + 3);
MG_STORE_BE16(server_name_ext + 7, hostnamesz);
}
// calculate keyshare // calculate keyshare
mg_random(tls->x25519_cli, sizeof(tls->x25519_cli)); mg_random(tls->x25519_cli, sizeof(tls->x25519_cli));
@ -878,12 +821,18 @@ static void mg_tls_client_send_hello(struct mg_connection *c) {
memmove(msg_client_hello + 44, tls->session_id, sizeof(tls->session_id)); memmove(msg_client_hello + 44, tls->session_id, sizeof(tls->session_id));
memmove(msg_client_hello + 94, x25519_pub, sizeof(x25519_pub)); memmove(msg_client_hello + 94, x25519_pub, sizeof(x25519_pub));
// server hello message // client hello message
mg_iobuf_add(wio, wio->len, msg_client_hello, sizeof(msg_client_hello)); mg_iobuf_add(wio, wio->len, msg_client_hello, sizeof(msg_client_hello));
mg_iobuf_add(wio, wio->len, hostname, strlen(hostname));
mg_sha256_update(&tls->sha256, msg_client_hello + 5, mg_sha256_update(&tls->sha256, msg_client_hello + 5,
sizeof(msg_client_hello) - 5); sizeof(msg_client_hello) - 5);
mg_sha256_update(&tls->sha256, (uint8_t *) hostname, strlen(hostname)); mg_iobuf_add(wio, wio->len, sig_alg, sig_alg_sz);
mg_sha256_update(&tls->sha256, sig_alg, sig_alg_sz);
if (hostnamesz > 0) {
mg_iobuf_add(wio, wio->len, server_name_ext, sizeof(server_name_ext));
mg_iobuf_add(wio, wio->len, hostname, hostnamesz);
mg_sha256_update(&tls->sha256, server_name_ext, sizeof(server_name_ext));
mg_sha256_update(&tls->sha256, (uint8_t *) hostname, hostnamesz);
}
// change cipher message // change cipher message
mg_iobuf_add(wio, wio->len, (const char *) "\x14\x03\x03\x00\x01\x01", 6); mg_iobuf_add(wio, wio->len, (const char *) "\x14\x03\x03\x00\x01\x01", 6);
@ -973,6 +922,12 @@ static int mg_tls_client_recv_cert(struct mg_connection *c) {
if (mg_tls_recv_record(c) < 0) { if (mg_tls_recv_record(c) < 0) {
return -1; return -1;
} }
if (tls->recv.buf[0] == MG_TLS_CERTIFICATE_REQUEST) {
MG_VERBOSE(("got certificate request"));
mg_tls_drop_message(c);
tls->cert_requested = 1;
return -1;
}
if (tls->recv.buf[0] != MG_TLS_CERTIFICATE) { if (tls->recv.buf[0] != MG_TLS_CERTIFICATE) {
mg_error(c, "expected server certificate but got msg 0x%02x", mg_error(c, "expected server certificate but got msg 0x%02x",
tls->recv.buf[0]); tls->recv.buf[0]);
@ -1059,7 +1014,7 @@ static int mg_tls_client_recv_cert(struct mg_connection *c) {
} while (0); } while (0);
mg_tls_drop_message(c); mg_tls_drop_message(c);
mg_tls_calc_cert_verify_hash(c, tls->sighash); mg_tls_calc_cert_verify_hash(c, tls->sighash, 0);
return 0; return 0;
} }
@ -1141,7 +1096,7 @@ static void mg_tls_client_send_finish(struct mg_connection *c) {
uint8_t finish[36] = {0x14, 0, 0, 32}; uint8_t finish[36] = {0x14, 0, 0, 32};
memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx));
mg_sha256_final(hash, &sha256); mg_sha256_final(hash, &sha256);
mg_hmac_sha256(finish + 4, tls->client_finished_key, 32, hash, 32); mg_hmac_sha256(finish + 4, tls->enc.client_finished_key, 32, hash, 32);
mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE);
mg_io_send(c, wio->buf, wio->len); mg_io_send(c, wio->buf, wio->len);
wio->len = 0; wio->len = 0;
@ -1182,8 +1137,23 @@ static void mg_tls_client_handshake(struct mg_connection *c) {
if (mg_tls_client_recv_finish(c) < 0) { if (mg_tls_client_recv_finish(c) < 0) {
break; break;
} }
mg_tls_client_send_finish(c); if (tls->cert_requested) {
mg_tls_generate_application_keys(c); /* for mTLS we should generate application keys at this point
* but then restore handshake keys and continue with
* the rest of the handshake */
struct tls_enc app_keys;
struct tls_enc hs_keys = tls->enc;
mg_tls_generate_application_keys(c);
app_keys = tls->enc;
tls->enc = hs_keys;
mg_tls_server_send_cert(c);
mg_tls_send_cert_verify(c, 1);
mg_tls_client_send_finish(c);
tls->enc = app_keys;
} else {
mg_tls_client_send_finish(c);
mg_tls_generate_application_keys(c);
}
tls->state = MG_TLS_STATE_CLIENT_CONNECTED; tls->state = MG_TLS_STATE_CLIENT_CONNECTED;
c->is_tls_hs = 0; c->is_tls_hs = 0;
break; break;
@ -1202,7 +1172,7 @@ static void mg_tls_server_handshake(struct mg_connection *c) {
mg_tls_generate_handshake_keys(c); mg_tls_generate_handshake_keys(c);
mg_tls_server_send_ext(c); mg_tls_server_send_ext(c);
mg_tls_server_send_cert(c); mg_tls_server_send_cert(c);
mg_tls_server_send_cert_verify(c); mg_tls_send_cert_verify(c, 0);
mg_tls_server_send_finish(c); mg_tls_server_send_finish(c);
tls->state = MG_TLS_STATE_SERVER_NEGOTIATED; tls->state = MG_TLS_STATE_SERVER_NEGOTIATED;
// fallthrough // fallthrough
@ -1286,14 +1256,13 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
tls->hostname[opts->name.len] = 0; tls->hostname[opts->name.len] = 0;
} }
if (c->is_client) { if (opts->cert.buf == NULL) {
tls->server_cert_der.buf = NULL; MG_VERBOSE(("no certificate provided"));
return; return;
} }
// parse PEM or DER certificate // parse PEM or DER certificate
if (mg_parse_pem(opts->cert, mg_str_s("CERTIFICATE"), &tls->server_cert_der) < if (mg_parse_pem(opts->cert, mg_str_s("CERTIFICATE"), &tls->cert_der) < 0) {
0) {
MG_ERROR(("Failed to load certificate")); MG_ERROR(("Failed to load certificate"));
return; return;
} }
@ -1318,7 +1287,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
if (memcmp(key.buf + 2, "\x02\x01\x01\x04\x20", 5) != 0) { if (memcmp(key.buf + 2, "\x02\x01\x01\x04\x20", 5) != 0) {
MG_ERROR(("EC private key: ASN.1 bad data")); MG_ERROR(("EC private key: ASN.1 bad data"));
} }
memmove(tls->server_key, key.buf + 7, 32); memmove(tls->ec_key, key.buf + 7, 32);
free((void *) key.buf); free((void *) key.buf);
} else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) { } else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) {
mg_error(c, "PKCS8 private key format is not supported"); mg_error(c, "PKCS8 private key format is not supported");
@ -1331,7 +1300,7 @@ void mg_tls_free(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
if (tls != NULL) { if (tls != NULL) {
mg_iobuf_free(&tls->send); mg_iobuf_free(&tls->send);
free((void *) tls->server_cert_der.buf); free((void *) tls->cert_der.buf);
} }
free(c->tls); free(c->tls);
c->tls = NULL; c->tls = NULL;
@ -1359,6 +1328,7 @@ long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
if (r < 0) { if (r < 0) {
return r; return r;
} }
if (tls->content_type != MG_TLS_APP_DATA) { if (tls->content_type != MG_TLS_APP_DATA) {
tls->recv.len = 0; tls->recv.len = 0;
mg_tls_drop_record(c); mg_tls_drop_record(c);

1337
src/tls_chacha20.c Normal file

File diff suppressed because it is too large Load Diff

110
src/tls_chacha20.h Normal file
View File

@ -0,0 +1,110 @@
// portable8439 v1.0.1
// Source: https://github.com/DavyLandman/portable8439
// Licensed under CC0-1.0
// Contains poly1305-donna e6ad6e091d30d7f4ec2d4f978be1fcfcbce72781 (Public
// Domain)
#include "arch.h"
#include "config.h"
#ifndef __PORTABLE_8439_H
#define __PORTABLE_8439_H
#if defined(__cplusplus)
extern "C" {
#endif
// provide your own decl specificier like -DPORTABLE_8439_DECL=ICACHE_RAM_ATTR
#ifndef PORTABLE_8439_DECL
#define PORTABLE_8439_DECL
#endif
/*
This library implements RFC 8439 a.k.a. ChaCha20-Poly1305 AEAD
You can use this library to avoid attackers mutating or reusing your
encrypted messages. This does assume you never reuse a nonce+key pair and,
if possible, carefully pick your associated data.
*/
// Make sure we are either nested in C++ or running in a C99+ compiler
#if !defined(__cplusplus) && !defined(_MSC_VER) && \
(!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#error "C99 or newer required"
#endif
// #if CHAR_BIT > 8
// # error "Systems without native octals not suppoted"
// #endif
#if defined(_MSC_VER) || defined(__cplusplus)
// add restrict support is possible
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || defined(__clang__) || \
defined(__GNUC__)
#define restrict __restrict
#else
#define restrict
#endif
#endif
#define RFC_8439_TAG_SIZE (16)
#define RFC_8439_KEY_SIZE (32)
#define RFC_8439_NONCE_SIZE (12)
/*
Encrypt/Seal plain text bytes into a cipher text that can only be
decrypted by knowing the key, nonce and associated data.
input:
- key: RFC_8439_KEY_SIZE bytes that all parties have agreed
upon beforehand
- nonce: RFC_8439_NONCE_SIZE bytes that should never be repeated
for the same key. A counter or a pseudo-random value are fine.
- ad: associated data to include with calculating the tag of the
cipher text. Can be null for empty.
- plain_text: data to be encrypted, pointer + size should not overlap
with cipher_text pointer
output:
- cipher_text: encrypted plain_text with a tag appended. Make sure to
allocate at least plain_text_size + RFC_8439_TAG_SIZE
returns:
- size of bytes written to cipher_text, can be -1 if overlapping
pointers are passed for plain_text and cipher_text
*/
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
uint8_t *restrict cipher_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
size_t ad_size, const uint8_t *restrict plain_text, size_t plain_text_size);
/*
Decrypt/unseal cipher text given the right key, nonce, and additional data.
input:
- key: RFC_8439_KEY_SIZE bytes that all parties have agreed
upon beforehand
- nonce: RFC_8439_NONCE_SIZE bytes that should never be repeated for
the same key. A counter or a pseudo-random value are fine.
- ad: associated data to include with calculating the tag of the
cipher text. Can be null for empty.
- cipher_text: encrypted message.
output:
- plain_text: data to be encrypted, pointer + size should not overlap
with cipher_text pointer, leave at least enough room for
cipher_text_size - RFC_8439_TAG_SIZE
returns:
- size of bytes written to plain_text, -1 signals either:
- incorrect key/nonce/ad
- corrupted cipher_text
- overlapping pointers are passed for plain_text and cipher_text
*/
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_SIZE],
const uint8_t *restrict cipher_text, size_t cipher_text_size);
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -93,6 +93,19 @@ static int mg_bio_write(BIO *bio, const char *buf, int len) {
return len; return len;
} }
#ifdef MG_TLS_SSLKEYLOGFILE
static void ssl_keylog_cb(const SSL *ssl, const char *line) {
char *keylogfile = getenv("SSLKEYLOGFILE");
if (keylogfile == NULL) {
return;
}
FILE *f = fopen(keylogfile, "a");
fprintf(f, "%s\n", line);
fflush(f);
fclose(f);
}
#endif
void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
const char *id = "mongoose"; const char *id = "mongoose";
@ -112,6 +125,9 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
MG_DEBUG(("%lu Setting TLS", c->id)); MG_DEBUG(("%lu Setting TLS", c->id));
tls->ctx = c->is_client ? SSL_CTX_new(SSLv23_client_method()) tls->ctx = c->is_client ? SSL_CTX_new(SSLv23_client_method())
: SSL_CTX_new(SSLv23_server_method()); : SSL_CTX_new(SSLv23_server_method());
#if MG_TLS_SSLKEYLOGFILE
SSL_CTX_set_keylog_callback(tls->ctx, ssl_keylog_cb);
#endif
if ((tls->ssl = SSL_new(tls->ctx)) == NULL) { if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
mg_error(c, "SSL_new"); mg_error(c, "SSL_new");
goto fail; goto fail;

View File

@ -202,7 +202,7 @@ mongoose.c: Makefile $(wildcard ../src/*.c) $(wildcard ../src/drivers/*.c)
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
mongoose.h: $(HDRS) Makefile mongoose.h: $(HDRS) Makefile
cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/device.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/device.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean: clean_examples clean_refprojs clean_tutorials clean_examples_embedded clean: clean_examples clean_refprojs clean_tutorials clean_examples_embedded

View File

@ -2361,7 +2361,8 @@ static void test_util(void) {
{ {
uint32_t val, max = (uint32_t) -1; uint32_t val, max = (uint32_t) -1;
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint32_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint32_t)) && val == 123);
mg_snprintf(buf, sizeof(buf), "%lu", max); mg_snprintf(buf, sizeof(buf), "%lu", (unsigned long) max);
ASSERT(strcmp(buf, "4294967295") == 0);
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint32_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint32_t)) && val == max);
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint32_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint32_t)) && val == 123);
ASSERT(mg_str_to_num(mg_str("11111111111111111111111111111111"), 2, &val, sizeof(uint32_t)) && val == max); ASSERT(mg_str_to_num(mg_str("11111111111111111111111111111111"), 2, &val, sizeof(uint32_t)) && val == max);