This repository contains tests which ensure that key s2n functions are not susceptible to timing attacks and are indeed constant time.
For more details, see #463
Crypographic protocols such as TLS are supposed to keep secret information secret. They do this by ensuring that WHICH bytes go over the wire is hidden using encryption. However, if the code is not carefully written, WHEN bytes go over the wire may depend on values that were supposed to remain secret.
For example, if code checks a password as follows
for (i = 0; i < length; ++i) {
if password[i] != input[i] {
send("bad password");
}
}
then the amount of time until the reply message is received will depend on which byte in the password is incorrect. An attacker can simply guess
- a*******
- b*******
- c*******
until the time to receive the error message changes, and then they know the first letter in the password. Repeating for the remaining characters turns an exponential guessing challenge into a linear one.
There are two major ways that timing side channels appear in code
In this case, the program may execute more code, and hence take more time, in one branch than another. The password example above is a branch based timing side-channel.
In this case, if one memory location is in cache, while another is not, there will be a detectable delay fetching the location from main memory. For example, an AES computation that uses software lookup tables can leak the secret key over the network based on cache timing https://cr.yp.to/antiforgery/cachetiming-20050414.pdf
The runtime of code should not depend on the value of secret data, and therefore, cryptographic code should ensure that
- No branch depends on secret data
- No memory access depends on secret data
Currently, we have constant-time proofs of two functions from utils/s2n_safety.c
- s2n_constant_time_equals
- s2n_constant_time_copy_or_dont
A proof proceeds in the following steps:
- Annotate public inputs using S2N_PUBLIC_INPUT(). All other inputs are assumed to be private
- Use the ct-verif tool, which compiles the program into the Boogie intermediate representation, and adds assertions that:
- No branch depends on secret data
- No memory access depends on secret data
- Use the Boogie program-analysis framework to convert the code under test into an SMT formula
- Use the z3 prover to prove that either:
- None of the assertions can be violated (in which case the code is constant time) OR
- Some of the assertions can be violated, in which case the code is not guaranteed to be constant time.
Running these tests will require the following dependencies (tested on Ubuntu 14.04). To see how to install this on a clean ubuntu machine, take a look at the ci scripts in this repo.
- ct-verif (available from https://github.com/imdea-software/verifying-constant-time/)
- Export its base directory as $CTVERIF_DIR
- SMACK and all its dependencies
- The easiest way to get these is to use the build.sh in smack/bin
- Ensure that all of the installed dependencies are on the $PATH
- source the smack.environment that the smack build script creates
cp ../../utils/s2n_safety.c .
make clean
EXPECTED_PASS=2
EXPECTED_FAIL=0
make 2>&1 | ./count_success.pl $EXPECTED_PASS $EXPECTED_FAIL
If both tests pass, you will see
verified: 2 errors: 0 as expected
If not all tests pass, you will see a message like:
ERROR: Expected verified: 2 errors: 0.
Got verified: 1 errors: 1.
contact dsn@amazon.com