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: 2026-07-04 07:27:58 Functions: 1 1 100.0 %
Branches: 19 38 50.0 %

           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                 :            : 
      18                 :            : #include "crypto/s2n_hmac.h"
      19                 :            : #include "error/s2n_errno.h"
      20                 :            : #include "tls/s2n_connection.h"
      21                 :            : #include "tls/s2n_record.h"
      22                 :            : #include "utils/s2n_mem.h"
      23                 :            : #include "utils/s2n_safety.h"
      24                 :            : 
      25                 :            : /* A TLS CBC record looks like ..
      26                 :            :  *
      27                 :            :  * [ Payload data ] [ HMAC ] [ Padding ] [ Padding length byte ]
      28                 :            :  *
      29                 :            :  * Each byte in the padding is expected to be set to the same value
      30                 :            :  * as the padding length byte. So if the padding length byte is '2'
      31                 :            :  * then the padding will be [ '2', '2' ] (there'll be three bytes
      32                 :            :  * set to that value if you include the padding length byte).
      33                 :            :  *
      34                 :            :  * The goal of s2n_verify_cbc() is to verify that the padding and hmac
      35                 :            :  * are correct, without leaking (via timing) how much padding there
      36                 :            :  * actually is: as this is considered secret. 
      37                 :            :  *
      38                 :            :  * In addition to our efforts here though, s2n also wraps any CBC
      39                 :            :  * verification error (or record parsing error in general) with
      40                 :            :  * a randomized delay of between 1ms and 10 seconds. See s2n_connection.c.
      41                 :            :  * This amount of delay randomization is sufficient to increase the
      42                 :            :  * complexity of attack for even a 1 microsecond timing leak (which
      43                 :            :  * is quite large) by a factor of around 83 trillion.
      44                 :            :  */
      45                 :            : int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, struct s2n_blob *decrypted)
      46                 :      41812 : {
      47                 :      41812 :     uint8_t mac_digest_size = 0;
      48         [ -  + ]:      41812 :     POSIX_GUARD(s2n_hmac_digest_size(hmac->alg, &mac_digest_size));
      49                 :            : 
      50                 :            :     /* The record has to be at least big enough to contain the MAC,
      51                 :            :      * plus the padding length byte */
      52 [ -  + ][ #  # ]:      41812 :     POSIX_ENSURE_GT(decrypted->size, mac_digest_size);
      53                 :            : 
      54                 :      41812 :     int payload_and_padding_size = decrypted->size - mac_digest_size;
      55                 :            : 
      56                 :            :     /* Determine what the padding length is */
      57                 :      41812 :     uint8_t padding_length = decrypted->data[decrypted->size - 1];
      58                 :            : 
      59         [ +  + ]:      41812 :     int payload_length = S2N_MAX(payload_and_padding_size - padding_length - 1, 0);
      60                 :            : 
      61                 :            :     /* Update the MAC */
      62         [ -  + ]:      41812 :     POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data, payload_length));
      63                 :      41812 :     int currently_in_hash_block = hmac->currently_in_hash_block;
      64                 :            : 
      65                 :            :     /* Check the MAC */
      66                 :      41812 :     uint8_t check_digest[S2N_MAX_DIGEST_LEN];
      67 [ #  # ][ -  + ]:      41812 :     POSIX_ENSURE_LTE(mac_digest_size, sizeof(check_digest));
      68         [ -  + ]:      41812 :     POSIX_GUARD(s2n_hmac_digest_two_compression_rounds(hmac, check_digest, mac_digest_size));
      69                 :            : 
      70                 :      41812 :     int mismatches = s2n_constant_time_equals(decrypted->data + payload_length, check_digest, mac_digest_size) ^ 1;
      71                 :            : 
      72                 :            :     /* Compute a MAC on the rest of the data so that we perform the same number of hash operations.
      73                 :            :      * Include the partial hash block from the first MAC to ensure we use the same number of blocks.
      74                 :            :      */
      75         [ -  + ]:      41812 :     POSIX_GUARD(s2n_hmac_reset(hmac));
      76         [ -  + ]:      41812 :     POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data, currently_in_hash_block));
      77         [ -  + ]:      41812 :     POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data + payload_length + mac_digest_size, decrypted->size - payload_length - mac_digest_size - 1));
      78                 :            : 
      79                 :            :     /* SSLv3 doesn't specify what the padding should actually be, so
      80                 :            :      * padding bytes are not verified. This is the vector for the POODLE
      81                 :            :      * attack (CVE-2014-3566). SSLv3 is disabled by default and not
      82                 :            :      * recommended. If SSLv3 must be used, the blinding feature (enabled
      83                 :            :      * by default) helps mitigates this issue as well.
      84                 :            :      */
      85         [ +  + ]:      41812 :     if (conn->actual_protocol_version == S2N_SSLv3) {
      86                 :        666 :         return 0 - mismatches;
      87                 :        666 :     }
      88                 :            : 
      89                 :            :     /* Check the maximum amount that could theoretically be padding */
      90         [ +  + ]:      41146 :     uint32_t check = S2N_MIN(255, (payload_and_padding_size - 1));
      91                 :            : 
      92 [ -  + ][ #  # ]:      41146 :     POSIX_ENSURE_GTE(check, padding_length);
      93                 :            : 
      94                 :      41146 :     uint32_t cutoff = check - padding_length;
      95 [ +  + ][ +  - ]:   10254628 :     for (size_t i = 0, j = decrypted->size - 1 - check; i < check && j < decrypted->size; i++, j++) {
      96                 :   10213482 :         uint8_t mask = ~(0xff << ((i >= cutoff) * 8));
      97                 :   10213482 :         mismatches |= (decrypted->data[j] ^ padding_length) & mask;
      98                 :   10213482 :     }
      99                 :            : 
     100 [ -  + ][ #  # ]:      41146 :     S2N_ERROR_IF(mismatches, S2N_ERR_CBC_VERIFY);
     101                 :            : 
     102                 :      41146 :     return 0;
     103                 :      41146 : }

Generated by: LCOV version 1.14