LCOV - code coverage report
Current view: top level - crypto - s2n_ecc_evp.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 236 251 94.0 %
Date: 2026-10-06 07:26:09 Functions: 19 21 90.5 %
Branches: 142 390 36.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_ecc_evp.h"
      17                 :            : 
      18                 :            : #include <openssl/ecdh.h>
      19                 :            : #include <openssl/evp.h>
      20                 :            : #if defined(OPENSSL_IS_AWSLC)
      21                 :            :     #include <openssl/mem.h>
      22                 :            : #endif
      23                 :            : 
      24                 :            : #include <stdint.h>
      25                 :            : 
      26                 :            : #include "crypto/s2n_fips.h"
      27                 :            : #include "crypto/s2n_libcrypto.h"
      28                 :            : #include "tls/s2n_connection.h"
      29                 :            : #include "tls/s2n_ecc_preferences.h"
      30                 :            : #include "tls/s2n_tls_parameters.h"
      31                 :            : #include "utils/s2n_mem.h"
      32                 :            : #include "utils/s2n_safety.h"
      33                 :            : 
      34                 :            : #define TLS_EC_CURVE_TYPE_NAMED 3
      35                 :            : 
      36                 :            : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free);
      37                 :            : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY_CTX *, EVP_PKEY_CTX_free);
      38                 :            : DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free);
      39                 :            : 
      40                 :            : #if EVP_APIS_SUPPORTED
      41                 :      12283 : DEFINE_POINTER_CLEANUP_FUNC(uint8_t *, OPENSSL_free);
      42                 :            : #endif
      43                 :            : 
      44                 :            : #if !EVP_APIS_SUPPORTED
      45                 :            : DEFINE_POINTER_CLEANUP_FUNC(EC_POINT *, EC_POINT_free);
      46                 :            : #endif
      47                 :            : 
      48                 :            : #if EVP_APIS_SUPPORTED
      49                 :            : static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
      50                 :            : #else
      51                 :            : static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out);
      52                 :            : static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length);
      53                 :            : static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key);
      54                 :            : #endif
      55                 :            : static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
      56                 :            : static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
      57                 :            : static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret);
      58                 :            : static int s2n_ecc_evp_generate_key_noop(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
      59                 :            : 
      60                 :            : /* IANA values can be found here: https://tools.ietf.org/html/rfc8446#appendix-B.3.1.4 */
      61                 :            : 
      62                 :            : const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1 = {
      63                 :            :     .iana_id = TLS_EC_CURVE_SECP_256_R1,
      64                 :            :     .libcrypto_nid = NID_X9_62_prime256v1,
      65                 :            :     .name = "secp256r1",
      66                 :            :     .share_size = SECP256R1_SHARE_SIZE,
      67                 :            :     .generate_key = s2n_ecc_evp_generate_key_nist_curves,
      68                 :            : };
      69                 :            : 
      70                 :            : const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1 = {
      71                 :            :     .iana_id = TLS_EC_CURVE_SECP_384_R1,
      72                 :            :     .libcrypto_nid = NID_secp384r1,
      73                 :            :     .name = "secp384r1",
      74                 :            :     .share_size = SECP384R1_SHARE_SIZE,
      75                 :            :     .generate_key = s2n_ecc_evp_generate_key_nist_curves,
      76                 :            : };
      77                 :            : 
      78                 :            : const struct s2n_ecc_named_curve s2n_ecc_curve_secp521r1 = {
      79                 :            :     .iana_id = TLS_EC_CURVE_SECP_521_R1,
      80                 :            :     .libcrypto_nid = NID_secp521r1,
      81                 :            :     .name = "secp521r1",
      82                 :            :     .share_size = SECP521R1_SHARE_SIZE,
      83                 :            :     .generate_key = s2n_ecc_evp_generate_key_nist_curves,
      84                 :            : };
      85                 :            : 
      86                 :            : #if EVP_APIS_SUPPORTED
      87                 :            : const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = {
      88                 :            :     .iana_id = TLS_EC_CURVE_ECDH_X25519,
      89                 :            :     .libcrypto_nid = NID_X25519,
      90                 :            :     .name = "x25519",
      91                 :            :     .share_size = X25519_SHARE_SIZE,
      92                 :            :     .generate_key = s2n_ecc_evp_generate_key_x25519,
      93                 :            : };
      94                 :            : #else
      95                 :            : const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = { 0 };
      96                 :            : #endif
      97                 :            : 
      98                 :            : /* A fake / unsupported curve for use in triggering retries
      99                 :            :  * during testing.
     100                 :            :  */
     101                 :            : const struct s2n_ecc_named_curve s2n_unsupported_curve = {
     102                 :            :     .iana_id = 0,
     103                 :            :     .name = "unsupported",
     104                 :            :     .libcrypto_nid = NID_X9_62_prime256v1,
     105                 :            :     .share_size = SECP256R1_SHARE_SIZE,
     106                 :            :     .generate_key = s2n_ecc_evp_generate_key_nist_curves,
     107                 :            : };
     108                 :            : 
     109                 :            : const struct s2n_ecc_named_curve s2n_ecc_curve_none = {
     110                 :            :     .iana_id = 0,
     111                 :            :     .name = "none",
     112                 :            :     .libcrypto_nid = 0,
     113                 :            :     .share_size = 0,
     114                 :            :     .generate_key = s2n_ecc_evp_generate_key_noop,
     115                 :            : };
     116                 :            : 
     117                 :            : /* All curves that s2n supports. New curves MUST be added here.
     118                 :            :  * This list is a super set of all the curves present in s2n_ecc_preferences list.
     119                 :            :  */
     120                 :            : const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[] = {
     121                 :            :     &s2n_ecc_curve_secp256r1,
     122                 :            :     &s2n_ecc_curve_secp384r1,
     123                 :            : #if EVP_APIS_SUPPORTED
     124                 :            :     &s2n_ecc_curve_x25519,
     125                 :            : #endif
     126                 :            :     &s2n_ecc_curve_secp521r1,
     127                 :            : };
     128                 :            : 
     129                 :            : const size_t s2n_all_supported_curves_list_len = s2n_array_len(s2n_all_supported_curves_list);
     130                 :            : 
     131                 :            : int s2n_is_evp_apis_supported()
     132                 :       3687 : {
     133                 :       3687 :     return EVP_APIS_SUPPORTED;
     134                 :       3687 : }
     135                 :            : 
     136                 :            : bool s2n_ecc_evp_supports_fips_check()
     137                 :          0 : {
     138                 :            : #ifdef S2N_LIBCRYPTO_SUPPORTS_EC_KEY_CHECK_FIPS
     139                 :            :     return true;
     140                 :            : #else
     141                 :          0 :     return false;
     142                 :          0 : #endif
     143                 :          0 : }
     144                 :            : 
     145                 :            : int s2n_find_ecc_curve_from_iana_id(uint16_t iana_id, const struct s2n_ecc_named_curve **out, bool *found)
     146                 :          4 : {
     147 [ #  # ][ -  + ]:          4 :     POSIX_ENSURE_REF(out);
     148 [ #  # ][ -  + ]:          4 :     POSIX_ENSURE_REF(found);
     149                 :          4 :     *found = false;
     150                 :            : 
     151         [ +  - ]:          8 :     for (size_t i = 0; i < s2n_all_supported_curves_list_len; i++) {
     152                 :          8 :         const struct s2n_ecc_named_curve *curve = s2n_all_supported_curves_list[i];
     153 [ -  + ][ #  # ]:          8 :         POSIX_ENSURE_REF(curve);
     154         [ +  + ]:          8 :         if (curve->iana_id == iana_id) {
     155                 :          4 :             *out = curve;
     156                 :          4 :             *found = true;
     157                 :          4 :             return S2N_SUCCESS;
     158                 :          4 :         }
     159                 :          8 :     }
     160                 :          0 :     return S2N_SUCCESS;
     161                 :          4 : }
     162                 :            : 
     163                 :            : #if EVP_APIS_SUPPORTED
     164                 :            : static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
     165                 :       1960 : {
     166                 :       1960 :     DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(named_curve->libcrypto_nid, NULL),
     167                 :       1960 :             EVP_PKEY_CTX_free_pointer);
     168 [ -  + ][ #  # ]:       1960 :     S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
     169                 :            : 
     170 [ -  + ][ #  # ]:       1960 :     POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
     171 [ -  + ][ #  # ]:       1960 :     POSIX_GUARD_OSSL(EVP_PKEY_keygen(pctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
     172 [ -  + ][ #  # ]:       1960 :     S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
     173                 :            : 
     174                 :       1960 :     return 0;
     175                 :       1960 : }
     176                 :            : #endif
     177                 :            : 
     178                 :            : static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
     179                 :      12126 : {
     180                 :      12126 :     DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
     181 [ -  + ][ #  # ]:      12126 :     S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
     182                 :            : 
     183 [ -  + ][ #  # ]:      12126 :     POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
     184 [ -  + ][ #  # ]:      12126 :     POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, named_curve->libcrypto_nid), S2N_ERR_ECDHE_GEN_KEY);
     185                 :            : 
     186                 :      12126 :     DEFER_CLEANUP(EVP_PKEY *params = NULL, EVP_PKEY_free_pointer);
     187 [ #  # ][ -  + ]:      12126 :     POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &params), S2N_ERR_ECDHE_GEN_KEY);
     188 [ -  + ][ #  # ]:      12126 :     S2N_ERROR_IF(params == NULL, S2N_ERR_ECDHE_GEN_KEY);
     189                 :            : 
     190                 :      12126 :     DEFER_CLEANUP(EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL), EVP_PKEY_CTX_free_pointer);
     191 [ -  + ][ #  # ]:      12126 :     S2N_ERROR_IF(kctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
     192                 :            : 
     193 [ #  # ][ -  + ]:      12126 :     POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(kctx), S2N_ERR_ECDHE_GEN_KEY);
     194 [ -  + ][ #  # ]:      12126 :     POSIX_GUARD_OSSL(EVP_PKEY_keygen(kctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
     195 [ -  + ][ #  # ]:      12126 :     S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
     196                 :            : 
     197                 :      12126 :     return 0;
     198                 :      12126 : }
     199                 :            : 
     200                 :            : static int s2n_ecc_evp_generate_key_noop(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
     201                 :          0 : {
     202         [ #  # ]:          0 :     POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
     203                 :          0 : }
     204                 :            : 
     205                 :            : static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
     206                 :      14087 : {
     207 [ -  + ][ #  # ]:      14087 :     POSIX_ENSURE_REF(named_curve);
     208 [ +  + ][ +  - ]:      14087 :     S2N_ERROR_IF(named_curve->generate_key == NULL, S2N_ERR_ECDHE_GEN_KEY);
     209                 :            : 
     210                 :      14086 :     return named_curve->generate_key(named_curve, evp_pkey);
     211                 :      14087 : }
     212                 :            : 
     213                 :            : static S2N_RESULT s2n_ecc_check_key(EC_KEY *ec_key)
     214                 :      10185 : {
     215 [ #  # ][ -  + ]:      10185 :     RESULT_ENSURE_REF(ec_key);
     216                 :            : 
     217                 :            : #ifdef S2N_LIBCRYPTO_SUPPORTS_EC_KEY_CHECK_FIPS
     218                 :            :     if (s2n_is_in_fips_mode()) {
     219                 :            :         RESULT_GUARD_OSSL(EC_KEY_check_fips(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY_FIPS);
     220                 :            :         return S2N_RESULT_OK;
     221                 :            :     }
     222                 :            : #endif
     223                 :            : 
     224 [ +  + ][ +  - ]:      10185 :     RESULT_GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY);
     225                 :            : 
     226                 :      10182 :     return S2N_RESULT_OK;
     227                 :      10185 : }
     228                 :            : 
     229                 :            : static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret)
     230                 :      11432 : {
     231 [ -  + ][ #  # ]:      11432 :     POSIX_ENSURE_REF(peer_public);
     232 [ -  + ][ #  # ]:      11432 :     POSIX_ENSURE_REF(own_key);
     233                 :            : 
     234                 :            :     /**
     235                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2
     236                 :            :      *# For the curves secp256r1, secp384r1, and secp521r1, peers MUST
     237                 :            :      *# validate each other's public value Q by ensuring that the point is a
     238                 :            :      *# valid point on the elliptic curve.
     239                 :            :      *
     240                 :            :      *= https://www.rfc-editor.org/rfc/rfc8422#section-5.11
     241                 :            :      *# With the NIST curves, each party MUST validate the public key sent by
     242                 :            :      *# its peer in the ClientKeyExchange and ServerKeyExchange messages.  A
     243                 :            :      *# receiving party MUST check that the x and y parameters from the
     244                 :            :      *# peer's public value satisfy the curve equation, y^2 = x^3 + ax + b
     245                 :            :      *# mod p.
     246                 :            :      *
     247                 :            :      * The validation requirement for the public key value only applies to NIST curves. The
     248                 :            :      * validation is skipped with non-NIST curves for increased performance.
     249                 :            :      */
     250 [ +  + ][ +  - ]:      11432 :     if (iana_id != TLS_EC_CURVE_ECDH_X25519 && iana_id != TLS_EC_CURVE_ECDH_X448) {
     251                 :      10185 :         DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer);
     252 [ #  # ][ -  + ]:      10185 :         POSIX_ENSURE(ec_key, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     253         [ +  + ]:      10185 :         POSIX_GUARD_RESULT(s2n_ecc_check_key(ec_key));
     254                 :      10185 :     }
     255                 :            : 
     256                 :      11429 :     size_t shared_secret_size = 0;
     257                 :            : 
     258                 :      11429 :     DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(own_key, NULL), EVP_PKEY_CTX_free_pointer);
     259 [ -  + ][ #  # ]:      11429 :     S2N_ERROR_IF(ctx == NULL, S2N_ERR_ECDHE_SHARED_SECRET);
     260                 :            : 
     261 [ -  + ][ #  # ]:      11429 :     POSIX_GUARD_OSSL(EVP_PKEY_derive_init(ctx), S2N_ERR_ECDHE_SHARED_SECRET);
     262 [ -  + ][ #  # ]:      11429 :     POSIX_GUARD_OSSL(EVP_PKEY_derive_set_peer(ctx, peer_public), S2N_ERR_ECDHE_SHARED_SECRET);
     263 [ -  + ][ #  # ]:      11429 :     POSIX_GUARD_OSSL(EVP_PKEY_derive(ctx, NULL, &shared_secret_size), S2N_ERR_ECDHE_SHARED_SECRET);
     264         [ -  + ]:      11429 :     POSIX_GUARD(s2n_alloc(shared_secret, shared_secret_size));
     265                 :            : 
     266         [ -  + ]:      11429 :     if (EVP_PKEY_derive(ctx, shared_secret->data, &shared_secret_size) != 1) {
     267         [ #  # ]:          0 :         POSIX_GUARD(s2n_free(shared_secret));
     268         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
     269                 :          0 :     }
     270                 :            : 
     271                 :      11429 :     return 0;
     272                 :      11429 : }
     273                 :            : 
     274                 :            : int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params)
     275                 :      13317 : {
     276 [ +  + ][ +  - ]:      13317 :     POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
     277 [ -  + ][ #  # ]:      13313 :     S2N_ERROR_IF(ecc_evp_params->evp_pkey != NULL, S2N_ERR_ECDHE_GEN_KEY);
     278 [ +  + ][ +  - ]:      13313 :     S2N_ERROR_IF(s2n_ecc_evp_generate_own_key(ecc_evp_params->negotiated_curve, &ecc_evp_params->evp_pkey) != 0,
     279                 :      13313 :             S2N_ERR_ECDHE_GEN_KEY);
     280 [ -  + ][ #  # ]:      13312 :     S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
     281                 :      13312 :     return 0;
     282                 :      13312 : }
     283                 :            : 
     284                 :            : int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params,
     285                 :            :         struct s2n_ecc_evp_params *public_ecc_evp_params,
     286                 :            :         struct s2n_blob *shared_key)
     287                 :       9879 : {
     288 [ -  + ][ #  # ]:       9879 :     POSIX_ENSURE_REF(private_ecc_evp_params->negotiated_curve);
     289 [ -  + ][ #  # ]:       9879 :     POSIX_ENSURE_REF(private_ecc_evp_params->evp_pkey);
     290 [ -  + ][ #  # ]:       9879 :     POSIX_ENSURE_REF(public_ecc_evp_params->negotiated_curve);
     291 [ +  + ][ +  - ]:       9879 :     POSIX_ENSURE_REF(public_ecc_evp_params->evp_pkey);
     292 [ +  + ][ +  - ]:       9878 :     S2N_ERROR_IF(private_ecc_evp_params->negotiated_curve->iana_id != public_ecc_evp_params->negotiated_curve->iana_id,
     293                 :       9878 :             S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     294         [ +  + ]:       9854 :     POSIX_GUARD(s2n_ecc_evp_compute_shared_secret(private_ecc_evp_params->evp_pkey, public_ecc_evp_params->evp_pkey,
     295                 :       9851 :             private_ecc_evp_params->negotiated_curve->iana_id, shared_key));
     296                 :       9851 :     return 0;
     297                 :       9854 : }
     298                 :            : 
     299                 :            : int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_evp_params,
     300                 :            :         struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key)
     301                 :        804 : {
     302 [ -  + ][ #  # ]:        804 :     POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
     303 [ -  + ][ #  # ]:        804 :     POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
     304 [ -  + ][ #  # ]:        804 :     POSIX_ENSURE_REF(Yc_in);
     305                 :            : 
     306                 :        804 :     uint8_t client_public_len = 0;
     307                 :        804 :     struct s2n_blob client_public_blob = { 0 };
     308                 :            : 
     309                 :        804 :     DEFER_CLEANUP(EVP_PKEY *peer_key = EVP_PKEY_new(), EVP_PKEY_free_pointer);
     310 [ -  + ][ #  # ]:        804 :     S2N_ERROR_IF(peer_key == NULL, S2N_ERR_BAD_MESSAGE);
     311         [ -  + ]:        804 :     POSIX_GUARD(s2n_stuffer_read_uint8(Yc_in, &client_public_len));
     312                 :        804 :     client_public_blob.size = client_public_len;
     313                 :        804 :     client_public_blob.data = s2n_stuffer_raw_read(Yc_in, client_public_blob.size);
     314 [ -  + ][ #  # ]:        804 :     POSIX_ENSURE_REF(client_public_blob.data);
     315                 :            : 
     316                 :        804 : #if EVP_APIS_SUPPORTED
     317         [ +  + ]:        804 :     if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
     318         [ -  + ]:        361 :         POSIX_GUARD(EVP_PKEY_set_type(peer_key, ecc_evp_params->negotiated_curve->libcrypto_nid));
     319                 :        443 :     } else {
     320                 :        443 :         DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
     321 [ -  + ][ #  # ]:        443 :         S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
     322 [ -  + ][ #  # ]:        443 :         POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
     323 [ -  + ][ #  # ]:        443 :         POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
     324 [ #  # ][ -  + ]:        443 :         POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &peer_key), S2N_ERR_ECDHE_SERIALIZING);
     325                 :        443 :     }
     326 [ -  + ][ #  # ]:        804 :     POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(peer_key, client_public_blob.data, client_public_blob.size),
     327                 :        804 :             S2N_ERR_ECDHE_SERIALIZING);
     328                 :            : #else
     329                 :            :     DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
     330                 :            :             EC_KEY_free_pointer);
     331                 :            :     S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     332                 :            : 
     333                 :            :     DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(&client_public_blob, ec_key), EC_POINT_free_pointer);
     334                 :            :     S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
     335                 :            : 
     336                 :            :     int success = EC_KEY_set_public_key(ec_key, point);
     337                 :            :     POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(peer_key, ec_key), S2N_ERR_ECDHE_SERIALIZING);
     338                 :            :     S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
     339                 :            : #endif
     340                 :            : 
     341                 :        804 :     return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key,
     342                 :        804 :             ecc_evp_params->negotiated_curve->iana_id, shared_key);
     343                 :        804 : }
     344                 :            : 
     345                 :            : int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_evp_params,
     346                 :            :         struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key)
     347                 :        774 : {
     348                 :        774 :     DEFER_CLEANUP(struct s2n_ecc_evp_params client_params = { 0 }, s2n_ecc_evp_params_free);
     349                 :            : 
     350 [ -  + ][ #  # ]:        774 :     POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
     351                 :        774 :     client_params.negotiated_curve = ecc_evp_params->negotiated_curve;
     352         [ -  + ]:        774 :     POSIX_GUARD(s2n_ecc_evp_generate_own_key(client_params.negotiated_curve, &client_params.evp_pkey));
     353 [ -  + ][ #  # ]:        774 :     S2N_ERROR_IF(client_params.evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
     354                 :            : 
     355         [ -  + ]:        774 :     if (s2n_ecc_evp_compute_shared_secret(client_params.evp_pkey, ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->iana_id, shared_key)
     356                 :        774 :             != S2N_SUCCESS) {
     357         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
     358                 :          0 :     }
     359                 :            : 
     360         [ -  + ]:        774 :     POSIX_GUARD(s2n_stuffer_write_uint8(Yc_out, client_params.negotiated_curve->share_size));
     361                 :            : 
     362         [ -  + ]:        774 :     if (s2n_ecc_evp_write_params_point(&client_params, Yc_out) != 0) {
     363         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_ECDHE_SERIALIZING);
     364                 :          0 :     }
     365                 :        774 :     return 0;
     366                 :        774 : }
     367                 :            : 
     368                 :            : #if (!EVP_APIS_SUPPORTED)
     369                 :            : static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length)
     370                 :            : {
     371                 :            :     size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
     372                 :            :     S2N_ERROR_IF(ret == 0, S2N_ERR_ECDHE_SERIALIZING);
     373                 :            :     S2N_ERROR_IF(ret > UINT8_MAX, S2N_ERR_ECDHE_SERIALIZING);
     374                 :            :     *length = (uint8_t) ret;
     375                 :            :     return 0;
     376                 :            : }
     377                 :            : 
     378                 :            : static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out)
     379                 :            : {
     380                 :            :     size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, out->data, out->size, NULL);
     381                 :            :     S2N_ERROR_IF(ret != out->size, S2N_ERR_ECDHE_SERIALIZING);
     382                 :            :     return 0;
     383                 :            : }
     384                 :            : 
     385                 :            : static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key)
     386                 :            : {
     387                 :            :     const EC_GROUP *group = EC_KEY_get0_group(ec_key);
     388                 :            :     EC_POINT *point = EC_POINT_new(group);
     389                 :            :     if (point == NULL) {
     390                 :            :         PTR_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     391                 :            :     }
     392                 :            :     if (EC_POINT_oct2point(group, point, blob->data, blob->size, NULL) != 1) {
     393                 :            :         EC_POINT_free(point);
     394                 :            :         PTR_BAIL(S2N_ERR_BAD_MESSAGE);
     395                 :            :     }
     396                 :            :     return point;
     397                 :            : }
     398                 :            : #endif
     399                 :            : 
     400                 :            : int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob)
     401                 :      10331 : {
     402 [ -  + ][ #  # ]:      10331 :     POSIX_ENSURE_REF(in);
     403 [ -  + ][ #  # ]:      10331 :     POSIX_ENSURE_REF(point_blob);
     404 [ #  # ][ -  + ]:      10331 :     POSIX_ENSURE_GTE(point_size, 0);
     405                 :            : 
     406                 :            :     /* Extract point from stuffer */
     407                 :      10331 :     point_blob->size = point_size;
     408                 :      10331 :     point_blob->data = s2n_stuffer_raw_read(in, point_size);
     409 [ -  + ][ #  # ]:      10331 :     POSIX_ENSURE_REF(point_blob->data);
     410                 :            : 
     411                 :      10331 :     return 0;
     412                 :      10331 : }
     413                 :            : 
     414                 :            : int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify,
     415                 :            :         struct s2n_ecdhe_raw_server_params *raw_server_ecc_params)
     416                 :        810 : {
     417 [ -  + ][ #  # ]:        810 :     POSIX_ENSURE_REF(in);
     418                 :        810 :     uint8_t curve_type = 0;
     419                 :        810 :     uint8_t point_length = 0;
     420                 :            : 
     421                 :            :     /* Remember where we started reading the data */
     422                 :        810 :     data_to_verify->data = s2n_stuffer_raw_read(in, 0);
     423 [ -  + ][ #  # ]:        810 :     POSIX_ENSURE_REF(data_to_verify->data);
     424                 :            : 
     425                 :            :     /* Read the curve */
     426         [ -  + ]:        810 :     POSIX_GUARD(s2n_stuffer_read_uint8(in, &curve_type));
     427 [ -  + ][ #  # ]:        810 :     S2N_ERROR_IF(curve_type != TLS_EC_CURVE_TYPE_NAMED, S2N_ERR_BAD_MESSAGE);
     428                 :        810 :     raw_server_ecc_params->curve_blob.data = s2n_stuffer_raw_read(in, 2);
     429 [ #  # ][ -  + ]:        810 :     POSIX_ENSURE_REF(raw_server_ecc_params->curve_blob.data);
     430                 :        810 :     raw_server_ecc_params->curve_blob.size = 2;
     431                 :            : 
     432                 :            :     /* Read the point */
     433         [ -  + ]:        810 :     POSIX_GUARD(s2n_stuffer_read_uint8(in, &point_length));
     434                 :            : 
     435         [ -  + ]:        810 :     POSIX_GUARD(s2n_ecc_evp_read_params_point(in, point_length, &raw_server_ecc_params->point_blob));
     436                 :            : 
     437                 :            :     /* curve type (1) + iana (2) + key share size (1) + key share */
     438                 :        810 :     data_to_verify->size = point_length + 4;
     439                 :            : 
     440                 :        810 :     return 0;
     441                 :        810 : }
     442                 :            : 
     443                 :            : int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out)
     444                 :      12283 : {
     445 [ #  # ][ -  + ]:      12283 :     POSIX_ENSURE_REF(ecc_evp_params);
     446 [ -  + ][ #  # ]:      12283 :     POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
     447 [ -  + ][ #  # ]:      12283 :     POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
     448 [ #  # ][ -  + ]:      12283 :     POSIX_ENSURE_REF(out);
     449                 :            : 
     450                 :      12283 : #if EVP_APIS_SUPPORTED
     451                 :      12283 :     DEFER_CLEANUP(uint8_t *encoded_point = NULL, OPENSSL_free_pointer);
     452                 :            : 
     453                 :      12283 :     size_t size = EVP_PKEY_get1_tls_encodedpoint(ecc_evp_params->evp_pkey, &encoded_point);
     454 [ +  - ][ +  + ]:      12283 :     POSIX_ENSURE(size == ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
     455         [ +  + ]:      12282 :     POSIX_GUARD(s2n_stuffer_write_bytes(out, encoded_point, size));
     456                 :            : #else
     457                 :            :     uint8_t point_len = 0;
     458                 :            :     struct s2n_blob point_blob = { 0 };
     459                 :            : 
     460                 :            :     DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(ecc_evp_params->evp_pkey), EC_KEY_free_pointer);
     461                 :            :     S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     462                 :            :     const EC_POINT *point = EC_KEY_get0_public_key(ec_key);
     463                 :            :     const EC_GROUP *group = EC_KEY_get0_group(ec_key);
     464                 :            :     S2N_ERROR_IF(point == NULL || group == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     465                 :            : 
     466                 :            :     POSIX_GUARD(s2n_ecc_evp_calculate_point_length(point, group, &point_len));
     467                 :            :     S2N_ERROR_IF(point_len != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
     468                 :            :     point_blob.data = s2n_stuffer_raw_write(out, point_len);
     469                 :            :     POSIX_ENSURE_REF(point_blob.data);
     470                 :            :     point_blob.size = point_len;
     471                 :            : 
     472                 :            :     POSIX_GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob));
     473                 :            : #endif
     474                 :      12278 :     return 0;
     475                 :      12282 : }
     476                 :            : 
     477                 :            : int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out,
     478                 :            :         struct s2n_blob *written)
     479                 :        878 : {
     480 [ -  + ][ #  # ]:        878 :     POSIX_ENSURE_REF(ecc_evp_params);
     481 [ #  # ][ -  + ]:        878 :     POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
     482 [ -  + ][ #  # ]:        878 :     POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
     483 [ #  # ][ -  + ]:        878 :     POSIX_ENSURE_REF(out);
     484 [ -  + ][ #  # ]:        878 :     POSIX_ENSURE_REF(written);
     485                 :            : 
     486                 :        878 :     uint8_t key_share_size = ecc_evp_params->negotiated_curve->share_size;
     487                 :        878 :     uint32_t key_share_offset = out->write_cursor;
     488                 :            : 
     489         [ -  + ]:        878 :     POSIX_GUARD(s2n_stuffer_write_uint8(out, TLS_EC_CURVE_TYPE_NAMED));
     490         [ -  + ]:        878 :     POSIX_GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id));
     491         [ -  + ]:        878 :     POSIX_GUARD(s2n_stuffer_write_uint8(out, key_share_size));
     492                 :            : 
     493         [ -  + ]:        878 :     POSIX_GUARD(s2n_ecc_evp_write_params_point(ecc_evp_params, out));
     494                 :            : 
     495                 :            :     /* key share + key share size (1) + iana (2) + curve type (1) */
     496                 :        878 :     written->size = key_share_size + 4;
     497                 :        878 :     written->data = out->blob.data + key_share_offset;
     498                 :            : 
     499                 :        878 :     return written->size;
     500                 :        878 : }
     501                 :            : 
     502                 :            : int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params)
     503                 :      10325 : {
     504 [ -  + ][ #  # ]:      10325 :     POSIX_ENSURE_REF(point_blob->data);
     505 [ #  # ][ -  + ]:      10325 :     POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
     506 [ -  + ][ #  # ]:      10325 :     S2N_ERROR_IF(point_blob->size != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
     507                 :            : 
     508                 :      10325 : #if EVP_APIS_SUPPORTED
     509         [ +  + ]:      10325 :     if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
     510         [ +  - ]:        818 :         if (ecc_evp_params->evp_pkey == NULL) {
     511                 :        818 :             ecc_evp_params->evp_pkey = EVP_PKEY_new();
     512                 :        818 :         }
     513 [ -  + ][ #  # ]:        818 :         S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
     514         [ -  + ]:        818 :         POSIX_GUARD(EVP_PKEY_set_type(ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->libcrypto_nid));
     515                 :       9507 :     } else {
     516                 :       9507 :         DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
     517 [ -  + ][ #  # ]:       9507 :         S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
     518 [ -  + ][ #  # ]:       9507 :         POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
     519 [ #  # ][ -  + ]:       9507 :         POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
     520 [ -  + ][ #  # ]:       9507 :         POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey), S2N_ERR_ECDHE_SERIALIZING);
     521                 :       9507 :     }
     522 [ +  + ][ +  - ]:      10325 :     POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(ecc_evp_params->evp_pkey, point_blob->data, point_blob->size),
     523                 :      10323 :             S2N_ERR_ECDHE_SERIALIZING);
     524                 :            : #else
     525                 :            :     if (ecc_evp_params->evp_pkey == NULL) {
     526                 :            :         ecc_evp_params->evp_pkey = EVP_PKEY_new();
     527                 :            :     }
     528                 :            :     S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
     529                 :            :     /* Create a key to store the point */
     530                 :            :     DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
     531                 :            :             EC_KEY_free_pointer);
     532                 :            :     S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     533                 :            : 
     534                 :            :     /* Parse and store the server public point */
     535                 :            :     DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(point_blob, ec_key), EC_POINT_free_pointer);
     536                 :            :     S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
     537                 :            : 
     538                 :            :     /* Set the point as the public key */
     539                 :            :     int success = EC_KEY_set_public_key(ec_key, point);
     540                 :            : 
     541                 :            :     POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(ecc_evp_params->evp_pkey, ec_key), S2N_ERR_ECDHE_SERIALIZING);
     542                 :            : 
     543                 :            :     /* EC_KEY_set_public_key returns 1 on success, 0 on failure */
     544                 :            :     S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
     545                 :            : 
     546                 :            : #endif
     547                 :      10323 :     return 0;
     548                 :      10325 : }
     549                 :            : 
     550                 :            : int s2n_ecc_evp_parse_params(struct s2n_connection *conn, struct s2n_ecdhe_raw_server_params *raw_server_ecc_params,
     551                 :            :         struct s2n_ecc_evp_params *ecc_evp_params)
     552                 :        810 : {
     553 [ +  + ][ +  - ]:        810 :     POSIX_ENSURE(s2n_ecc_evp_find_supported_curve(conn, &raw_server_ecc_params->curve_blob, &ecc_evp_params->negotiated_curve) == 0,
     554                 :        808 :             S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     555                 :        808 :     return s2n_ecc_evp_parse_params_point(&raw_server_ecc_params->point_blob, ecc_evp_params);
     556                 :        810 : }
     557                 :            : 
     558                 :            : int s2n_ecc_evp_find_supported_curve(struct s2n_connection *conn, struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found)
     559                 :        810 : {
     560                 :        810 :     const struct s2n_ecc_preferences *ecc_prefs = NULL;
     561         [ -  + ]:        810 :     POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_prefs));
     562 [ -  + ][ #  # ]:        810 :     POSIX_ENSURE_REF(ecc_prefs);
     563                 :            : 
     564                 :        810 :     struct s2n_stuffer iana_ids_in = { 0 };
     565                 :            : 
     566         [ -  + ]:        810 :     POSIX_GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids));
     567         [ -  + ]:        810 :     POSIX_GUARD(s2n_stuffer_write(&iana_ids_in, iana_ids));
     568         [ +  + ]:        841 :     for (size_t i = 0; i < ecc_prefs->count; i++) {
     569                 :        839 :         const struct s2n_ecc_named_curve *supported_curve = ecc_prefs->ecc_curves[i];
     570         [ +  + ]:        870 :         for (uint32_t j = 0; j < iana_ids->size / 2; j++) {
     571                 :        839 :             uint16_t iana_id = 0;
     572         [ -  + ]:        839 :             POSIX_GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id));
     573         [ +  + ]:        839 :             if (supported_curve->iana_id == iana_id) {
     574                 :        808 :                 *found = supported_curve;
     575                 :        808 :                 return 0;
     576                 :        808 :             }
     577                 :        839 :         }
     578         [ -  + ]:         31 :         POSIX_GUARD(s2n_stuffer_reread(&iana_ids_in));
     579                 :         31 :     }
     580                 :            : 
     581         [ +  - ]:          2 :     POSIX_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
     582                 :          2 : }
     583                 :            : 
     584                 :            : int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params)
     585                 :   14250105 : {
     586         [ +  + ]:   14250105 :     if (ecc_evp_params->evp_pkey != NULL) {
     587                 :      24441 :         EVP_PKEY_free(ecc_evp_params->evp_pkey);
     588                 :      24441 :         ecc_evp_params->evp_pkey = NULL;
     589                 :      24441 :     }
     590                 :   14250105 :     return 0;
     591                 :   14250105 : }

Generated by: LCOV version 1.14