LCOV - code coverage report
Current view: top level - crypto - s2n_prf_libcrypto.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 0 48 0.0 %
Date: 2025-08-15 07:28:39 Functions: 0 1 0.0 %
Branches: 0 60 0.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 "crypto/s2n_prf_libcrypto.h"
      17                 :            : 
      18                 :            : #include "crypto/s2n_hash.h"
      19                 :            : #include "error/s2n_errno.h"
      20                 :            : #include "tls/s2n_connection.h"
      21                 :            : #include "utils/s2n_safety.h"
      22                 :            : 
      23                 :            : #if defined(OPENSSL_IS_AWSLC)
      24                 :            : 
      25                 :            : /* The AWSLC TLS PRF API is exported in all AWSLC versions. However, in the AWSLC FIPS branch, this
      26                 :            :  * API is defined in a private header:
      27                 :            :  * https://github.com/aws/aws-lc/blob/d251b365b73a6e6acff6ee634aa8f077f23cdea4/crypto/fipsmodule/tls/internal.h#L27
      28                 :            :  *
      29                 :            :  * AWSLC has committed to this API definition, and the API has been added to a public header in the
      30                 :            :  * main branch: https://github.com/aws/aws-lc/pull/1033. As such, this API is forward-declared in
      31                 :            :  * order to make it accessible to s2n-tls when linked to AWSLC-FIPS.
      32                 :            :  */
      33                 :            : int CRYPTO_tls1_prf(const EVP_MD *digest,
      34                 :            :         uint8_t *out, size_t out_len,
      35                 :            :         const uint8_t *secret, size_t secret_len,
      36                 :            :         const char *label, size_t label_len,
      37                 :            :         const uint8_t *seed1, size_t seed1_len,
      38                 :            :         const uint8_t *seed2, size_t seed2_len);
      39                 :            : 
      40                 :            : S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn,
      41                 :            :         struct s2n_blob *secret, struct s2n_blob *label,
      42                 :            :         struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c,
      43                 :            :         struct s2n_blob *out)
      44                 :            : {
      45                 :            :     const EVP_MD *digest = NULL;
      46                 :            :     if (conn->actual_protocol_version < S2N_TLS12) {
      47                 :            :         /* md5_sha1 is a digest that indicates both MD5 and SHA1 should be used in the PRF calculation.
      48                 :            :          * This is needed for pre-TLS12 PRFs.
      49                 :            :          */
      50                 :            :         digest = EVP_md5_sha1();
      51                 :            :     } else {
      52                 :            :         RESULT_GUARD(s2n_hmac_md_from_alg(conn->secure->cipher_suite->prf_alg, &digest));
      53                 :            :     }
      54                 :            :     RESULT_ENSURE_REF(digest);
      55                 :            : 
      56                 :            :     DEFER_CLEANUP(struct s2n_stuffer seed_b_stuffer = { 0 }, s2n_stuffer_free);
      57                 :            :     size_t seed_b_len = 0;
      58                 :            :     uint8_t *seed_b_data = NULL;
      59                 :            : 
      60                 :            :     if (seed_b != NULL) {
      61                 :            :         struct s2n_blob seed_b_blob = { 0 };
      62                 :            :         RESULT_GUARD_POSIX(s2n_blob_init(&seed_b_blob, seed_b->data, seed_b->size));
      63                 :            :         RESULT_GUARD_POSIX(s2n_stuffer_init_written(&seed_b_stuffer, &seed_b_blob));
      64                 :            : 
      65                 :            :         if (seed_c != NULL) {
      66                 :            :             /* The AWSLC TLS PRF implementation only provides two seed arguments. If three seeds
      67                 :            :              * were provided, pass in the third seed by concatenating it with the second seed.
      68                 :            :              */
      69                 :            :             RESULT_GUARD_POSIX(s2n_stuffer_alloc(&seed_b_stuffer, seed_b->size + seed_c->size));
      70                 :            :             RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&seed_b_stuffer, seed_b->data, seed_b->size));
      71                 :            :             RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&seed_b_stuffer, seed_c->data, seed_c->size));
      72                 :            :         }
      73                 :            : 
      74                 :            :         seed_b_len = s2n_stuffer_data_available(&seed_b_stuffer);
      75                 :            :         seed_b_data = s2n_stuffer_raw_read(&seed_b_stuffer, seed_b_len);
      76                 :            :         RESULT_ENSURE_REF(seed_b_data);
      77                 :            :     }
      78                 :            : 
      79                 :            :     RESULT_GUARD_OSSL(CRYPTO_tls1_prf(digest,
      80                 :            :                               out->data, out->size,
      81                 :            :                               secret->data, secret->size,
      82                 :            :                               (const char *) label->data, label->size,
      83                 :            :                               seed_a->data, seed_a->size,
      84                 :            :                               seed_b_data, seed_b_len),
      85                 :            :             S2N_ERR_PRF_DERIVE);
      86                 :            : 
      87                 :            :     return S2N_RESULT_OK;
      88                 :            : }
      89                 :            : 
      90                 :            : #elif S2N_OPENSSL_VERSION_AT_LEAST(3, 0, 0)
      91                 :            : 
      92                 :            :     #include "crypto/s2n_kdf.h"
      93                 :            : 
      94                 :            : S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn,
      95                 :            :         struct s2n_blob *secret, struct s2n_blob *label,
      96                 :            :         struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c,
      97                 :            :         struct s2n_blob *out)
      98                 :          0 : {
      99 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE_REF(conn);
     100 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE_REF(secret);
     101 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE_REF(label);
     102 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE_REF(seed_a);
     103 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE_REF(out);
     104                 :            : 
     105                 :          0 :     struct s2n_blob empty_seed = { 0 };
     106         [ #  # ]:          0 :     if (!seed_b) {
     107                 :          0 :         seed_b = &empty_seed;
     108                 :          0 :     }
     109         [ #  # ]:          0 :     if (!seed_c) {
     110                 :          0 :         seed_c = &empty_seed;
     111                 :          0 :     }
     112                 :            : 
     113                 :            :     /* Openssl limits the size of the seed to 1024 bytes, including the label.
     114                 :            :      * This would be an issue for TLS1.2 PQ, which uses full keyshares as seeds.
     115                 :            :      * However, s2n-tls doesn't support PQ with Openssl, so this limitation will
     116                 :            :      * never affect customers.
     117                 :            :      *
     118                 :            :      * As of this commit, EVP_KDF_derive will fail silently (without logging any
     119                 :            :      * error) if the seed is too large. This check adds visibility.
     120                 :            :      */
     121                 :          0 :     uint64_t seed_total_size = label->size + seed_a->size + seed_b->size + seed_c->size;
     122 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE(seed_total_size <= 1024, S2N_ERR_PRF_INVALID_SEED);
     123                 :            : 
     124                 :          0 :     const char *digest_name = "MD5-SHA1";
     125                 :          0 :     const char *fetch_properties = "-fips";
     126                 :            : 
     127         [ #  # ]:          0 :     if (conn->actual_protocol_version == S2N_TLS12) {
     128                 :          0 :         fetch_properties = "";
     129                 :            : 
     130 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_REF(conn->secure);
     131 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_REF(conn->secure->cipher_suite);
     132                 :          0 :         s2n_hmac_algorithm prf_alg = conn->secure->cipher_suite->prf_alg;
     133                 :            : 
     134                 :          0 :         const EVP_MD *digest = NULL;
     135         [ #  # ]:          0 :         RESULT_GUARD(s2n_hmac_md_from_alg(prf_alg, &digest));
     136 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_REF(digest);
     137                 :          0 :         digest_name = EVP_MD_get0_name(digest);
     138 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_REF(digest_name);
     139                 :          0 :     }
     140                 :            : 
     141                 :            :     /* As an optimization, we should be able to fetch and cache this EVP_KDF*
     142                 :            :      * once when s2n_init is called.
     143                 :            :      */
     144                 :          0 :     DEFER_CLEANUP(EVP_KDF *prf_impl = EVP_KDF_fetch(NULL, "TLS1-PRF", fetch_properties),
     145                 :          0 :             EVP_KDF_free_pointer);
     146 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE(prf_impl, S2N_ERR_PRF_INVALID_ALGORITHM);
     147                 :            : 
     148                 :          0 :     DEFER_CLEANUP(EVP_KDF_CTX *prf_ctx = EVP_KDF_CTX_new(prf_impl),
     149                 :          0 :             EVP_KDF_CTX_free_pointer);
     150 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE_REF(prf_ctx);
     151                 :            : 
     152                 :          0 :     OSSL_PARAM params[] = {
     153                 :            :         /* Casting away the const is safe because providers are forbidden from
     154                 :            :          * modifying any OSSL_PARAM value other than return_size.
     155                 :            :          * Even the examples in the Openssl documentation cast const strings to
     156                 :            :          * non-const void pointers when setting up OSSL_PARAMs.
     157                 :            :          */
     158                 :          0 :         S2N_OSSL_PARAM_STR(OSSL_KDF_PARAM_PROPERTIES, (void *) (uintptr_t) fetch_properties),
     159                 :          0 :         S2N_OSSL_PARAM_STR(OSSL_KDF_PARAM_DIGEST, (void *) (uintptr_t) digest_name),
     160                 :          0 :         S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SECRET, secret),
     161                 :            :         /* "TLS1-PRF" handles the label like just another seed */
     162                 :          0 :         S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, label),
     163                 :          0 :         S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, seed_a),
     164                 :          0 :         S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, seed_b),
     165                 :          0 :         S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, seed_c),
     166                 :          0 :         OSSL_PARAM_END,
     167                 :          0 :     };
     168                 :            : 
     169 [ #  # ][ #  # ]:          0 :     RESULT_GUARD_OSSL(EVP_KDF_derive(prf_ctx, out->data, out->size, params),
     170                 :          0 :             S2N_ERR_PRF_DERIVE);
     171                 :          0 :     return S2N_RESULT_OK;
     172                 :          0 : }
     173                 :            : 
     174                 :            : #else
     175                 :            : 
     176                 :            : S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn,
     177                 :            :         struct s2n_blob *secret, struct s2n_blob *label,
     178                 :            :         struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c,
     179                 :            :         struct s2n_blob *out)
     180                 :            : {
     181                 :            :     RESULT_BAIL(S2N_ERR_FIPS_MODE_UNSUPPORTED);
     182                 :            : }
     183                 :            : 
     184                 :            : #endif

Generated by: LCOV version 1.14