aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/authencesn.c
diff options
context:
space:
mode:
authorJames Yonan <james@openvpn.net>2013-09-26 04:20:39 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2013-10-07 02:17:06 -0400
commit6bf37e5aa90f18baf5acf4874bca505dd667c37f (patch)
tree7972d4009f662cf78abdbea3b4040316d46503c1 /crypto/authencesn.c
parentd319fe2a0af3509f959d5195fb8916accbf14857 (diff)
crypto: crypto_memneq - add equality testing of memory regions w/o timing leaks
When comparing MAC hashes, AEAD authentication tags, or other hash values in the context of authentication or integrity checking, it is important not to leak timing information to a potential attacker, i.e. when communication happens over a network. Bytewise memory comparisons (such as memcmp) are usually optimized so that they return a nonzero value as soon as a mismatch is found. E.g, on x86_64/i5 for 512 bytes this can be ~50 cyc for a full mismatch and up to ~850 cyc for a full match (cold). This early-return behavior can leak timing information as a side channel, allowing an attacker to iteratively guess the correct result. This patch adds a new method crypto_memneq ("memory not equal to each other") to the crypto API that compares memory areas of the same length in roughly "constant time" (cache misses could change the timing, but since they don't reveal information about the content of the strings being compared, they are effectively benign). Iow, best and worst case behaviour take the same amount of time to complete (in contrast to memcmp). Note that crypto_memneq (unlike memcmp) can only be used to test for equality or inequality, NOT for lexicographical order. This, however, is not an issue for its use-cases within the crypto API. We tried to locate all of the places in the crypto API where memcmp was being used for authentication or integrity checking, and convert them over to crypto_memneq. crypto_memneq is declared noinline, placed in its own source file, and compiled with optimizations that might increase code size disabled ("Os") because a smart compiler (or LTO) might notice that the return value is always compared against zero/nonzero, and might then reintroduce the same early-return optimization that we are trying to avoid. Using #pragma or __attribute__ optimization annotations of the code for disabling optimization was avoided as it seems to be considered broken or unmaintained for long time in GCC [1]. Therefore, we work around that by specifying the compile flag for memneq.o directly in the Makefile. We found that this seems to be most appropriate. As we use ("Os"), this patch also provides a loop-free "fast-path" for frequently used 16 byte digests. Similarly to kernel library string functions, leave an option for future even further optimized architecture specific assembler implementations. This was a joint work of James Yonan and Daniel Borkmann. Also thanks for feedback from Florian Weimer on this and earlier proposals [2]. [1] http://gcc.gnu.org/ml/gcc/2012-07/msg00211.html [2] https://lkml.org/lkml/2013/2/10/131 Signed-off-by: James Yonan <james@openvpn.net> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Cc: Florian Weimer <fw@deneb.enyo.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/authencesn.c')
-rw-r--r--crypto/authencesn.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index ab53762fc309..c569d58de661 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -247,7 +247,7 @@ static void authenc_esn_verify_ahash_update_done(struct crypto_async_request *ar
247 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, 247 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
248 authsize, 0); 248 authsize, 0);
249 249
250 err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; 250 err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
251 if (err) 251 if (err)
252 goto out; 252 goto out;
253 253
@@ -296,7 +296,7 @@ static void authenc_esn_verify_ahash_update_done2(struct crypto_async_request *a
296 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, 296 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
297 authsize, 0); 297 authsize, 0);
298 298
299 err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; 299 err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
300 if (err) 300 if (err)
301 goto out; 301 goto out;
302 302
@@ -336,7 +336,7 @@ static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
336 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, 336 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
337 authsize, 0); 337 authsize, 0);
338 338
339 err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; 339 err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
340 if (err) 340 if (err)
341 goto out; 341 goto out;
342 342
@@ -568,7 +568,7 @@ static int crypto_authenc_esn_verify(struct aead_request *req)
568 ihash = ohash + authsize; 568 ihash = ohash + authsize;
569 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, 569 scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
570 authsize, 0); 570 authsize, 0);
571 return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0; 571 return crypto_memneq(ihash, ohash, authsize) ? -EBADMSG : 0;
572} 572}
573 573
574static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv, 574static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,