Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ The security of TLS and its associated encryption algorithms depends upon secure
##### Modularized encryption
s2n has been structured so that different encryption libraries may be used. Today s2n supports OpenSSL, LibreSSL, BoringSSL, and the Apple Common Crypto framework to perform the underlying cryptographic operations.

##### Timing blinding
s2n includes structured support for blinding time-based side-channels that may leak sensitive data. For example, if s2n fails to parse a TLS record or handshake message, s2n will add a randomized delay of between 1ms and 10 seconds, granular to nanoseconds, before responding. This raises the complexity of real-world timing side-channel attacks by a factor of at least tens of trillions.

##### Table based state-machines
s2n uses simple tables to drive the TLS/SSL state machines, making it difficult for invalid out-of-order states to arise.

Expand Down
11 changes: 6 additions & 5 deletions crypto/s2n_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,13 @@ int s2n_hmac_digest_two_compression_rounds(struct s2n_hmac_state *state, void *o
{
GUARD(s2n_hmac_digest(state, out, size));

/* If there were 8 or more bytes of space left in the current hash block
* then the serialized length will have fit in that block. If there were
* fewer than 8 then adding the length will have caused an extra compression
* block round. This digest function always does two compression rounds,
/* If there were 9 or more bytes of space left in the current hash block
* then the serialized length, plus an 0x80 byte, will have fit in that block.
* If there were fewer than 9 then adding the length will have caused an extra
* compression block round. This digest function always does two compression rounds,
* even if there is no need for the second.
*/
if (state->currently_in_hash_block > (state->hash_block_size - 8))
if (state->currently_in_hash_block > (state->hash_block_size - 9))
{
return 0;
}
Expand All @@ -213,6 +213,7 @@ int s2n_hmac_digest_two_compression_rounds(struct s2n_hmac_state *state, void *o

int s2n_hmac_reset(struct s2n_hmac_state *state)
{
state->currently_in_hash_block = 0;
memcpy_check(&state->inner, &state->inner_just_key, sizeof(state->inner));

return 0;
Expand Down
17 changes: 12 additions & 5 deletions tls/s2n_cbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@
*
* The goal of s2n_verify_cbc() is to verify that the padding and hmac
* are correct, without leaking (via timing) how much padding there
* actually is: this is considered secret.
* actually is: as this is considered secret.
*
* In addition to our efforts here though, s2n also wraps any CBC
* verification error (or record parsing error in general) with
* a randomized delay of between 1ms and 10 seconds. See s2n_connection.c.
* This amount of delay randomization is sufficient to increase the
* complexity of attack for even a 1 microsecond timing leak (which
* is quite large) by a factor of around 83 trillion.
*/
int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, struct s2n_blob *decrypted)
{
Expand Down Expand Up @@ -77,14 +84,14 @@ int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, str
return 0 - mismatches;
}

/* Check the padding */
/* Check the maximum amount of padding */
int check = 255;
if (check > payload_and_padding_size) {
check = payload_and_padding_size;
if (check > (payload_and_padding_size - 1)) {
check = (payload_and_padding_size - 1);
}

int cutoff = check - padding_length;
for (int i = 0, j = decrypted->size - check; i < check && j < decrypted->size; i++, j++) {
for (int i = 0, j = decrypted->size - 1 - check; i < check && j < decrypted->size; i++, j++) {
uint8_t mask = ~(0xff << ((i >= cutoff) * 8));
mismatches |= (decrypted->data[j] ^ padding_length) & mask;
}
Expand Down