diff options
Diffstat (limited to 'crypto/openssl/ssl/record/methods/ssl3_meth.c')
| -rw-r--r-- | crypto/openssl/ssl/record/methods/ssl3_meth.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/crypto/openssl/ssl/record/methods/ssl3_meth.c b/crypto/openssl/ssl/record/methods/ssl3_meth.c new file mode 100644 index 000000000000..6b5a1bed23eb --- /dev/null +++ b/crypto/openssl/ssl/record/methods/ssl3_meth.c @@ -0,0 +1,334 @@ +/* + * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/evp.h> +#include <openssl/core_names.h> +#include "internal/ssl3_cbc.h" +#include "../../ssl_local.h" +#include "../record_local.h" +#include "recmethod_local.h" + +static int ssl3_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, + unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen, + unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *ciph, + size_t taglen, + int mactype, + const EVP_MD *md, + COMP_METHOD *comp) +{ + EVP_CIPHER_CTX *ciph_ctx; + int enc = (rl->direction == OSSL_RECORD_DIRECTION_WRITE) ? 1 : 0; + + if (md == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + + if ((rl->enc_ctx = EVP_CIPHER_CTX_new()) == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + ciph_ctx = rl->enc_ctx; + + rl->md_ctx = EVP_MD_CTX_new(); + if (rl->md_ctx == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + + if ((md != NULL && EVP_DigestInit_ex(rl->md_ctx, md, NULL) <= 0)) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + +#ifndef OPENSSL_NO_COMP + if (comp != NULL) { + rl->compctx = COMP_CTX_new(comp); + if (rl->compctx == NULL) { + ERR_raise(ERR_LIB_SSL, SSL_R_COMPRESSION_LIBRARY_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + } +#endif + + if (!EVP_CipherInit_ex(ciph_ctx, ciph, NULL, key, iv, enc)) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + + /* + * The cipher we actually ended up using in the EVP_CIPHER_CTX may be + * different to that in ciph if we have an ENGINE in use + */ + if (EVP_CIPHER_get0_provider(EVP_CIPHER_CTX_get0_cipher(ciph_ctx)) != NULL + && !ossl_set_tls_provider_parameters(rl, ciph_ctx, ciph, md)) { + /* ERR_raise already called */ + return OSSL_RECORD_RETURN_FATAL; + } + + if (mackeylen > sizeof(rl->mac_secret)) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + memcpy(rl->mac_secret, mackey, mackeylen); + + return OSSL_RECORD_RETURN_SUCCESS; +} + +/* + * ssl3_cipher encrypts/decrypts |n_recs| records in |inrecs|. Calls RLAYERfatal + * on internal error, but not otherwise. It is the responsibility of the caller + * to report a bad_record_mac + * + * Returns: + * 0: if the record is publicly invalid, or an internal error + * 1: Success or Mac-then-encrypt decryption failed (MAC will be randomised) + */ +static int ssl3_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *inrecs, + size_t n_recs, int sending, SSL_MAC_BUF *mac, + size_t macsize) +{ + TLS_RL_RECORD *rec; + EVP_CIPHER_CTX *ds; + size_t l, i; + size_t bs; + const EVP_CIPHER *enc; + int provided; + + rec = inrecs; + /* + * We shouldn't ever be called with more than one record in the SSLv3 case + */ + if (n_recs != 1) + return 0; + + ds = rl->enc_ctx; + if (ds == NULL || (enc = EVP_CIPHER_CTX_get0_cipher(ds)) == NULL) + return 0; + + provided = (EVP_CIPHER_get0_provider(enc) != NULL); + + l = rec->length; + bs = EVP_CIPHER_CTX_get_block_size(ds); + + if (bs == 0) + return 0; + + /* COMPRESS */ + + if ((bs != 1) && sending && !provided) { + /* + * We only do this for legacy ciphers. Provided ciphers add the + * padding on the provider side. + */ + i = bs - (l % bs); + + /* we need to add 'i-1' padding bytes */ + l += i; + /* + * the last of these zero bytes will be overwritten with the + * padding length. + */ + memset(&rec->input[rec->length], 0, i); + rec->length += i; + rec->input[l - 1] = (unsigned char)(i - 1); + } + + if (!sending) { + if (l == 0 || l % bs != 0) { + /* Publicly invalid */ + return 0; + } + /* otherwise, rec->length >= bs */ + } + + if (provided) { + int outlen; + + if (!EVP_CipherUpdate(ds, rec->data, &outlen, rec->input, + (unsigned int)l)) + return 0; + rec->length = outlen; + + if (!sending && mac != NULL) { + /* Now get a pointer to the MAC */ + OSSL_PARAM params[2], *p = params; + + /* Get the MAC */ + mac->alloced = 0; + + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_CIPHER_PARAM_TLS_MAC, + (void **)&mac->mac, + macsize); + *p = OSSL_PARAM_construct_end(); + + if (!EVP_CIPHER_CTX_get_params(ds, params)) { + /* Shouldn't normally happen */ + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + } + } else { + if (EVP_Cipher(ds, rec->data, rec->input, (unsigned int)l) < 1) { + /* Shouldn't happen */ + RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!sending) + return ssl3_cbc_remove_padding_and_mac(&rec->length, + rec->orig_len, + rec->data, + (mac != NULL) ? &mac->mac : NULL, + (mac != NULL) ? &mac->alloced : NULL, + bs, + macsize, + rl->libctx); + } + + return 1; +} + +static const unsigned char ssl3_pad_1[48] = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 +}; + +static const unsigned char ssl3_pad_2[48] = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c +}; + +static int ssl3_mac(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *rec, unsigned char *md, + int sending) +{ + unsigned char *mac_sec, *seq = rl->sequence; + const EVP_MD_CTX *hash; + unsigned char *p, rec_char; + size_t md_size; + size_t npad; + int t; + + mac_sec = &(rl->mac_secret[0]); + hash = rl->md_ctx; + + t = EVP_MD_CTX_get_size(hash); + if (t <= 0) + return 0; + md_size = t; + npad = (48 / md_size) * md_size; + + if (!sending + && EVP_CIPHER_CTX_get_mode(rl->enc_ctx) == EVP_CIPH_CBC_MODE + && ssl3_cbc_record_digest_supported(hash)) { +#ifdef OPENSSL_NO_DEPRECATED_3_0 + return 0; +#else + /* + * 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. + */ + + /*- + * npad is, at most, 48 bytes and that's with MD5: + * 16 + 48 + 8 (sequence bytes) + 1 + 2 = 75. + * + * With SHA-1 (the largest hash speced for SSLv3) the hash size + * goes up 4, but npad goes down by 8, resulting in a smaller + * total size. + */ + unsigned char header[75]; + size_t j = 0; + memcpy(header + j, mac_sec, md_size); + j += md_size; + memcpy(header + j, ssl3_pad_1, npad); + j += npad; + memcpy(header + j, seq, 8); + j += 8; + header[j++] = rec->type; + header[j++] = (unsigned char)(rec->length >> 8); + header[j++] = (unsigned char)(rec->length & 0xff); + + /* Final param == is SSLv3 */ + if (ssl3_cbc_digest_record(EVP_MD_CTX_get0_md(hash), + md, &md_size, + header, rec->input, + rec->length, rec->orig_len, + mac_sec, md_size, 1) <= 0) + return 0; +#endif + } else { + unsigned int md_size_u; + /* Chop the digest off the end :-) */ + EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); + + if (md_ctx == NULL) + return 0; + + rec_char = rec->type; + p = md; + s2n(rec->length, p); + if (EVP_MD_CTX_copy_ex(md_ctx, hash) <= 0 + || EVP_DigestUpdate(md_ctx, mac_sec, md_size) <= 0 + || EVP_DigestUpdate(md_ctx, ssl3_pad_1, npad) <= 0 + || EVP_DigestUpdate(md_ctx, seq, 8) <= 0 + || EVP_DigestUpdate(md_ctx, &rec_char, 1) <= 0 + || EVP_DigestUpdate(md_ctx, md, 2) <= 0 + || EVP_DigestUpdate(md_ctx, rec->input, rec->length) <= 0 + || EVP_DigestFinal_ex(md_ctx, md, NULL) <= 0 + || EVP_MD_CTX_copy_ex(md_ctx, hash) <= 0 + || EVP_DigestUpdate(md_ctx, mac_sec, md_size) <= 0 + || EVP_DigestUpdate(md_ctx, ssl3_pad_2, npad) <= 0 + || EVP_DigestUpdate(md_ctx, md, md_size) <= 0 + || EVP_DigestFinal_ex(md_ctx, md, &md_size_u) <= 0) { + EVP_MD_CTX_free(md_ctx); + return 0; + } + + EVP_MD_CTX_free(md_ctx); + } + + if (!tls_increment_sequence_ctr(rl)) + return 0; + + return 1; +} + +const struct record_functions_st ssl_3_0_funcs = { + ssl3_set_crypto_state, + ssl3_cipher, + ssl3_mac, + tls_default_set_protocol_version, + tls_default_read_n, + tls_get_more_records, + tls_default_validate_record_header, + tls_default_post_process_record, + tls_get_max_records_default, + tls_write_records_default, + /* These 2 functions are defined in tls1_meth.c */ + tls1_allocate_write_buffers, + tls1_initialise_write_packets, + NULL, + tls_prepare_record_header_default, + NULL, + tls_prepare_for_encryption_default, + tls_post_encryption_processing_default, + NULL +}; |
