LCOV - code coverage report
Current view: top level - tls - s2n_cbc.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 29 29 100.0 %
Date: 2025-08-15 07:28:39 Functions: 1 1 100.0 %
Branches: 15 34 44.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License").
       5                 :            :  * You may not use this file except in compliance with the License.
       6                 :            :  * A copy of the License is located at
       7                 :            :  *
       8                 :            :  *  http://aws.amazon.com/apache2.0
       9                 :            :  *
      10                 :            :  * or in the "license" file accompanying this file. This file is distributed
      11                 :            :  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
      12                 :            :  * express or implied. See the License for the specific language governing
      13                 :            :  * permissions and limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <stdint.h>
      17                 :            : #include <sys/param.h>
      18                 :            : 
      19                 :            : #include "crypto/s2n_hmac.h"
      20                 :            : #include "error/s2n_errno.h"
      21                 :            : #include "tls/s2n_connection.h"
      22                 :            : #include "tls/s2n_record.h"
      23                 :            : #include "utils/s2n_mem.h"
      24                 :            : #include "utils/s2n_safety.h"
      25                 :            : 
      26                 :            : /* A TLS CBC record looks like ..
      27                 :            :  *
      28                 :            :  * [ Payload data ] [ HMAC ] [ Padding ] [ Padding length byte ]
      29                 :            :  *
      30                 :            :  * Each byte in the padding is expected to be set to the same value
      31                 :            :  * as the padding length byte. So if the padding length byte is '2'
      32                 :            :  * then the padding will be [ '2', '2' ] (there'll be three bytes
      33                 :            :  * set to that value if you include the padding length byte).
      34                 :            :  *
      35                 :            :  * The goal of s2n_verify_cbc() is to verify that the padding and hmac
      36                 :            :  * are correct, without leaking (via timing) how much padding there
      37                 :            :  * actually is: as this is considered secret. 
      38                 :            :  *
      39                 :            :  * In addition to our efforts here though, s2n also wraps any CBC
      40                 :            :  * verification error (or record parsing error in general) with
      41                 :            :  * a randomized delay of between 1ms and 10 seconds. See s2n_connection.c.
      42                 :            :  * This amount of delay randomization is sufficient to increase the
      43                 :            :  * complexity of attack for even a 1 microsecond timing leak (which
      44                 :            :  * is quite large) by a factor of around 83 trillion.
      45                 :            :  */
      46                 :            : int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, struct s2n_blob *decrypted)
      47                 :      41767 : {
      48                 :      41767 :     uint8_t mac_digest_size = 0;
      49         [ -  + ]:      41767 :     POSIX_GUARD(s2n_hmac_digest_size(hmac->alg, &mac_digest_size));
      50                 :            : 
      51                 :            :     /* The record has to be at least big enough to contain the MAC,
      52                 :            :      * plus the padding length byte */
      53 [ -  + ][ #  # ]:      41767 :     POSIX_ENSURE_GT(decrypted->size, mac_digest_size);
      54                 :            : 
      55                 :      41767 :     int payload_and_padding_size = decrypted->size - mac_digest_size;
      56                 :            : 
      57                 :            :     /* Determine what the padding length is */
      58                 :      41767 :     uint8_t padding_length = decrypted->data[decrypted->size - 1];
      59                 :            : 
      60                 :      41767 :     int payload_length = MAX(payload_and_padding_size - padding_length - 1, 0);
      61                 :            : 
      62                 :            :     /* Update the MAC */
      63         [ -  + ]:      41767 :     POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data, payload_length));
      64                 :      41767 :     int currently_in_hash_block = hmac->currently_in_hash_block;
      65                 :            : 
      66                 :            :     /* Check the MAC */
      67                 :      41767 :     uint8_t check_digest[S2N_MAX_DIGEST_LEN];
      68 [ #  # ][ -  + ]:      41767 :     POSIX_ENSURE_LTE(mac_digest_size, sizeof(check_digest));
      69         [ -  + ]:      41767 :     POSIX_GUARD(s2n_hmac_digest_two_compression_rounds(hmac, check_digest, mac_digest_size));
      70                 :            : 
      71                 :      41767 :     int mismatches = s2n_constant_time_equals(decrypted->data + payload_length, check_digest, mac_digest_size) ^ 1;
      72                 :            : 
      73                 :            :     /* Compute a MAC on the rest of the data so that we perform the same number of hash operations.
      74                 :            :      * Include the partial hash block from the first MAC to ensure we use the same number of blocks.
      75                 :            :      */
      76         [ -  + ]:      41767 :     POSIX_GUARD(s2n_hmac_reset(hmac));
      77         [ -  + ]:      41767 :     POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data, currently_in_hash_block));
      78         [ -  + ]:      41767 :     POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data + payload_length + mac_digest_size, decrypted->size - payload_length - mac_digest_size - 1));
      79                 :            : 
      80                 :            :     /* SSLv3 doesn't specify what the padding should actually be */
      81         [ +  + ]:      41767 :     if (conn->actual_protocol_version == S2N_SSLv3) {
      82                 :        625 :         return 0 - mismatches;
      83                 :        625 :     }
      84                 :            : 
      85                 :            :     /* Check the maximum amount that could theoretically be padding */
      86                 :      41142 :     uint32_t check = MIN(255, (payload_and_padding_size - 1));
      87                 :            : 
      88 [ -  + ][ #  # ]:      41142 :     POSIX_ENSURE_GTE(check, padding_length);
      89                 :            : 
      90                 :      41142 :     uint32_t cutoff = check - padding_length;
      91 [ +  + ][ +  - ]:   10254548 :     for (size_t i = 0, j = decrypted->size - 1 - check; i < check && j < decrypted->size; i++, j++) {
      92                 :   10213406 :         uint8_t mask = ~(0xff << ((i >= cutoff) * 8));
      93                 :   10213406 :         mismatches |= (decrypted->data[j] ^ padding_length) & mask;
      94                 :   10213406 :     }
      95                 :            : 
      96 [ -  + ][ #  # ]:      41142 :     S2N_ERROR_IF(mismatches, S2N_ERR_CBC_VERIFY);
      97                 :            : 
      98                 :      41142 :     return 0;
      99                 :      41142 : }

Generated by: LCOV version 1.14