LCOV - code coverage report
Current view: top level - crypto - s2n_drbg.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 138 139 99.3 %
Date: 2025-08-15 07:28:39 Functions: 12 12 100.0 %
Branches: 91 236 38.6 %

           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 "crypto/s2n_drbg.h"
      17                 :            : 
      18                 :            : #include <openssl/evp.h>
      19                 :            : #include <sys/param.h>
      20                 :            : 
      21                 :            : #include "crypto/s2n_openssl.h"
      22                 :            : #include "utils/s2n_blob.h"
      23                 :            : #include "utils/s2n_random.h"
      24                 :            : #include "utils/s2n_safety.h"
      25                 :            : 
      26                 :            : static bool ignore_prediction_resistance_for_testing = false;
      27                 :            : 
      28                 :            : #define s2n_drbg_key_size(drgb)  EVP_CIPHER_CTX_key_length((drbg)->ctx)
      29                 :            : #define s2n_drbg_seed_size(drgb) (S2N_DRBG_BLOCK_SIZE + s2n_drbg_key_size(drgb))
      30                 :            : 
      31                 :            : /* This function is the same as s2n_increment_sequence_number
      32                 :            :     but it does not check for overflow, since overflow is
      33                 :            :     acceptable in DRBG */
      34                 :            : S2N_RESULT s2n_increment_drbg_counter(struct s2n_blob *counter)
      35                 :  148222744 : {
      36         [ +  + ]:  148804007 :     for (uint32_t i = (uint32_t) counter->size; i > 0; i--) {
      37                 :  148804007 :         counter->data[i - 1] += 1;
      38         [ +  + ]:  148804007 :         if (counter->data[i - 1]) {
      39                 :  148222982 :             break;
      40                 :  148222982 :         }
      41                 :            : 
      42                 :            :         /* seq[i] wrapped, so let it carry */
      43                 :  148804007 :     }
      44                 :  148222744 :     return S2N_RESULT_OK;
      45                 :  148222744 : }
      46                 :            : 
      47                 :            : static S2N_RESULT s2n_drbg_block_encrypt(EVP_CIPHER_CTX *ctx, uint8_t in[S2N_DRBG_BLOCK_SIZE], uint8_t out[S2N_DRBG_BLOCK_SIZE])
      48                 :  148222970 : {
      49 [ -  + ][ #  # ]:  148222970 :     RESULT_ENSURE_REF(ctx);
      50                 :            : 
      51                 :            :     /* len is set by EVP_EncryptUpdate and checked post operation */
      52                 :  148222970 :     int len = S2N_DRBG_BLOCK_SIZE;
      53 [ -  + ][ #  # ]:  148222970 :     RESULT_GUARD_OSSL(EVP_EncryptUpdate(ctx, out, &len, in, S2N_DRBG_BLOCK_SIZE), S2N_ERR_DRBG);
      54 [ -  + ][ #  # ]:  148222970 :     RESULT_ENSURE_EQ(len, S2N_DRBG_BLOCK_SIZE);
      55                 :            : 
      56                 :  148222970 :     return S2N_RESULT_OK;
      57                 :  148222970 : }
      58                 :            : 
      59                 :            : static S2N_RESULT s2n_drbg_bits(struct s2n_drbg *drbg, struct s2n_blob *out)
      60                 :    6272843 : {
      61 [ -  + ][ #  # ]:    6272843 :     RESULT_ENSURE_REF(drbg);
      62 [ -  + ][ #  # ]:    6272843 :     RESULT_ENSURE_REF(drbg->ctx);
      63 [ #  # ][ -  + ]:    6272843 :     RESULT_ENSURE_REF(out);
      64                 :            : 
      65                 :    6272843 :     struct s2n_blob value = { 0 };
      66         [ -  + ]:    6272843 :     RESULT_GUARD_POSIX(s2n_blob_init(&value, drbg->v, sizeof(drbg->v)));
      67                 :    6272843 :     uint32_t block_aligned_size = out->size - (out->size % S2N_DRBG_BLOCK_SIZE);
      68                 :            : 
      69                 :            :     /* Per NIST SP800-90A 10.2.1.2: */
      70         [ +  + ]:  153669227 :     for (size_t i = 0; i < block_aligned_size; i += S2N_DRBG_BLOCK_SIZE) {
      71         [ -  + ]:  147396384 :         RESULT_GUARD(s2n_increment_drbg_counter(&value));
      72         [ -  + ]:  147396384 :         RESULT_GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, out->data + i));
      73                 :  147396384 :         drbg->bytes_used += S2N_DRBG_BLOCK_SIZE;
      74                 :  147396384 :     }
      75                 :            : 
      76         [ +  + ]:    6272843 :     if (out->size <= block_aligned_size) {
      77                 :    5446596 :         return S2N_RESULT_OK;
      78                 :    5446596 :     }
      79                 :            : 
      80                 :     826247 :     uint8_t spare_block[S2N_DRBG_BLOCK_SIZE];
      81         [ -  + ]:     826247 :     RESULT_GUARD(s2n_increment_drbg_counter(&value));
      82         [ -  + ]:     826247 :     RESULT_GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, spare_block));
      83                 :     826247 :     drbg->bytes_used += S2N_DRBG_BLOCK_SIZE;
      84                 :            : 
      85 [ -  + ][ #  # ]:     826247 :     RESULT_CHECKED_MEMCPY(out->data + block_aligned_size, spare_block, out->size - block_aligned_size);
                 [ +  + ]
      86                 :            : 
      87                 :     826247 :     return S2N_RESULT_OK;
      88                 :     826247 : }
      89                 :            : 
      90                 :            : static S2N_RESULT s2n_drbg_update(struct s2n_drbg *drbg, struct s2n_blob *provided_data)
      91                 :    4014527 : {
      92 [ -  + ][ #  # ]:    4014527 :     RESULT_ENSURE_REF(drbg);
      93 [ #  # ][ -  + ]:    4014527 :     RESULT_ENSURE_REF(drbg->ctx);
      94 [ -  + ][ #  # ]:    4014527 :     RESULT_ENSURE_REF(provided_data);
      95                 :            : 
      96 [ -  + ][ #  # ]:    8029054 :     RESULT_STACK_BLOB(temp_blob, s2n_drbg_seed_size(drgb), S2N_DRBG_MAX_SEED_SIZE);
                 [ -  + ]
      97                 :            : 
      98 [ -  + ][ #  # ]:    4014527 :     RESULT_ENSURE_EQ(provided_data->size, (uint32_t) s2n_drbg_seed_size(drbg));
      99                 :            : 
     100         [ -  + ]:    4014527 :     RESULT_GUARD(s2n_drbg_bits(drbg, &temp_blob));
     101                 :            : 
     102                 :            :     /* XOR in the provided data */
     103         [ +  + ]:  158064012 :     for (uint32_t i = 0; i < provided_data->size; i++) {
     104                 :  154049485 :         temp_blob.data[i] ^= provided_data->data[i];
     105                 :  154049485 :     }
     106                 :            : 
     107                 :            :     /* Update the key and value */
     108 [ -  + ][ #  # ]:    4014527 :     RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, temp_blob.data, NULL), S2N_ERR_DRBG);
     109                 :            : 
     110 [ -  + ][ #  # ]:    4014527 :     RESULT_CHECKED_MEMCPY(drbg->v, temp_blob.data + s2n_drbg_key_size(drbg), S2N_DRBG_BLOCK_SIZE);
                 [ +  + ]
     111                 :            : 
     112                 :    4014527 :     return S2N_RESULT_OK;
     113                 :    4014527 : }
     114                 :            : 
     115                 :            : static S2N_RESULT s2n_drbg_mix_in_entropy(struct s2n_drbg *drbg, struct s2n_blob *entropy, struct s2n_blob *ps)
     116                 :    1756272 : {
     117 [ -  + ][ #  # ]:    1756272 :     RESULT_ENSURE_REF(drbg);
     118 [ -  + ][ #  # ]:    1756272 :     RESULT_ENSURE_REF(drbg->ctx);
     119 [ -  + ][ #  # ]:    1756272 :     RESULT_ENSURE_REF(entropy);
     120                 :            : 
     121 [ -  + ][ #  # ]:    1756272 :     RESULT_ENSURE_GTE(entropy->size, ps->size);
     122                 :            : 
     123         [ +  + ]:   69031392 :     for (uint32_t i = 0; i < ps->size; i++) {
     124                 :   67275120 :         entropy->data[i] ^= ps->data[i];
     125                 :   67275120 :     }
     126                 :            : 
     127         [ -  + ]:    1756272 :     RESULT_GUARD(s2n_drbg_update(drbg, entropy));
     128                 :            : 
     129                 :    1756272 :     return S2N_RESULT_OK;
     130                 :    1756272 : }
     131                 :            : 
     132                 :            : static S2N_RESULT s2n_drbg_seed(struct s2n_drbg *drbg, struct s2n_blob *ps)
     133                 :       6818 : {
     134 [ -  + ][ -  + ]:       6818 :     RESULT_STACK_BLOB(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
                 [ #  # ]
     135                 :            : 
     136         [ -  + ]:       6818 :     RESULT_GUARD(s2n_get_seed_entropy(&blob));
     137         [ -  + ]:       6818 :     RESULT_GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps));
     138                 :            : 
     139                 :       6818 :     drbg->bytes_used = 0;
     140                 :            : 
     141                 :       6818 :     return S2N_RESULT_OK;
     142                 :       6818 : }
     143                 :            : 
     144                 :            : static S2N_RESULT s2n_drbg_mix(struct s2n_drbg *drbg, struct s2n_blob *ps)
     145                 :    2258186 : {
     146         [ +  + ]:    2258186 :     if (s2n_unlikely(ignore_prediction_resistance_for_testing)) {
     147 [ -  + ][ #  # ]:     508778 :         RESULT_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST);
     148                 :     508778 :         return S2N_RESULT_OK;
     149                 :     508778 :     }
     150                 :            : 
     151 [ -  + ][ #  # ]:    3498816 :     RESULT_STACK_BLOB(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
                 [ -  + ]
     152                 :            : 
     153         [ -  + ]:    1749408 :     RESULT_GUARD(s2n_get_mix_entropy(&blob));
     154         [ -  + ]:    1749408 :     RESULT_GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps));
     155                 :            : 
     156                 :    1749408 :     drbg->mixes += 1;
     157                 :            : 
     158                 :    1749408 :     return S2N_RESULT_OK;
     159                 :    1749408 : }
     160                 :            : 
     161                 :            : S2N_RESULT s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string, const s2n_drbg_mode mode)
     162                 :       6846 : {
     163 [ -  + ][ #  # ]:       6846 :     RESULT_ENSURE_REF(drbg);
     164 [ -  + ][ #  # ]:       6846 :     RESULT_ENSURE_REF(personalization_string);
     165                 :            : 
     166                 :       6846 :     drbg->ctx = EVP_CIPHER_CTX_new();
     167         [ -  + ]:       6846 :     RESULT_GUARD_PTR(drbg->ctx);
     168                 :            : 
     169 [ -  + ][ #  # ]:       6846 :     RESULT_EVP_CTX_INIT(drbg->ctx);
     170                 :            : 
     171                 :       6846 :     switch (mode) {
     172         [ +  + ]:       3467 :         case S2N_AES_128_CTR_NO_DF_PR:
     173 [ #  # ][ -  + ]:       3467 :             RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_128_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG);
     174                 :       3467 :             break;
     175         [ +  + ]:       3467 :         case S2N_AES_256_CTR_NO_DF_PR:
     176 [ #  # ][ -  + ]:       3309 :             RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_256_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG);
     177                 :       3309 :             break;
     178         [ -  + ]:       3309 :         default:
     179         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_DRBG);
     180                 :       6846 :     }
     181                 :            : 
     182 [ -  + ][ #  # ]:       6797 :     RESULT_ENSURE_LTE(s2n_drbg_key_size(drbg), S2N_DRBG_MAX_KEY_SIZE);
     183 [ -  + ][ #  # ]:       6797 :     RESULT_ENSURE_LTE(s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
     184                 :            : 
     185                 :       6797 :     static const uint8_t zero_key[S2N_DRBG_MAX_KEY_SIZE] = { 0 };
     186                 :            : 
     187                 :            :     /* Start off with zeroed data, per 10.2.1.3.1 item 4 and 5 */
     188                 :       6797 :     memset(drbg->v, 0, sizeof(drbg->v));
     189 [ -  + ][ #  # ]:       6797 :     RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, zero_key, NULL), S2N_ERR_DRBG);
     190                 :            : 
     191                 :            :     /* Copy the personalization string */
     192 [ -  + ][ #  # ]:      13594 :     RESULT_STACK_BLOB(ps, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
                 [ -  + ]
     193         [ -  + ]:       6797 :     RESULT_GUARD_POSIX(s2n_blob_zero(&ps));
     194                 :            : 
     195 [ #  # ][ -  + ]:       6797 :     RESULT_CHECKED_MEMCPY(ps.data, personalization_string->data, MIN(ps.size, personalization_string->size));
         [ +  + ][ +  + ]
     196                 :            : 
     197                 :            :     /* Seed the DRBG */
     198         [ -  + ]:       6797 :     RESULT_GUARD(s2n_drbg_seed(drbg, &ps));
     199                 :            : 
     200                 :       6797 :     return S2N_RESULT_OK;
     201                 :       6797 : }
     202                 :            : 
     203                 :            : S2N_RESULT s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *blob)
     204                 :    2258257 : {
     205 [ -  + ][ #  # ]:    2258257 :     RESULT_ENSURE_REF(drbg);
     206 [ -  + ][ #  # ]:    2258257 :     RESULT_ENSURE_REF(drbg->ctx);
     207                 :            : 
     208 [ -  + ][ #  # ]:    4516514 :     RESULT_STACK_BLOB(zeros, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
                 [ -  + ]
     209                 :            : 
     210 [ #  # ][ -  + ]:    2258257 :     RESULT_ENSURE(blob->size <= S2N_DRBG_GENERATE_LIMIT, S2N_ERR_DRBG_REQUEST_SIZE);
     211                 :            : 
     212                 :            :     /* Mix in additional entropy for every randomness generation call. This
     213                 :            :      * defense mechanism is referred to as "prediction resistance".
     214                 :            :      * If we ever relax this defense, we must:
     215                 :            :      *  1. Implement reseeding according to limit specified in
     216                 :            :      *     NIST SP800-90A 10.2.1 Table 3.
     217                 :            :      *  2. Re-consider whether the current fork detection strategy is still
     218                 :            :      *     sufficient.
     219                 :            :      */
     220         [ -  + ]:    2258257 :     RESULT_GUARD(s2n_drbg_mix(drbg, &zeros));
     221         [ -  + ]:    2258257 :     RESULT_GUARD(s2n_drbg_bits(drbg, blob));
     222         [ -  + ]:    2258257 :     RESULT_GUARD(s2n_drbg_update(drbg, &zeros));
     223                 :            : 
     224                 :    2258257 :     return S2N_RESULT_OK;
     225                 :    2258257 : }
     226                 :            : 
     227                 :            : S2N_RESULT s2n_drbg_wipe(struct s2n_drbg *drbg)
     228                 :       7369 : {
     229 [ -  + ][ #  # ]:       7369 :     RESULT_ENSURE_REF(drbg);
     230                 :            : 
     231         [ +  + ]:       7369 :     if (drbg->ctx) {
     232 [ -  + ][ #  # ]:       6717 :         RESULT_GUARD_OSSL(EVP_CIPHER_CTX_cleanup(drbg->ctx), S2N_ERR_DRBG);
     233                 :            : 
     234                 :       6717 :         EVP_CIPHER_CTX_free(drbg->ctx);
     235                 :       6717 :         drbg->ctx = NULL;
     236                 :       6717 :     }
     237                 :            : 
     238                 :       7369 :     *drbg = (struct s2n_drbg){ 0 };
     239                 :       7369 :     return S2N_RESULT_OK;
     240                 :       7369 : }
     241                 :            : 
     242                 :            : S2N_RESULT s2n_drbg_bytes_used(struct s2n_drbg *drbg, uint64_t *bytes_used)
     243                 :        226 : {
     244 [ -  + ][ #  # ]:        226 :     RESULT_ENSURE_REF(drbg);
     245 [ #  # ][ -  + ]:        226 :     RESULT_ENSURE_REF(bytes_used);
     246                 :            : 
     247                 :        226 :     *bytes_used = drbg->bytes_used;
     248                 :        226 :     return S2N_RESULT_OK;
     249                 :        226 : }
     250                 :            : 
     251                 :            : S2N_RESULT s2n_ignore_prediction_resistance_for_testing(bool ignore_bool)
     252                 :        106 : {
     253 [ -  + ][ #  # ]:        106 :     RESULT_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST);
     254                 :            : 
     255                 :        106 :     ignore_prediction_resistance_for_testing = ignore_bool;
     256                 :            : 
     257                 :        106 :     return S2N_RESULT_OK;
     258                 :        106 : }

Generated by: LCOV version 1.14