diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index fe126ccd7a..9ad81337c3 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -42,27 +42,30 @@ extern "C" { #define OSSL_ALG_PARAM_PROPERTIES "properties"/* utf8_string */ /* cipher parameters */ -#define OSSL_CIPHER_PARAM_PADDING "padding" /* uint */ -#define OSSL_CIPHER_PARAM_MODE "mode" /* uint */ -#define OSSL_CIPHER_PARAM_BLOCK_SIZE "blocksize" /* size_t */ -#define OSSL_CIPHER_PARAM_FLAGS "flags" /* ulong */ -#define OSSL_CIPHER_PARAM_KEYLEN "keylen" /* size_t */ -#define OSSL_CIPHER_PARAM_IVLEN "ivlen" /* size_t */ -#define OSSL_CIPHER_PARAM_IV "iv" /* octet_string OR octet_ptr */ -#define OSSL_CIPHER_PARAM_NUM "num" /* uint */ -#define OSSL_CIPHER_PARAM_ROUNDS "rounds" /* uint */ -#define OSSL_CIPHER_PARAM_AEAD_TAG "tag" /* octet_string */ -#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD "tlsaad" /* octet_string */ -#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD "tlsaadpad" /* size_t */ -#define OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED "tlsivfixed" /* octet_string */ -#define OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN "tlsivgen" /* octet_string */ -#define OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV "tlsivinv" /* octet_string */ +#define OSSL_CIPHER_PARAM_PADDING "padding" /* uint */ +#define OSSL_CIPHER_PARAM_TLS_VERSION "tls-version" /* uint */ +#define OSSL_CIPHER_PARAM_TLS_MAC "tls-mac" /* octet_ptr */ +#define OSSL_CIPHER_PARAM_TLS_MAC_SIZE "tls-mac-size" /* size_t */ +#define OSSL_CIPHER_PARAM_MODE "mode" /* uint */ +#define OSSL_CIPHER_PARAM_BLOCK_SIZE "blocksize" /* size_t */ +#define OSSL_CIPHER_PARAM_FLAGS "flags" /* ulong */ +#define OSSL_CIPHER_PARAM_KEYLEN "keylen" /* size_t */ +#define OSSL_CIPHER_PARAM_IVLEN "ivlen" /* size_t */ +#define OSSL_CIPHER_PARAM_IV "iv" /* octet_string OR octet_ptr */ +#define OSSL_CIPHER_PARAM_NUM "num" /* uint */ +#define OSSL_CIPHER_PARAM_ROUNDS "rounds" /* uint */ +#define OSSL_CIPHER_PARAM_AEAD_TAG "tag" /* octet_string */ +#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD "tlsaad" /* octet_string */ +#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD "tlsaadpad" /* size_t */ +#define OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED "tlsivfixed" /* octet_string */ +#define OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN "tlsivgen" /* octet_string */ +#define OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV "tlsivinv" /* octet_string */ #define OSSL_CIPHER_PARAM_AEAD_IVLEN OSSL_CIPHER_PARAM_IVLEN -#define OSSL_CIPHER_PARAM_AEAD_TAGLEN "taglen" /* size_t */ -#define OSSL_CIPHER_PARAM_AEAD_MAC_KEY "mackey" /* octet_string */ -#define OSSL_CIPHER_PARAM_RANDOM_KEY "randkey" /* octet_string */ -#define OSSL_CIPHER_PARAM_RC2_KEYBITS "keybits" /* size_t */ -#define OSSL_CIPHER_PARAM_SPEED "speed" /* uint */ +#define OSSL_CIPHER_PARAM_AEAD_TAGLEN "taglen" /* size_t */ +#define OSSL_CIPHER_PARAM_AEAD_MAC_KEY "mackey" /* octet_string */ +#define OSSL_CIPHER_PARAM_RANDOM_KEY "randkey" /* octet_string */ +#define OSSL_CIPHER_PARAM_RC2_KEYBITS "keybits" /* size_t */ +#define OSSL_CIPHER_PARAM_SPEED "speed" /* uint */ /* For passing the AlgorithmIdentifier parameter in DER form */ #define OSSL_CIPHER_PARAM_ALG_ID "alg_id_param" /* octet_string */ diff --git a/providers/implementations/ciphers/ciphercommon.c b/providers/implementations/ciphers/ciphercommon.c index 93bee0dc0f..0b0219c7ad 100644 --- a/providers/implementations/ciphers/ciphercommon.c +++ b/providers/implementations/ciphers/ciphercommon.c @@ -24,6 +24,7 @@ static const OSSL_PARAM cipher_known_gettable_params[] = { OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, NULL), OSSL_PARAM_ulong(OSSL_CIPHER_PARAM_FLAGS, NULL), + { OSSL_CIPHER_PARAM_TLS_MAC, OSSL_PARAM_OCTET_PTR, NULL, 0, OSSL_PARAM_UNMODIFIED }, OSSL_PARAM_END }; const OSSL_PARAM *cipher_generic_gettable_params(void) @@ -69,6 +70,8 @@ CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(cipher_generic) CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(cipher_generic) CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(cipher_generic) +OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS_VERSION, NULL), +OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS_MAC_SIZE, NULL), CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(cipher_generic) /* @@ -178,6 +181,41 @@ int cipher_generic_block_update(void *vctx, unsigned char *out, size_t *outl, size_t blksz = ctx->blocksize; size_t nextblocks; + if (ctx->tlsversion > 0) { + /* + * Each update call corresponds to a TLS record and is individually + * padded + */ + + /* Sanity check inputs */ + if (in == 0 + || (inl % blksz) != 0 + || in != out + || outsize < inl + || !ctx->pad) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + /* Shouldn't normally fail */ + if (!ctx->hw->cipher(ctx, out, in, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + /* This only fails if padding is publicly invalid */ + /* TODO(3.0): FIX ME FIX ME - Figure out aead */ + *outl = inl; + if (!ctx->enc + && !tlsunpadblock(ctx->libctx, ctx->tlsversion, out, outl, + blksz, &ctx->tlsmac, &ctx->alloced, + ctx->tlsmacsize, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + return 1; + } + if (ctx->bufsz != 0) nextblocks = fillblock(ctx->buf, &ctx->bufsz, blksz, &in, &inl); else @@ -238,6 +276,12 @@ int cipher_generic_block_final(void *vctx, unsigned char *out, size_t *outl, PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; size_t blksz = ctx->blocksize; + if (ctx->tlsversion > 0) { + /* We never finalize TLS, so this is an error */ + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + if (ctx->enc) { if (ctx->pad) { padblock(ctx->buf, &ctx->bufsz, blksz); @@ -375,6 +419,12 @@ int cipher_generic_get_ctx_params(void *vctx, OSSL_PARAM params[]) ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); return 0; } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS_MAC); + if (p != NULL + && !OSSL_PARAM_set_octet_ptr(p, ctx->tlsmac, ctx->tlsmacsize)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } return 1; } @@ -393,6 +443,20 @@ int cipher_generic_set_ctx_params(void *vctx, const OSSL_PARAM params[]) } ctx->pad = pad ? 1 : 0; } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_VERSION); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &ctx->tlsversion)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_MAC_SIZE); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &ctx->tlsmacsize)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_NUM); if (p != NULL) { unsigned int num; diff --git a/providers/implementations/ciphers/ciphercommon_block.c b/providers/implementations/ciphers/ciphercommon_block.c index ac792d68d7..ba6f68eeff 100644 --- a/providers/implementations/ciphers/ciphercommon_block.c +++ b/providers/implementations/ciphers/ciphercommon_block.c @@ -8,9 +8,31 @@ */ #include +/* For SSL3_VERSION, TLS1_VERSION etc */ +#include +#include +#include "internal/constant_time.h" #include "ciphercommon_local.h" #include "prov/providercommonerr.h" +/* Functions defined in ssl/tls_pad.c */ +int ssl3_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, + unsigned char **mac, + int *alloced, + size_t block_size, size_t mac_size, + OPENSSL_CTX *libctx); + +int tls1_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, + unsigned char **mac, + int *alloced, + size_t block_size, size_t mac_size, + int aead, + OPENSSL_CTX *libctx); + /* * Fills a single block of buffered data from the input, and returns the amount * of data remaining in the input that is a multiple of the blocksize. The buffer @@ -110,3 +132,56 @@ int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize) *buflen = len; return 1; } + +/*- + * tlsunpadblock removes the CBC padding from the decrypted, TLS, CBC + * record in constant time. Also removes the MAC from the record in constant + * time. + * + * libctx: Our library context + * tlsversion: The TLS version in use, e.g. SSL3_VERSION, TLS1_VERSION, etc + * buf: The decrypted TLS record data + * buflen: The length of the decrypted TLS record data. Updated with the new + * length after the padding is removed + * block_size: the block size of the cipher used to encrypt the record. + * mac: Location to store the pointer to the MAC + * alloced: Whether the MAC is stored in a newly allocated buffer, or whether + * *mac points into *buf + * macsize: the size of the MAC inside the record (or 0 if there isn't one) + * aead: whether this is an aead cipher + * returns: + * 0: (in non-constant time) if the record is publicly invalid. + * 1: (in constant time) Record is publicly valid. If padding is invalid then + * the mac is random + */ +int tlsunpadblock(OPENSSL_CTX *libctx, unsigned int tlsversion, + unsigned char *buf, size_t *buflen, size_t blocksize, + unsigned char **mac, int *alloced, size_t macsize, int aead) +{ + int ret; + + switch (tlsversion) { + case SSL3_VERSION: + return ssl3_cbc_remove_padding_and_mac(buflen, *buflen, buf, mac, + alloced, blocksize, macsize, + libctx); + + case TLS1_2_VERSION: + case DTLS1_2_VERSION: + case TLS1_1_VERSION: + case DTLS1_VERSION: + case DTLS1_BAD_VER: + /* Remove the explicit IV */ + buf += blocksize; + *buflen -= blocksize; + /* Fall through */ + case TLS1_VERSION: + ret = tls1_cbc_remove_padding_and_mac(buflen, *buflen, buf, mac, + alloced, blocksize, macsize, + aead, libctx); + return ret; + + default: + return 0; + } +} diff --git a/providers/implementations/ciphers/ciphercommon_local.h b/providers/implementations/ciphers/ciphercommon_local.h index 1c4716f357..43c1c192af 100644 --- a/providers/implementations/ciphers/ciphercommon_local.h +++ b/providers/implementations/ciphers/ciphercommon_local.h @@ -11,3 +11,6 @@ void padblock(unsigned char *buf, size_t *buflen, size_t blocksize); int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize); +int tlsunpadblock(OPENSSL_CTX *libctx, unsigned int tlsversion, + unsigned char *buf, size_t *buflen, size_t blocksize, + unsigned char **mac, int *alloced, size_t macsize, int aead); diff --git a/providers/implementations/include/prov/ciphercommon.h b/providers/implementations/include/prov/ciphercommon.h index fa6eec6a27..18bb579026 100644 --- a/providers/implementations/include/prov/ciphercommon.h +++ b/providers/implementations/include/prov/ciphercommon.h @@ -31,6 +31,9 @@ typedef struct prov_cipher_ctx_st PROV_CIPHER_CTX; typedef int (PROV_CIPHER_HW_FN)(PROV_CIPHER_CTX *dat, unsigned char *out, const unsigned char *in, size_t len); +/* TODO(3.0): VERIFY ME */ +#define MAX_TLS_MAC_SIZE 48 + struct prov_cipher_ctx_st { block128_f block; union { @@ -48,6 +51,14 @@ struct prov_cipher_ctx_st { unsigned int enc : 1; /* Set to 1 for encrypt, or 0 otherwise */ unsigned int iv_set : 1; /* Set when the iv is copied to the iv/oiv buffers */ + unsigned int tlsversion; /* If TLS padding is in use the TLS version number */ + unsigned char *tlsmac; /* tls MAC extracted from the last record */ + int alloced; /* + * Whether the tlsmac data has been allocated or + * points into the user buffer. + */ + size_t tlsmacsize; /* Size of the TLS MAC */ + /* * num contains the number of bytes of |iv| which are valid for modes that * manage partial blocks themselves. diff --git a/ssl/build.info b/ssl/build.info index a66e0d4bdb..fd187ac7e5 100644 --- a/ssl/build.info +++ b/ssl/build.info @@ -29,3 +29,5 @@ SOURCE[../libssl]=\ record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \ statem/statem.c record/ssl3_record_tls13.c record/tls_pad.c DEFINE[../libssl]=$AESDEF + +SOURCE[../providers/libcommon.a]=record/tls_pad.c