diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2020-10-03 17:35:18 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2020-10-03 17:35:18 +0000 |
commit | 57ac3469dd8dcd4a3e0977fcb9e619f2213269f0 (patch) | |
tree | beb9624b1897d17738bf559cfd70a658203c3e44 /lib/libssl/t1_enc.c | |
parent | 221ee06f6ac63da03b111e2ec8fce5ccc80a4784 (diff) |
Reimplement the TLSv1.2 record handling for the read side.
This is the next step in replacing the TLSv1.2 record layer.
The existing record handling code does decryption and processing in
place, which is not ideal for various reasons, however it is retained
for now as other code depends on this behaviour. Additionally, CBC
requires special handling to avoid timing oracles - for now the
existing timing safe code is largely retained.
ok beck@ inoguchi@ tb@
Diffstat (limited to 'lib/libssl/t1_enc.c')
-rw-r--r-- | lib/libssl/t1_enc.c | 339 |
1 files changed, 5 insertions, 334 deletions
diff --git a/lib/libssl/t1_enc.c b/lib/libssl/t1_enc.c index a66c82bdca6..7a71a084349 100644 --- a/lib/libssl/t1_enc.c +++ b/lib/libssl/t1_enc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: t1_enc.c,v 1.123 2020/08/30 15:40:20 jsing Exp $ */ +/* $OpenBSD: t1_enc.c,v 1.124 2020/10/03 17:35:16 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -440,6 +440,10 @@ tls1_change_cipher_state_cipher(SSL *s, char is_read, if (!tls12_record_layer_set_read_cipher_hash(s->internal->rl, cipher_ctx, mac_ctx, stream_mac)) goto err; + + if (!tls12_record_layer_set_read_mac_key(s->internal->rl, + S3I(s)->read_mac_secret, mac_secret_size)) + goto err; } else { if (stream_mac) s->internal->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM; @@ -672,260 +676,6 @@ tls1_setup_key_block(SSL *s) return (ret); } -/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively. - * - * Returns: - * 0: (in non-constant time) if the record is publically invalid (i.e. too - * short etc). - * 1: if the record's padding is valid / the encryption was successful. - * -1: if the record's padding/AEAD-authenticator is invalid or, if sending, - * an internal error occured. - */ -int -tls1_enc(SSL *s, int send) -{ - const SSL_AEAD_CTX *aead; - const EVP_CIPHER *enc; - EVP_CIPHER_CTX *ds; - SSL3_RECORD_INTERNAL *rec; - unsigned char *seq; - unsigned long l; - int bs, i, j, k, ret, mac_size = 0; - - if (send) { - /* No longer supported. */ - return -1; - } else { - aead = s->internal->aead_read_ctx; - rec = &S3I(s)->rrec; - seq = S3I(s)->read_sequence; - } - - if (aead) { - unsigned char ad[13], *in, *out, nonce[16]; - size_t out_len, pad_len = 0; - unsigned int nonce_used; - - if (SSL_IS_DTLS(s)) { - dtls1_build_sequence_number(ad, seq, - send ? D1I(s)->w_epoch : D1I(s)->r_epoch); - } else { - memcpy(ad, seq, SSL3_SEQUENCE_SIZE); - tls1_record_sequence_increment(seq); - } - - ad[8] = rec->type; - ad[9] = (unsigned char)(s->version >> 8); - ad[10] = (unsigned char)(s->version); - - if (aead->variable_nonce_len > 8 || - aead->variable_nonce_len > sizeof(nonce)) - return -1; - - if (aead->xor_fixed_nonce) { - if (aead->fixed_nonce_len > sizeof(nonce) || - aead->variable_nonce_len > aead->fixed_nonce_len) - return -1; /* Should never happen. */ - pad_len = aead->fixed_nonce_len - aead->variable_nonce_len; - } else { - if (aead->fixed_nonce_len + - aead->variable_nonce_len > sizeof(nonce)) - return -1; /* Should never happen. */ - } - - if (send) { - size_t len = rec->length; - size_t eivlen = 0; - in = rec->input; - out = rec->data; - - if (aead->xor_fixed_nonce) { - /* - * The sequence number is left zero - * padded, then xored with the fixed - * nonce. - */ - memset(nonce, 0, pad_len); - memcpy(nonce + pad_len, ad, - aead->variable_nonce_len); - for (i = 0; i < aead->fixed_nonce_len; i++) - nonce[i] ^= aead->fixed_nonce[i]; - nonce_used = aead->fixed_nonce_len; - } else { - /* - * When sending we use the sequence number as - * the variable part of the nonce. - */ - memcpy(nonce, aead->fixed_nonce, - aead->fixed_nonce_len); - nonce_used = aead->fixed_nonce_len; - memcpy(nonce + nonce_used, ad, - aead->variable_nonce_len); - nonce_used += aead->variable_nonce_len; - } - - /* - * In do_ssl3_write, rec->input is moved forward by - * variable_nonce_len in order to leave space for the - * variable nonce. Thus we can copy the sequence number - * bytes into place without overwriting any of the - * plaintext. - */ - if (aead->variable_nonce_in_record) { - memcpy(out, ad, aead->variable_nonce_len); - len -= aead->variable_nonce_len; - eivlen = aead->variable_nonce_len; - } - - ad[11] = len >> 8; - ad[12] = len & 0xff; - - if (!EVP_AEAD_CTX_seal(&aead->ctx, - out + eivlen, &out_len, len + aead->tag_len, nonce, - nonce_used, in + eivlen, len, ad, sizeof(ad))) - return -1; - if (aead->variable_nonce_in_record) - out_len += aead->variable_nonce_len; - } else { - /* receive */ - size_t len = rec->length; - - if (rec->data != rec->input) - return -1; /* internal error - should never happen. */ - out = in = rec->input; - - if (len < aead->variable_nonce_len) - return 0; - - if (aead->xor_fixed_nonce) { - /* - * The sequence number is left zero - * padded, then xored with the fixed - * nonce. - */ - memset(nonce, 0, pad_len); - memcpy(nonce + pad_len, ad, - aead->variable_nonce_len); - for (i = 0; i < aead->fixed_nonce_len; i++) - nonce[i] ^= aead->fixed_nonce[i]; - nonce_used = aead->fixed_nonce_len; - } else { - memcpy(nonce, aead->fixed_nonce, - aead->fixed_nonce_len); - nonce_used = aead->fixed_nonce_len; - - memcpy(nonce + nonce_used, - aead->variable_nonce_in_record ? in : ad, - aead->variable_nonce_len); - nonce_used += aead->variable_nonce_len; - } - - if (aead->variable_nonce_in_record) { - in += aead->variable_nonce_len; - len -= aead->variable_nonce_len; - out += aead->variable_nonce_len; - } - - if (len < aead->tag_len) - return 0; - len -= aead->tag_len; - - ad[11] = len >> 8; - ad[12] = len & 0xff; - - if (!EVP_AEAD_CTX_open(&aead->ctx, out, &out_len, len, - nonce, nonce_used, in, len + aead->tag_len, ad, - sizeof(ad))) - return -1; - - rec->data = rec->input = out; - } - - rec->length = out_len; - - return 1; - } - - if (send) { - if (EVP_MD_CTX_md(s->internal->write_hash)) { - int n = EVP_MD_CTX_size(s->internal->write_hash); - OPENSSL_assert(n >= 0); - } - ds = s->internal->enc_write_ctx; - if (s->internal->enc_write_ctx == NULL) - enc = NULL; - else { - int ivlen = 0; - enc = EVP_CIPHER_CTX_cipher(s->internal->enc_write_ctx); - if (SSL_USE_EXPLICIT_IV(s) && - EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE) - ivlen = EVP_CIPHER_iv_length(enc); - if (ivlen > 1) { - if (rec->data != rec->input) { -#ifdef DEBUG - /* we can't write into the input stream: - * Can this ever happen?? (steve) - */ - fprintf(stderr, - "%s:%d: rec->data != rec->input\n", - __FILE__, __LINE__); -#endif - } else - arc4random_buf(rec->input, ivlen); - } - } - } else { - if (EVP_MD_CTX_md(s->read_hash)) { - int n = EVP_MD_CTX_size(s->read_hash); - OPENSSL_assert(n >= 0); - } - ds = s->enc_read_ctx; - if (s->enc_read_ctx == NULL) - enc = NULL; - else - enc = EVP_CIPHER_CTX_cipher(s->enc_read_ctx); - } - - if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) { - memmove(rec->data, rec->input, rec->length); - rec->input = rec->data; - ret = 1; - } else { - l = rec->length; - bs = EVP_CIPHER_block_size(ds->cipher); - - if (bs != 1 && send) { - i = bs - ((int)l % bs); - - /* Add weird padding of upto 256 bytes */ - - /* we need to add 'i' padding bytes of value j */ - j = i - 1; - for (k = (int)l; k < (int)(l + i); k++) - rec->input[k] = j; - l += i; - rec->length += i; - } - - if (!send) { - if (l == 0 || l % bs != 0) - return 0; - } - - i = EVP_Cipher(ds, rec->data, rec->input, l); - if ((EVP_CIPHER_flags(ds->cipher) & - EVP_CIPH_FLAG_CUSTOM_CIPHER) ? (i < 0) : (i == 0)) - return -1; /* AEAD can fail to verify MAC */ - - ret = 1; - if (EVP_MD_CTX_md(s->read_hash) != NULL) - mac_size = EVP_MD_CTX_size(s->read_hash); - if ((bs != 1) && !send) - ret = tls1_cbc_remove_padding(s, rec, bs, mac_size); - } - return ret; -} - int tls1_final_finish_mac(SSL *s, const char *str, int str_len, unsigned char *out) { @@ -947,85 +697,6 @@ tls1_final_finish_mac(SSL *s, const char *str, int str_len, unsigned char *out) } int -tls1_mac(SSL *ssl, unsigned char *md, int send) -{ - SSL3_RECORD_INTERNAL *rec; - unsigned char *seq; - EVP_MD_CTX *hash; - size_t md_size, orig_len; - EVP_MD_CTX hmac, *mac_ctx; - unsigned char header[13]; - int stream_mac = (send ? - (ssl->internal->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM) : - (ssl->internal->mac_flags & SSL_MAC_FLAG_READ_MAC_STREAM)); - int t; - - if (send) { - /* No longer supported. */ - return -1; - } else { - rec = &(ssl->s3->internal->rrec); - seq = &(ssl->s3->internal->read_sequence[0]); - hash = ssl->read_hash; - } - - t = EVP_MD_CTX_size(hash); - OPENSSL_assert(t >= 0); - md_size = t; - - /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */ - if (stream_mac) { - mac_ctx = hash; - } else { - if (!EVP_MD_CTX_copy(&hmac, hash)) - return -1; - mac_ctx = &hmac; - } - - if (SSL_IS_DTLS(ssl)) - dtls1_build_sequence_number(header, seq, - send ? D1I(ssl)->w_epoch : D1I(ssl)->r_epoch); - else - memcpy(header, seq, SSL3_SEQUENCE_SIZE); - - orig_len = rec->length + md_size + rec->padding_length; - - header[8] = rec->type; - header[9] = (unsigned char)(ssl->version >> 8); - header[10] = (unsigned char)(ssl->version); - header[11] = (rec->length) >> 8; - header[12] = (rec->length) & 0xff; - - if (!send && - EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE && - ssl3_cbc_record_digest_supported(mac_ctx)) { - /* This is a CBC-encrypted record. We must avoid leaking any - * timing-side channel information about how many blocks of - * data we are hashing because that gives an attacker a - * timing-oracle. */ - if (!ssl3_cbc_digest_record(mac_ctx, - md, &md_size, header, rec->input, - rec->length + md_size, orig_len, - ssl->s3->internal->read_mac_secret, - ssl->s3->internal->read_mac_secret_size)) - return -1; - } else { - EVP_DigestSignUpdate(mac_ctx, header, sizeof(header)); - EVP_DigestSignUpdate(mac_ctx, rec->input, rec->length); - t = EVP_DigestSignFinal(mac_ctx, md, &md_size); - OPENSSL_assert(t > 0); - } - - if (!stream_mac) - EVP_MD_CTX_cleanup(&hmac); - - if (!SSL_IS_DTLS(ssl)) - tls1_record_sequence_increment(seq); - - return (md_size); -} - -int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, int len) { |