diff options
Diffstat (limited to 'src/crypto/cipher/e_tls.c')
-rw-r--r-- | src/crypto/cipher/e_tls.c | 180 |
1 files changed, 91 insertions, 89 deletions
diff --git a/src/crypto/cipher/e_tls.c b/src/crypto/cipher/e_tls.c index 8ac1aae..bed02cb 100644 --- a/src/crypto/cipher/e_tls.c +++ b/src/crypto/cipher/e_tls.c @@ -22,6 +22,7 @@ #include <openssl/hmac.h> #include <openssl/mem.h> #include <openssl/sha.h> +#include <openssl/type_check.h> #include "../crypto/internal.h" #include "internal.h" @@ -34,37 +35,26 @@ typedef struct { * separately for the constant-time CBC code. */ uint8_t mac_key[EVP_MAX_MD_SIZE]; uint8_t mac_key_len; - /* enc_key is the portion of the key used for the stream or block - * cipher. It is retained separately to allow the EVP_CIPHER_CTX to be - * initialized once the direction is known. */ - uint8_t enc_key[EVP_MAX_KEY_LENGTH]; - uint8_t enc_key_len; - /* iv is the portion of the key used for the fixed IV. It is retained - * separately to allow the EVP_CIPHER_CTX to be initialized once the direction - * is known. */ - uint8_t iv[EVP_MAX_IV_LENGTH]; - uint8_t iv_len; /* implicit_iv is one iff this is a pre-TLS-1.1 CBC cipher without an explicit * IV. */ char implicit_iv; - char initialized; } AEAD_TLS_CTX; +OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE < 256, mac_key_len_fits_in_uint8_t); static void aead_tls_cleanup(EVP_AEAD_CTX *ctx) { AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; EVP_CIPHER_CTX_cleanup(&tls_ctx->cipher_ctx); HMAC_CTX_cleanup(&tls_ctx->hmac_ctx); OPENSSL_cleanse(&tls_ctx->mac_key, sizeof(tls_ctx->mac_key)); - OPENSSL_cleanse(&tls_ctx->enc_key, sizeof(tls_ctx->enc_key)); - OPENSSL_cleanse(&tls_ctx->iv, sizeof(tls_ctx->iv)); OPENSSL_free(tls_ctx); ctx->aead_state = NULL; } static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, - size_t tag_len, const EVP_CIPHER *cipher, - const EVP_MD *md, char implicit_iv) { + size_t tag_len, enum evp_aead_direction_t dir, + const EVP_CIPHER *cipher, const EVP_MD *md, + char implicit_iv) { if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH && tag_len != EVP_MD_size(md)) { OPENSSL_PUT_ERROR(CIPHER, aead_tls_init, CIPHER_R_UNSUPPORTED_TAG_SIZE); @@ -78,11 +68,8 @@ static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t mac_key_len = EVP_MD_size(md); size_t enc_key_len = EVP_CIPHER_key_length(cipher); - size_t iv_len = implicit_iv ? EVP_CIPHER_iv_length(cipher) : 0; - assert(mac_key_len + enc_key_len + iv_len == key_len); - assert(mac_key_len < 256); - assert(enc_key_len < 256); - assert(iv_len < 256); + assert(mac_key_len + enc_key_len + + (implicit_iv ? EVP_CIPHER_iv_length(cipher) : 0) == key_len); /* Although EVP_rc4() is a variable-length cipher, the default key size is * correct for TLS. */ @@ -93,19 +80,18 @@ static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, } EVP_CIPHER_CTX_init(&tls_ctx->cipher_ctx); HMAC_CTX_init(&tls_ctx->hmac_ctx); + assert(mac_key_len <= EVP_MAX_MD_SIZE); memcpy(tls_ctx->mac_key, key, mac_key_len); tls_ctx->mac_key_len = (uint8_t)mac_key_len; - memcpy(tls_ctx->enc_key, &key[mac_key_len], enc_key_len); - tls_ctx->enc_key_len = (uint8_t)enc_key_len; - memcpy(tls_ctx->iv, &key[mac_key_len + enc_key_len], iv_len); - tls_ctx->iv_len = (uint8_t)iv_len; tls_ctx->implicit_iv = implicit_iv; - tls_ctx->initialized = 0; ctx->aead_state = tls_ctx; - if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, cipher, NULL, NULL, NULL, 0) || + if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len], + implicit_iv ? &key[mac_key_len + enc_key_len] : NULL, + dir == evp_aead_seal) || !HMAC_Init_ex(&tls_ctx->hmac_ctx, key, mac_key_len, md, NULL)) { aead_tls_cleanup(ctx); + ctx->aead_state = NULL; return 0; } EVP_CIPHER_CTX_set_padding(&tls_ctx->cipher_ctx, 0); @@ -113,32 +99,6 @@ static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, return 1; } -/* aead_tls_ensure_cipher_init initializes |tls_ctx| for encryption (or - * decryption, if |encrypt| is zero). If it has already been initialized, it - * ensures the direction matches and fails otherwise. It returns one on success - * and zero on failure. - * - * Note that, unlike normal AEADs, legacy TLS AEADs may not be used concurrently - * due to this (and bulk-cipher-internal) statefulness. */ -static int aead_tls_ensure_cipher_init(AEAD_TLS_CTX *tls_ctx, int encrypt) { - if (!tls_ctx->initialized) { - /* Finish initializing the EVP_CIPHER_CTX now that the direction is - * known. */ - if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, tls_ctx->enc_key, - tls_ctx->implicit_iv ? tls_ctx->iv : NULL, - encrypt)) { - return 0; - } - tls_ctx->initialized = 1; - } else if (tls_ctx->cipher_ctx.encrypt != encrypt) { - /* Unlike a normal AEAD, using a TLS AEAD once freezes the direction. */ - OPENSSL_PUT_ERROR(CIPHER, aead_tls_ensure_cipher_init, - CIPHER_R_INVALID_OPERATION); - return 0; - } - return 1; -} - static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t max_out_len, const uint8_t *nonce, size_t nonce_len, @@ -147,6 +107,13 @@ static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; size_t total = 0; + if (!tls_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_OPERATION); + return 0; + + } + if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len || in_len > INT_MAX) { /* EVP_CIPHER takes int as input. */ @@ -169,10 +136,6 @@ static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, return 0; } - if (!aead_tls_ensure_cipher_init(tls_ctx, 1)) { - return 0; - } - /* To allow for CBC mode which changes cipher length, |ad| doesn't include the * length for legacy ciphers. */ uint8_t ad_extra[2]; @@ -249,6 +212,13 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *ad, size_t ad_len) { AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; + if (tls_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_OPERATION); + return 0; + + } + if (in_len < HMAC_size(&tls_ctx->hmac_ctx)) { OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT); return 0; @@ -277,10 +247,6 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, return 0; } - if (!aead_tls_ensure_cipher_init(tls_ctx, 0)) { - return 0; - } - /* Configure the explicit IV. */ if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && !tls_ctx->implicit_iv && @@ -394,83 +360,101 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, } static int aead_rc4_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_rc4(), EVP_sha1(), 0); + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1(), + 0); } static int aead_aes_128_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_128_cbc(), + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), EVP_sha1(), 0); } -static int aead_aes_128_cbc_sha1_tls_implicit_iv_init(EVP_AEAD_CTX *ctx, - const uint8_t *key, - size_t key_len, - size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_128_cbc(), +static int aead_aes_128_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), EVP_sha1(), 1); } static int aead_aes_128_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, - size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_128_cbc(), + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), EVP_sha256(), 0); } static int aead_aes_256_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(), + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), EVP_sha1(), 0); } -static int aead_aes_256_cbc_sha1_tls_implicit_iv_init(EVP_AEAD_CTX *ctx, - const uint8_t *key, - size_t key_len, - size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(), +static int aead_aes_256_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), EVP_sha1(), 1); } static int aead_aes_256_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, - size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(), + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), EVP_sha256(), 0); } static int aead_aes_256_cbc_sha384_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, - size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(), + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), EVP_sha384(), 0); } static int aead_des_ede3_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, - size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_des_ede3_cbc(), + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), EVP_sha1(), 0); } -static int aead_des_ede3_cbc_sha1_tls_implicit_iv_init(EVP_AEAD_CTX *ctx, - const uint8_t *key, - size_t key_len, - size_t tag_len) { - return aead_tls_init(ctx, key, key_len, tag_len, EVP_des_ede3_cbc(), +static int aead_des_ede3_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), EVP_sha1(), 1); } +static int aead_rc4_sha1_tls_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key) { + const AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX*) ctx->aead_state; + if (EVP_CIPHER_CTX_cipher(&tls_ctx->cipher_ctx) != EVP_rc4()) { + return 0; + } + + *out_key = (const RC4_KEY*) tls_ctx->cipher_ctx.cipher_data; + return 1; +} + static const EVP_AEAD aead_rc4_sha1_tls = { SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */ 0, /* nonce len */ SHA_DIGEST_LENGTH, /* overhead */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_rc4_sha1_tls_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + aead_rc4_sha1_tls_get_rc4_state, /* get_rc4_state */ }; static const EVP_AEAD aead_aes_128_cbc_sha1_tls = { @@ -478,10 +462,12 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_tls = { 16, /* nonce len (IV) */ 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_aes_128_cbc_sha1_tls_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = { @@ -489,10 +475,12 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = { 0, /* nonce len */ 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_aes_128_cbc_sha1_tls_implicit_iv_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_aes_128_cbc_sha256_tls = { @@ -500,10 +488,12 @@ static const EVP_AEAD aead_aes_128_cbc_sha256_tls = { 16, /* nonce len (IV) */ 16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_aes_128_cbc_sha256_tls_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_aes_256_cbc_sha1_tls = { @@ -511,10 +501,12 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_tls = { 16, /* nonce len (IV) */ 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_aes_256_cbc_sha1_tls_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = { @@ -522,10 +514,12 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = { 0, /* nonce len */ 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_aes_256_cbc_sha1_tls_implicit_iv_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_aes_256_cbc_sha256_tls = { @@ -533,10 +527,12 @@ static const EVP_AEAD aead_aes_256_cbc_sha256_tls = { 16, /* nonce len (IV) */ 16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_aes_256_cbc_sha256_tls_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_aes_256_cbc_sha384_tls = { @@ -544,10 +540,12 @@ static const EVP_AEAD aead_aes_256_cbc_sha384_tls = { 16, /* nonce len (IV) */ 16 + SHA384_DIGEST_LENGTH, /* overhead (padding + SHA384) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_aes_256_cbc_sha384_tls_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = { @@ -555,10 +553,12 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = { 8, /* nonce len (IV) */ 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_des_ede3_cbc_sha1_tls_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = { @@ -566,10 +566,12 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = { 0, /* nonce len */ 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ aead_des_ede3_cbc_sha1_tls_implicit_iv_init, aead_tls_cleanup, aead_tls_seal, aead_tls_open, + NULL, /* get_rc4_state */ }; const EVP_AEAD *EVP_aead_rc4_sha1_tls(void) { return &aead_rc4_sha1_tls; } |