summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2013-01-29 14:44:36 +0000
committerDr. Stephen Henson <steve@openssl.org>2013-01-31 12:34:10 +0000
commitb908e88ec15aa0a74805e3f2236fc4f83f2789c2 (patch)
tree424b1a8703f65502460f311a42d3da7521a4085b /ssl
parent014265eb02e26f35c8db58e2ccbf100b0b2f0072 (diff)
Timing fix mitigation for FIPS mode.
We have to use EVP in FIPS mode so we can only partially mitigate timing differences. Make an extra call to EVP_DigestSignUpdate to hash additonal blocks to cover any timing differences caused by removal of padding.
Diffstat (limited to 'ssl')
-rw-r--r--ssl/s3_cbc.c51
-rw-r--r--ssl/ssl_locl.h4
-rw-r--r--ssl/t1_enc.c7
3 files changed, 62 insertions, 0 deletions
diff --git a/ssl/s3_cbc.c b/ssl/s3_cbc.c
index e9b112c1b5..c3305eac06 100644
--- a/ssl/s3_cbc.c
+++ b/ssl/s3_cbc.c
@@ -368,6 +368,10 @@ static void tls1_sha512_final_raw(void* ctx, unsigned char *md_out)
* which ssl3_cbc_digest_record supports. */
char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx)
{
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode())
+ return 0;
+#endif
switch (ctx->digest->type)
{
case NID_md5:
@@ -694,3 +698,50 @@ void ssl3_cbc_digest_record(
*md_out_size = md_out_size_u;
EVP_MD_CTX_cleanup(&md_ctx);
}
+
+#ifndef OPENSSL_FIPS
+
+/* Due to the need to use EVP in FIPS mode we can't reimplement digests but
+ * we can ensure the number of blocks processed is equal for all cases
+ * by digesting additional data.
+ */
+
+void tls_fips_digest_extra(
+ const EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *mac_ctx,
+ const unsigned char *data, size_t data_len, size_t orig_len)
+ {
+ size_t block_size, digest_pad, blocks_data, blocks_orig;
+ if (EVP_CIPHER_CTX_mode(cipher_ctx) != EVP_CIPH_CBC_MODE)
+ return;
+ block_size = EVP_MD_CTX_block_size(mac_ctx);
+ /* We are in FIPS mode if we get this far so we know we have only SHA*
+ * digests and TLS to deal with.
+ * Minimum digest padding length is 17 for SHA384/SHA512 and 9
+ * otherwise.
+ * Additional header is 13 bytes. To get the number of digest blocks
+ * processed round up the amount of data plus padding to the nearest
+ * block length. Block length is 128 for SHA384/SHA512 and 64 otherwise.
+ * So we have:
+ * blocks = (payload_len + digest_pad + 13 + block_size - 1)/block_size
+ * equivalently:
+ * blocks = (payload_len + digest_pad + 12)/block_size + 1
+ * HMAC adds a constant overhead.
+ * We're ultimately only interested in differences so this becomes
+ * blocks = (payload_len + 29)/128
+ * for SHA384/SHA512 and
+ * blocks = (payload_len + 21)/64
+ * otherwise.
+ */
+ digest_pad = block_size == 64 ? 21 : 29;
+ blocks_orig = (orig_len + digest_pad)/block_size;
+ blocks_data = (data_len + digest_pad)/block_size;
+ /* MAC enough blocks to make up the difference between the original
+ * and actual lengths plus one extra block to ensure this is never a
+ * no op. The "data" pointer should always have enough space to
+ * perform this operation as it is large enough for a maximum
+ * length TLS buffer.
+ */
+ EVP_DigestSignUpdate(mac_ctx, data,
+ (blocks_orig - blocks_data + 1) * block_size);
+ }
+#endif
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index dd8388cace..e9430cd3db 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1167,4 +1167,8 @@ void ssl3_cbc_digest_record(
unsigned mac_secret_length,
char is_sslv3);
+void tls_fips_digest_extra(
+ const EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *mac_ctx,
+ const unsigned char *data, size_t data_len, size_t orig_len);
+
#endif
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index bb46f7f9ba..6fbe2c33aa 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -1025,6 +1025,13 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send)
EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length);
t=EVP_DigestSignFinal(mac_ctx,md,&md_size);
OPENSSL_assert(t > 0);
+#ifdef OPENSSL_FIPS
+ if (!send && FIPS_mode())
+ tls_fips_digest_extra(
+ ssl->enc_read_ctx,
+ mac_ctx, rec->input,
+ rec->length, rec->orig_len);
+#endif
}
if (!stream_mac)