-/* $OpenBSD: tls12_record_layer.c,v 1.29 2021/05/16 15:21:10 jsing Exp $ */
+/* $OpenBSD: tls12_record_layer.c,v 1.30 2021/05/16 15:49:01 jsing Exp $ */
/*
* Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
*
#include "ssl_locl.h"
-#define TLS12_RECORD_SEQ_NUM_LEN 8
+#define TLS12_RECORD_SEQ_NUM_LEN 8
+#define TLS12_AEAD_FIXED_NONCE_MAX_LEN 12
struct tls12_record_protection {
uint16_t epoch;
uint8_t seq_num[TLS12_RECORD_SEQ_NUM_LEN];
- SSL_AEAD_CTX *aead_ctx;
+ EVP_AEAD_CTX *aead_ctx;
+
+ uint8_t *aead_fixed_nonce;
+ size_t aead_fixed_nonce_len;
+
+ size_t aead_variable_nonce_len;
+ size_t aead_tag_len;
+
+ int aead_xor_nonces;
+ int aead_variable_nonce_in_record;
EVP_CIPHER_CTX *cipher_ctx;
EVP_MD_CTX *hash_ctx;
tls12_record_protection_clear(struct tls12_record_protection *rp)
{
if (rp->aead_ctx != NULL) {
- EVP_AEAD_CTX_cleanup(&rp->aead_ctx->ctx);
+ EVP_AEAD_CTX_cleanup(rp->aead_ctx);
freezero(rp->aead_ctx, sizeof(*rp->aead_ctx));
}
+ freezero(rp->aead_fixed_nonce, rp->aead_fixed_nonce_len);
+
EVP_CIPHER_CTX_free(rp->cipher_ctx);
EVP_MD_CTX_free(rp->hash_ctx);
*overhead = 0;
if (rl->write->aead_ctx != NULL) {
- *overhead = rl->write->aead_ctx->tag_len;
+ *overhead = rl->write->aead_tag_len;
} else if (rl->write->cipher_ctx != NULL) {
eiv_len = 0;
if (rl->version != TLS1_VERSION) {
struct tls12_record_protection *rp, int is_write, CBS *mac_key, CBS *key,
CBS *iv)
{
- size_t aead_nonce_len, fixed_nonce_len;
+ size_t aead_nonce_len;
if (!tls12_record_protection_unused(rp))
return 0;
/* AES GCM cipher suites use variable nonce in record. */
if (rl->aead == EVP_aead_aes_128_gcm() ||
rl->aead == EVP_aead_aes_256_gcm())
- rp->aead_ctx->variable_nonce_in_record = 1;
+ rp->aead_variable_nonce_in_record = 1;
/* ChaCha20 Poly1305 XORs the fixed and variable nonces. */
if (rl->aead == EVP_aead_chacha20_poly1305())
- rp->aead_ctx->xor_fixed_nonce = 1;
+ rp->aead_xor_nonces = 1;
- if (!CBS_write_bytes(iv, rp->aead_ctx->fixed_nonce,
- sizeof(rp->aead_ctx->fixed_nonce), &fixed_nonce_len))
+ if (!CBS_stow(iv, &rp->aead_fixed_nonce, &rp->aead_fixed_nonce_len))
return 0;
- rp->aead_ctx->fixed_nonce_len = fixed_nonce_len;
- rp->aead_ctx->tag_len = EVP_AEAD_max_overhead(rl->aead);
- rp->aead_ctx->variable_nonce_len = 8;
+ rp->aead_tag_len = EVP_AEAD_max_overhead(rl->aead);
+ rp->aead_variable_nonce_len = 8;
aead_nonce_len = EVP_AEAD_nonce_length(rl->aead);
- if (rp->aead_ctx->xor_fixed_nonce) {
+ if (rp->aead_xor_nonces) {
/* Fixed nonce length must match, variable must not exceed. */
- if (rp->aead_ctx->fixed_nonce_len != aead_nonce_len)
+ if (rp->aead_fixed_nonce_len != aead_nonce_len)
return 0;
- if (rp->aead_ctx->variable_nonce_len > aead_nonce_len)
+ if (rp->aead_variable_nonce_len > aead_nonce_len)
return 0;
} else {
/* Concatenated nonce length must equal AEAD nonce length. */
- if (rp->aead_ctx->fixed_nonce_len +
- rp->aead_ctx->variable_nonce_len != aead_nonce_len)
+ if (rp->aead_fixed_nonce_len +
+ rp->aead_variable_nonce_len != aead_nonce_len)
return 0;
}
- if (!EVP_AEAD_CTX_init(&rp->aead_ctx->ctx, rl->aead, CBS_data(key),
+ if (!EVP_AEAD_CTX_init(rp->aead_ctx, rl->aead, CBS_data(key),
CBS_len(key), EVP_AEAD_DEFAULT_TAG_LENGTH, NULL))
return 0;
static int
tls12_record_layer_aead_concat_nonce(struct tls12_record_layer *rl,
- const SSL_AEAD_CTX *aead, const uint8_t *seq_num,
+ struct tls12_record_protection *rp, const uint8_t *seq_num,
uint8_t **out, size_t *out_len)
{
CBB cbb;
- if (aead->variable_nonce_len > SSL3_SEQUENCE_SIZE)
+ if (rp->aead_variable_nonce_len > SSL3_SEQUENCE_SIZE)
return 0;
/* Fixed nonce and variable nonce (sequence number) are concatenated. */
if (!CBB_init(&cbb, 16))
goto err;
- if (!CBB_add_bytes(&cbb, aead->fixed_nonce,
- aead->fixed_nonce_len))
+ if (!CBB_add_bytes(&cbb, rp->aead_fixed_nonce,
+ rp->aead_fixed_nonce_len))
goto err;
- if (!CBB_add_bytes(&cbb, seq_num, aead->variable_nonce_len))
+ if (!CBB_add_bytes(&cbb, seq_num, rp->aead_variable_nonce_len))
goto err;
if (!CBB_finish(&cbb, out, out_len))
goto err;
static int
tls12_record_layer_aead_xored_nonce(struct tls12_record_layer *rl,
- const SSL_AEAD_CTX *aead, const uint8_t *seq_num,
+ struct tls12_record_protection *rp, const uint8_t *seq_num,
uint8_t **out, size_t *out_len)
{
uint8_t *nonce = NULL;
CBB cbb;
int i;
- if (aead->variable_nonce_len > SSL3_SEQUENCE_SIZE)
+ if (rp->aead_variable_nonce_len > SSL3_SEQUENCE_SIZE)
return 0;
- if (aead->fixed_nonce_len < aead->variable_nonce_len)
+ if (rp->aead_fixed_nonce_len < rp->aead_variable_nonce_len)
return 0;
/*
if (!CBB_init(&cbb, 16))
goto err;
if (!CBB_add_space(&cbb, &pad,
- aead->fixed_nonce_len - aead->variable_nonce_len))
+ rp->aead_fixed_nonce_len - rp->aead_variable_nonce_len))
goto err;
- if (!CBB_add_bytes(&cbb, seq_num, aead->variable_nonce_len))
+ if (!CBB_add_bytes(&cbb, seq_num, rp->aead_variable_nonce_len))
goto err;
if (!CBB_finish(&cbb, &nonce, &nonce_len))
goto err;
- for (i = 0; i < aead->fixed_nonce_len; i++)
- nonce[i] ^= aead->fixed_nonce[i];
+ for (i = 0; i < rp->aead_fixed_nonce_len; i++)
+ nonce[i] ^= rp->aead_fixed_nonce[i];
*out = nonce;
*out_len = nonce_len;
uint8_t content_type, CBS *seq_num, CBS *fragment, uint8_t **out,
size_t *out_len)
{
- const SSL_AEAD_CTX *aead = rl->read->aead_ctx;
+ struct tls12_record_protection *rp = rl->read;
uint8_t *header = NULL, *nonce = NULL;
size_t header_len = 0, nonce_len = 0;
uint8_t *plain;
int ret = 0;
/* XXX - move to nonce allocated in record layer, matching TLSv1.3 */
- if (aead->xor_fixed_nonce) {
- if (!tls12_record_layer_aead_xored_nonce(rl, aead,
+ if (rp->aead_xor_nonces) {
+ if (!tls12_record_layer_aead_xored_nonce(rl, rp,
CBS_data(seq_num), &nonce, &nonce_len))
goto err;
- } else if (aead->variable_nonce_in_record) {
+ } else if (rp->aead_variable_nonce_in_record) {
if (!CBS_get_bytes(fragment, &var_nonce,
- aead->variable_nonce_len))
+ rp->aead_variable_nonce_len))
goto err;
- if (!tls12_record_layer_aead_concat_nonce(rl, aead,
+ if (!tls12_record_layer_aead_concat_nonce(rl, rp,
CBS_data(&var_nonce), &nonce, &nonce_len))
goto err;
} else {
- if (!tls12_record_layer_aead_concat_nonce(rl, aead,
+ if (!tls12_record_layer_aead_concat_nonce(rl, rp,
CBS_data(seq_num), &nonce, &nonce_len))
goto err;
}
/* XXX EVP_AEAD_max_tag_len vs EVP_AEAD_CTX_tag_len. */
- if (CBS_len(fragment) < aead->tag_len) {
+ if (CBS_len(fragment) < rp->aead_tag_len) {
rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
goto err;
}
/* XXX - decrypt/process in place for now. */
plain = (uint8_t *)CBS_data(fragment);
- plain_len = CBS_len(fragment) - aead->tag_len;
+ plain_len = CBS_len(fragment) - rp->aead_tag_len;
if (!tls12_record_layer_pseudo_header(rl, content_type, plain_len,
seq_num, &header, &header_len))
goto err;
- if (!EVP_AEAD_CTX_open(&aead->ctx, plain, out_len, plain_len,
+ if (!EVP_AEAD_CTX_open(rp->aead_ctx, plain, out_len, plain_len,
nonce, nonce_len, CBS_data(fragment), CBS_len(fragment),
header, header_len)) {
rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
uint8_t content_type, CBS *seq_num, const uint8_t *content,
size_t content_len, CBB *out)
{
- const SSL_AEAD_CTX *aead = rl->write->aead_ctx;
+ struct tls12_record_protection *rp = rl->write;
uint8_t *header = NULL, *nonce = NULL;
size_t header_len = 0, nonce_len = 0;
size_t enc_record_len, out_len;
int ret = 0;
/* XXX - move to nonce allocated in record layer, matching TLSv1.3 */
- if (aead->xor_fixed_nonce) {
- if (!tls12_record_layer_aead_xored_nonce(rl, aead,
+ if (rp->aead_xor_nonces) {
+ if (!tls12_record_layer_aead_xored_nonce(rl, rp,
CBS_data(seq_num), &nonce, &nonce_len))
goto err;
} else {
- if (!tls12_record_layer_aead_concat_nonce(rl, aead,
+ if (!tls12_record_layer_aead_concat_nonce(rl, rp,
CBS_data(seq_num), &nonce, &nonce_len))
goto err;
}
- if (aead->variable_nonce_in_record) {
+ if (rp->aead_variable_nonce_in_record) {
/* XXX - length check? */
if (!CBB_add_bytes(out, CBS_data(seq_num),
- aead->variable_nonce_len))
+ rp->aead_variable_nonce_len))
goto err;
}
goto err;
/* XXX EVP_AEAD_max_tag_len vs EVP_AEAD_CTX_tag_len. */
- enc_record_len = content_len + aead->tag_len;
+ enc_record_len = content_len + rp->aead_tag_len;
if (enc_record_len > SSL3_RT_MAX_ENCRYPTED_LENGTH)
goto err;
if (!CBB_add_space(out, &enc_data, enc_record_len))
goto err;
- if (!EVP_AEAD_CTX_seal(&aead->ctx, enc_data, &out_len, enc_record_len,
+ if (!EVP_AEAD_CTX_seal(rp->aead_ctx, enc_data, &out_len, enc_record_len,
nonce, nonce_len, content, content_len, header, header_len))
goto err;