LCOV - code coverage report
Current view: top level - crypto - s2n_dhe.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 207 226 91.6 %
Date: 2026-10-06 07:26:09 Functions: 17 17 100.0 %
Branches: 103 308 33.4 %

           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_dhe.h"
      17                 :            : 
      18                 :            : #include <openssl/bn.h>
      19                 :            : #include <openssl/dh.h>
      20                 :            : #include <openssl/evp.h>
      21                 :            : #include <stdint.h>
      22                 :            : 
      23                 :            : #include "crypto/s2n_openssl.h"
      24                 :            : #include "error/s2n_errno.h"
      25                 :            : #include "stuffer/s2n_stuffer.h"
      26                 :            : #include "utils/s2n_blob.h"
      27                 :            : #include "utils/s2n_mem.h"
      28                 :            : #include "utils/s2n_safety.h"
      29                 :            : 
      30                 :            : DEFINE_POINTER_CLEANUP_FUNC(BIGNUM *, BN_free);
      31                 :            : 
      32                 :            : #define S2N_MIN_DH_PRIME_SIZE_BYTES (2048 / 8)
      33                 :            : 
      34                 :            : /* Caller is not responsible for freeing values returned by these accessors
      35                 :            :  * Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html
      36                 :            :  */
      37                 :            : static const BIGNUM *s2n_get_Ys_dh_param(struct s2n_dh_params *dh_params)
      38                 :        151 : {
      39                 :        151 :     const BIGNUM *Ys = NULL;
      40                 :            : 
      41                 :            : /* DH made opaque in Openssl 1.1.0 */
      42                 :        151 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
      43                 :        151 :     DH_get0_key(dh_params->dh, &Ys, NULL);
      44                 :            : #else
      45                 :            :     Ys = dh_params->dh->pub_key;
      46                 :            : #endif
      47                 :            : 
      48                 :        151 :     return Ys;
      49                 :        151 : }
      50                 :            : 
      51                 :            : static const BIGNUM *s2n_get_p_dh_param(struct s2n_dh_params *dh_params)
      52                 :        362 : {
      53                 :        362 :     const BIGNUM *p = NULL;
      54                 :        362 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
      55                 :        362 :     DH_get0_pqg(dh_params->dh, &p, NULL, NULL);
      56                 :            : #else
      57                 :            :     p = dh_params->dh->p;
      58                 :            : #endif
      59                 :            : 
      60                 :        362 :     return p;
      61                 :        362 : }
      62                 :            : 
      63                 :            : /* Pad the shared secret with leading zeros to a constant length equal to
      64                 :            :  * expected_size. DH_compute_key may return fewer bytes when the result has
      65                 :            :  * leading zeros, and a variable-length output could theoretically leak
      66                 :            :  * information about the shared secret via timing.
      67                 :            :  *
      68                 :            :  * DH_compute_key_padded exists to handle this, but is only available in
      69                 :            :  * certain libcrypto implementations (OpenSSL 1.1.0+). We pad manually
      70                 :            :  * for portability across all supported libcryptos.
      71                 :            :  */
      72                 :            : static void s2n_dh_pad_shared_secret(struct s2n_blob *shared_key, int computed_size, int expected_size)
      73                 :         48 : {
      74                 :         48 :     int padding = expected_size - computed_size;
      75                 :         48 :     memmove(shared_key->data + padding, shared_key->data, computed_size);
      76                 :         48 :     memset(shared_key->data, 0, padding);
      77                 :         48 :     shared_key->size = expected_size;
      78                 :         48 : }
      79                 :            : 
      80                 :            : static const BIGNUM *s2n_get_g_dh_param(struct s2n_dh_params *dh_params)
      81                 :        285 : {
      82                 :        285 :     const BIGNUM *g = NULL;
      83                 :        285 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
      84                 :        285 :     DH_get0_pqg(dh_params->dh, NULL, NULL, &g);
      85                 :            : #else
      86                 :            :     g = dh_params->dh->g;
      87                 :            : #endif
      88                 :            : 
      89                 :        285 :     return g;
      90                 :        285 : }
      91                 :            : 
      92                 :            : static int s2n_check_p_g_dh_params(struct s2n_dh_params *dh_params)
      93                 :        261 : {
      94 [ -  + ][ #  # ]:        261 :     POSIX_ENSURE_REF(dh_params);
      95 [ +  - ][ +  + ]:        261 :     POSIX_ENSURE_REF(dh_params->dh);
      96                 :            : 
      97                 :        260 :     const BIGNUM *p = s2n_get_p_dh_param(dh_params);
      98                 :        260 :     const BIGNUM *g = s2n_get_g_dh_param(dh_params);
      99                 :            : 
     100 [ -  + ][ #  # ]:        260 :     POSIX_ENSURE_REF(g);
     101 [ #  # ][ -  + ]:        260 :     POSIX_ENSURE_REF(p);
     102                 :            : 
     103 [ -  + ][ #  # ]:        260 :     S2N_ERROR_IF(DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_PARAMS_CREATE);
     104 [ -  + ][ #  # ]:        260 :     S2N_ERROR_IF(BN_is_zero(g), S2N_ERR_DH_PARAMS_CREATE);
     105 [ -  + ][ #  # ]:        260 :     S2N_ERROR_IF(BN_is_zero(p), S2N_ERR_DH_PARAMS_CREATE);
     106                 :            : 
     107                 :        260 :     return S2N_SUCCESS;
     108                 :        260 : }
     109                 :            : 
     110                 :            : static int s2n_check_pub_key_dh_params(struct s2n_dh_params *dh_params)
     111                 :         78 : {
     112                 :         78 :     const BIGNUM *pub_key = s2n_get_Ys_dh_param(dh_params);
     113 [ -  + ][ #  # ]:         78 :     POSIX_ENSURE_REF(pub_key);
     114                 :            : 
     115                 :            :     /*
     116                 :            :      * https://www.rfc-editor.org/rfc/rfc2631#section-2.1.5
     117                 :            :      *
     118                 :            :      * The following algorithm MAY be used to validate a received public
     119                 :            :      * key y.
     120                 :            :      *
     121                 :            :      * 1. Verify that y lies within the interval [2,p-1].
     122                 :            :      *    If it does not, the key is invalid.
     123                 :            :      *
     124                 :            :      * This check is optional per the RFC, but applied here as
     125                 :            :      * defense-in-depth to reject degenerate public key values.
     126                 :            :      */
     127 [ -  + ][ #  # ]:         78 :     S2N_ERROR_IF(BN_is_zero(pub_key), S2N_ERR_DH_PARAMS_CREATE);
     128 [ +  + ][ +  - ]:         78 :     S2N_ERROR_IF(BN_is_one(pub_key), S2N_ERR_DH_PARAMS_CREATE);
     129                 :            : 
     130                 :         77 :     const BIGNUM *p = s2n_get_p_dh_param(dh_params);
     131 [ -  + ][ #  # ]:         77 :     POSIX_ENSURE_REF(p);
     132                 :            : 
     133                 :         77 :     BIGNUM *p_minus_one = BN_dup(p);
     134 [ -  + ][ #  # ]:         77 :     POSIX_ENSURE_REF(p_minus_one);
     135         [ -  + ]:         77 :     if (!BN_sub_word(p_minus_one, 1)) {
     136                 :          0 :         BN_free(p_minus_one);
     137         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_DH_PARAMS_CREATE);
     138                 :          0 :     }
     139                 :         77 :     int cmp = BN_cmp(pub_key, p_minus_one);
     140                 :         77 :     BN_free(p_minus_one);
     141 [ +  + ][ +  - ]:         77 :     S2N_ERROR_IF(cmp > 0, S2N_ERR_DH_PARAMS_CREATE);
     142                 :            : 
     143                 :         76 :     return S2N_SUCCESS;
     144                 :         77 : }
     145                 :            : 
     146                 :            : static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g,
     147                 :            :         struct s2n_blob *Ys)
     148                 :         28 : {
     149 [ #  # ][ -  + ]:         28 :     POSIX_ENSURE(p->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
     150 [ -  + ][ #  # ]:         28 :     POSIX_ENSURE(g->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
     151 [ #  # ][ -  + ]:         28 :     POSIX_ENSURE(Ys->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
     152                 :         28 :     BIGNUM *bn_p = BN_bin2bn((const unsigned char *) p->data, p->size, NULL);
     153                 :         28 :     BIGNUM *bn_g = BN_bin2bn((const unsigned char *) g->data, g->size, NULL);
     154                 :         28 :     BIGNUM *bn_Ys = BN_bin2bn((const unsigned char *) Ys->data, Ys->size, NULL);
     155                 :            : 
     156                 :         28 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
     157                 :            :     /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html:
     158                 :            :         * values that have been passed in should not be freed directly after this function has been called
     159                 :            :         */
     160 [ -  + ][ #  # ]:         28 :     POSIX_GUARD_OSSL(DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g), S2N_ERR_DH_PARAMS_CREATE);
     161                 :            : 
     162                 :            :     /* Same as DH_set0_pqg */
     163 [ -  + ][ #  # ]:         28 :     POSIX_GUARD_OSSL(DH_set0_key(dh_params->dh, bn_Ys, NULL), S2N_ERR_DH_PARAMS_CREATE);
     164                 :            : #else
     165                 :            :     dh_params->dh->p = bn_p;
     166                 :            :     dh_params->dh->g = bn_g;
     167                 :            :     dh_params->dh->pub_key = bn_Ys;
     168                 :            : #endif
     169                 :            : 
     170                 :         28 :     return S2N_SUCCESS;
     171                 :         28 : }
     172                 :            : 
     173                 :            : int s2n_check_all_dh_params(struct s2n_dh_params *dh_params)
     174                 :         78 : {
     175         [ -  + ]:         78 :     POSIX_GUARD(s2n_check_p_g_dh_params(dh_params));
     176         [ +  + ]:         78 :     POSIX_GUARD(s2n_check_pub_key_dh_params(dh_params));
     177                 :            : 
     178                 :         76 :     return S2N_SUCCESS;
     179                 :         78 : }
     180                 :            : 
     181                 :            : int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3)
     182                 :         85 : {
     183 [ #  # ][ -  + ]:         85 :     POSIX_ENSURE_REF(dh_params);
     184 [ -  + ][ +  - ]:         85 :     POSIX_PRECONDITION(s2n_blob_validate(pkcs3));
     185                 :         85 :     DEFER_CLEANUP(struct s2n_dh_params temp_dh_params = { 0 }, s2n_dh_params_free);
     186                 :            : 
     187                 :         85 :     uint8_t *original_ptr = pkcs3->data;
     188                 :         85 :     temp_dh_params.dh = d2i_DHparams(NULL, (const unsigned char **) (void *) &pkcs3->data, pkcs3->size);
     189                 :            : 
     190         [ +  + ]:         85 :     POSIX_GUARD(s2n_check_p_g_dh_params(&temp_dh_params));
     191                 :            : 
     192         [ +  - ]:         84 :     if (pkcs3->data) {
     193 [ -  + ][ #  # ]:         84 :         POSIX_ENSURE_GTE(pkcs3->data, original_ptr);
     194 [ -  + ][ #  # ]:         84 :         POSIX_ENSURE((uint32_t) (pkcs3->data - original_ptr) == pkcs3->size, S2N_ERR_INVALID_PKCS3);
     195                 :         84 :     }
     196                 :            : 
     197                 :         84 :     pkcs3->data = original_ptr;
     198                 :            : 
     199                 :            :     /* Require at least 2048 bits for the DH size */
     200 [ -  + ][ #  # ]:         84 :     POSIX_ENSURE(DH_size(temp_dh_params.dh) >= S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_TOO_SMALL);
     201                 :            : 
     202                 :            :     /* Check the generator and prime */
     203         [ -  + ]:         84 :     POSIX_GUARD(s2n_dh_params_check(&temp_dh_params));
     204                 :            : 
     205                 :         84 :     dh_params->dh = temp_dh_params.dh;
     206                 :            : 
     207                 :         84 :     ZERO_TO_DISABLE_DEFER_CLEANUP(temp_dh_params);
     208                 :            : 
     209                 :         84 :     return S2N_SUCCESS;
     210                 :         84 : }
     211                 :            : 
     212                 :            : int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g,
     213                 :            :         struct s2n_blob *Ys)
     214                 :         28 : {
     215 [ #  # ][ -  + ]:         28 :     POSIX_ENSURE_REF(server_dh_params);
     216 [ -  + ][ +  - ]:         28 :     POSIX_PRECONDITION(s2n_blob_validate(p));
     217 [ -  + ][ +  - ]:         28 :     POSIX_PRECONDITION(s2n_blob_validate(g));
     218 [ -  + ][ +  - ]:         28 :     POSIX_PRECONDITION(s2n_blob_validate(Ys));
     219                 :            : 
     220                 :         28 :     server_dh_params->dh = DH_new();
     221 [ -  + ][ #  # ]:         28 :     POSIX_ENSURE(server_dh_params->dh != NULL, S2N_ERR_DH_PARAMS_CREATE);
     222                 :            : 
     223         [ -  + ]:         28 :     POSIX_GUARD(s2n_set_p_g_Ys_dh_params(server_dh_params, p, g, Ys));
     224         [ +  + ]:         28 :     POSIX_GUARD(s2n_check_all_dh_params(server_dh_params));
     225                 :            : 
     226                 :         26 :     return S2N_SUCCESS;
     227                 :         28 : }
     228                 :            : 
     229                 :            : int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output)
     230                 :         25 : {
     231         [ -  + ]:         25 :     POSIX_GUARD(s2n_check_all_dh_params(server_dh_params));
     232 [ -  + ][ +  - ]:         25 :     POSIX_PRECONDITION(s2n_stuffer_validate(out));
     233 [ -  + ][ +  - ]:         25 :     POSIX_PRECONDITION(s2n_blob_validate(output));
     234                 :            : 
     235                 :         25 :     const BIGNUM *bn_p = s2n_get_p_dh_param(server_dh_params);
     236                 :         25 :     const BIGNUM *bn_g = s2n_get_g_dh_param(server_dh_params);
     237                 :         25 :     const BIGNUM *bn_Ys = s2n_get_Ys_dh_param(server_dh_params);
     238                 :            : 
     239                 :            :     /* Reject sizes that don't fit in the uint16 wire encoding before truncating. */
     240                 :         25 :     int p_num_bytes = BN_num_bytes(bn_p);
     241                 :         25 :     int g_num_bytes = BN_num_bytes(bn_g);
     242                 :         25 :     int Ys_num_bytes = BN_num_bytes(bn_Ys);
     243 [ #  # ][ +  - ]:         25 :     POSIX_ENSURE(p_num_bytes >= 0 && p_num_bytes <= UINT16_MAX, S2N_ERR_DH_SERIALIZING);
                 [ +  - ]
     244 [ #  # ][ +  - ]:         25 :     POSIX_ENSURE(g_num_bytes >= 0 && g_num_bytes <= UINT16_MAX, S2N_ERR_DH_SERIALIZING);
                 [ +  - ]
     245 [ #  # ][ +  - ]:         25 :     POSIX_ENSURE(Ys_num_bytes >= 0 && Ys_num_bytes <= UINT16_MAX, S2N_ERR_DH_SERIALIZING);
                 [ +  - ]
     246                 :            : 
     247                 :         25 :     uint16_t p_size = p_num_bytes;
     248                 :         25 :     uint16_t g_size = g_num_bytes;
     249                 :         25 :     uint16_t Ys_size = Ys_num_bytes;
     250                 :         25 :     uint8_t *p = NULL;
     251                 :         25 :     uint8_t *g = NULL;
     252                 :         25 :     uint8_t *Ys = NULL;
     253                 :            : 
     254                 :         25 :     output->data = s2n_stuffer_raw_write(out, 0);
     255 [ -  + ][ #  # ]:         25 :     POSIX_ENSURE_REF(output->data);
     256                 :            : 
     257         [ -  + ]:         25 :     POSIX_GUARD(s2n_stuffer_write_uint16(out, p_size));
     258                 :         25 :     p = s2n_stuffer_raw_write(out, p_size);
     259 [ -  + ][ #  # ]:         25 :     POSIX_ENSURE_REF(p);
     260 [ #  # ][ -  + ]:         25 :     POSIX_ENSURE(BN_bn2bin(bn_p, p) == p_size, S2N_ERR_DH_SERIALIZING);
     261                 :            : 
     262         [ -  + ]:         25 :     POSIX_GUARD(s2n_stuffer_write_uint16(out, g_size));
     263                 :         25 :     g = s2n_stuffer_raw_write(out, g_size);
     264 [ -  + ][ #  # ]:         25 :     POSIX_ENSURE_REF(g);
     265 [ -  + ][ #  # ]:         25 :     POSIX_ENSURE(BN_bn2bin(bn_g, g) == g_size, S2N_ERR_DH_SERIALIZING);
     266                 :            : 
     267         [ -  + ]:         25 :     POSIX_GUARD(s2n_stuffer_write_uint16(out, Ys_size));
     268                 :         25 :     Ys = s2n_stuffer_raw_write(out, Ys_size);
     269 [ -  + ][ #  # ]:         25 :     POSIX_ENSURE_REF(Ys);
     270 [ #  # ][ -  + ]:         25 :     POSIX_ENSURE(BN_bn2bin(bn_Ys, Ys) == Ys_size, S2N_ERR_DH_SERIALIZING);
     271                 :            : 
     272                 :         25 :     output->size = p_size + 2 + g_size + 2 + Ys_size + 2;
     273                 :            : 
     274                 :         25 :     return S2N_SUCCESS;
     275                 :         25 : }
     276                 :            : 
     277                 :            : int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out,
     278                 :            :         struct s2n_blob *shared_key)
     279                 :         24 : {
     280                 :         24 :     struct s2n_dh_params client_params = { 0 };
     281                 :         24 :     uint8_t *client_pub_key = NULL;
     282                 :         24 :     uint16_t client_pub_key_size = 0;
     283                 :         24 :     int shared_key_size = 0;
     284                 :            : 
     285         [ -  + ]:         24 :     POSIX_GUARD(s2n_dh_params_check(server_dh_params));
     286         [ -  + ]:         24 :     POSIX_GUARD(s2n_dh_params_copy(server_dh_params, &client_params));
     287         [ -  + ]:         24 :     POSIX_GUARD(s2n_dh_generate_ephemeral_key(&client_params));
     288         [ -  + ]:         24 :     POSIX_GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh)));
     289                 :            : 
     290                 :         24 :     const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params);
     291 [ -  + ][ #  # ]:         24 :     POSIX_ENSURE_REF(client_pub_key_bn);
     292                 :            :     /* Reject sizes that don't fit in the uint16 wire encoding before truncating. */
     293                 :         24 :     int client_pub_key_num_bytes = BN_num_bytes(client_pub_key_bn);
     294 [ -  + ][ -  + ]:         24 :     if (client_pub_key_num_bytes < 0 || client_pub_key_num_bytes > UINT16_MAX) {
     295         [ #  # ]:          0 :         POSIX_GUARD(s2n_free(shared_key));
     296         [ #  # ]:          0 :         POSIX_GUARD(s2n_dh_params_free(&client_params));
     297         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_DH_WRITING_PUBLIC_KEY);
     298                 :          0 :     }
     299                 :         24 :     client_pub_key_size = client_pub_key_num_bytes;
     300         [ -  + ]:         24 :     POSIX_GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size));
     301                 :         24 :     client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size);
     302         [ -  + ]:         24 :     if (client_pub_key == NULL) {
     303         [ #  # ]:          0 :         POSIX_GUARD(s2n_free(shared_key));
     304         [ #  # ]:          0 :         POSIX_GUARD(s2n_dh_params_free(&client_params));
     305         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_DH_WRITING_PUBLIC_KEY);
     306                 :          0 :     }
     307                 :            : 
     308         [ -  + ]:         24 :     if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) {
     309         [ #  # ]:          0 :         POSIX_GUARD(s2n_free(shared_key));
     310         [ #  # ]:          0 :         POSIX_GUARD(s2n_dh_params_free(&client_params));
     311         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_DH_COPYING_PUBLIC_KEY);
     312                 :          0 :     }
     313                 :            : 
     314                 :            :     /* server_dh_params already validated */
     315                 :         24 :     const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params);
     316                 :         24 :     int server_dh_params_size = DH_size(server_dh_params->dh);
     317                 :         24 :     shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh);
     318         [ -  + ]:         24 :     if (shared_key_size < 0) {
     319         [ #  # ]:          0 :         POSIX_GUARD(s2n_free(shared_key));
     320         [ #  # ]:          0 :         POSIX_GUARD(s2n_dh_params_free(&client_params));
     321         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_DH_SHARED_SECRET);
     322                 :          0 :     }
     323                 :            : 
     324                 :         24 :     s2n_dh_pad_shared_secret(shared_key, shared_key_size, server_dh_params_size);
     325                 :            : 
     326         [ -  + ]:         24 :     POSIX_GUARD(s2n_dh_params_free(&client_params));
     327                 :            : 
     328                 :         24 :     return S2N_SUCCESS;
     329                 :         24 : }
     330                 :            : 
     331                 :            : int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in,
     332                 :            :         struct s2n_blob *shared_key)
     333                 :         25 : {
     334                 :         25 :     uint16_t Yc_length = 0;
     335                 :         25 :     struct s2n_blob Yc = { 0 };
     336                 :         25 :     int shared_key_size = 0;
     337                 :         25 :     DEFER_CLEANUP(BIGNUM *pub_key = NULL, BN_free_pointer);
     338                 :            : 
     339         [ -  + ]:         25 :     POSIX_GUARD(s2n_check_all_dh_params(server_dh_params));
     340                 :         25 :     int server_dh_params_size = DH_size(server_dh_params->dh);
     341 [ #  # ][ -  + ]:         25 :     POSIX_ENSURE(server_dh_params_size <= INT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
     342                 :            : 
     343                 :            :     /*
     344                 :            :      * As defined in https://www.rfc-editor.org/rfc/rfc5246#section-7.4.7.2,
     345                 :            :      * the client's DH public value (Yc) is sent as a variable-length opaque value.
     346                 :            :      * Validate that Yc_length does not exceed the DH group size to prevent
     347                 :            :      * unnecessary computation and memory allocation on oversized keys.
     348                 :            :      *
     349                 :            :      * According to https://www.rfc-editor.org/rfc/rfc2631#section-2.1.5,
     350                 :            :      * the valid range of Yc is [2, p-1]. When encoding a BIGNUM to bytes,
     351                 :            :      * leading zeros are often stripped, in which case Yc_length might be
     352                 :            :      * less than server_dh_params_size.
     353                 :            :      */
     354         [ -  + ]:         25 :     POSIX_GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length));
     355 [ -  + ][ #  # ]:         25 :     POSIX_ENSURE(Yc_length > 0, S2N_ERR_DH_SHARED_SECRET);
     356 [ +  - ][ +  + ]:         25 :     POSIX_ENSURE((int) Yc_length <= server_dh_params_size, S2N_ERR_DH_SHARED_SECRET);
     357                 :            : 
     358                 :         24 :     Yc.size = Yc_length;
     359                 :         24 :     Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size);
     360 [ -  + ][ #  # ]:         24 :     POSIX_ENSURE_REF(Yc.data);
     361                 :            : 
     362                 :         24 :     pub_key = BN_bin2bn((const unsigned char *) Yc.data, Yc.size, NULL);
     363 [ #  # ][ -  + ]:         24 :     POSIX_ENSURE_REF(pub_key);
     364         [ -  + ]:         24 :     POSIX_GUARD(s2n_alloc(shared_key, server_dh_params_size));
     365                 :            : 
     366                 :         24 :     shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh);
     367 [ #  # ][ -  + ]:         24 :     POSIX_ENSURE(shared_key_size > 0, S2N_ERR_DH_SHARED_SECRET);
     368                 :            : 
     369                 :         24 :     s2n_dh_pad_shared_secret(shared_key, shared_key_size, server_dh_params_size);
     370                 :            : 
     371                 :         24 :     return S2N_SUCCESS;
     372                 :         24 : }
     373                 :            : 
     374                 :            : int s2n_dh_params_check(struct s2n_dh_params *dh_params)
     375                 :        108 : {
     376 [ #  # ][ -  + ]:        108 :     POSIX_ENSURE_REF(dh_params);
     377 [ -  + ][ #  # ]:        108 :     POSIX_ENSURE_REF(dh_params->dh);
     378                 :        108 :     int codes = 0;
     379                 :            : 
     380 [ #  # ][ -  + ]:        108 :     POSIX_GUARD_OSSL(DH_check(dh_params->dh, &codes), S2N_ERR_DH_PARAMETER_CHECK);
     381 [ -  + ][ #  # ]:        108 :     POSIX_ENSURE(codes == 0, S2N_ERR_DH_PARAMETER_CHECK);
     382                 :            : 
     383                 :        108 :     return S2N_SUCCESS;
     384                 :        108 : }
     385                 :            : 
     386                 :            : int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to)
     387                 :         48 : {
     388         [ -  + ]:         48 :     POSIX_GUARD(s2n_check_p_g_dh_params(from));
     389 [ #  # ][ -  + ]:         48 :     POSIX_ENSURE_REF(to);
     390                 :            : 
     391                 :         48 :     to->dh = DHparams_dup(from->dh);
     392 [ #  # ][ -  + ]:         48 :     POSIX_ENSURE(to->dh != NULL, S2N_ERR_DH_COPYING_PARAMETERS);
     393                 :            : 
     394                 :         48 :     return S2N_SUCCESS;
     395                 :         48 : }
     396                 :            : 
     397                 :            : int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params)
     398                 :         50 : {
     399         [ -  + ]:         50 :     POSIX_GUARD(s2n_check_p_g_dh_params(dh_params));
     400                 :            : 
     401 [ -  + ][ #  # ]:         50 :     POSIX_GUARD_OSSL(DH_generate_key(dh_params->dh), S2N_ERR_DH_GENERATING_PARAMETERS);
     402                 :            : 
     403                 :         50 :     return S2N_SUCCESS;
     404                 :         50 : }
     405                 :            : 
     406                 :            : int s2n_dh_params_free(struct s2n_dh_params *dh_params)
     407                 :    3553085 : {
     408 [ -  + ][ #  # ]:    3553085 :     POSIX_ENSURE_REF(dh_params);
     409                 :    3553085 :     DH_free(dh_params->dh);
     410                 :    3553085 :     dh_params->dh = NULL;
     411                 :            : 
     412                 :    3553085 :     return S2N_SUCCESS;
     413                 :    3553085 : }

Generated by: LCOV version 1.14