LCOV - code coverage report
Current view: top level - crypto - s2n_pkey.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 146 165 88.5 %
Date: 2025-08-15 07:28:39 Functions: 15 15 100.0 %
Branches: 75 170 44.1 %

           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_pkey.h"
      17                 :            : 
      18                 :            : #include <openssl/evp.h>
      19                 :            : 
      20                 :            : #include "crypto/s2n_mldsa.h"
      21                 :            : #include "crypto/s2n_openssl_evp.h"
      22                 :            : #include "crypto/s2n_openssl_x509.h"
      23                 :            : #include "crypto/s2n_pkey_evp.h"
      24                 :            : #include "crypto/s2n_rsa_pss.h"
      25                 :            : #include "error/s2n_errno.h"
      26                 :            : #include "utils/s2n_mem.h"
      27                 :            : #include "utils/s2n_result.h"
      28                 :            : #include "utils/s2n_safety.h"
      29                 :            : 
      30                 :            : #ifndef EVP_PKEY_RSA_PSS
      31                 :            :     #define EVP_PKEY_RSA_PSS EVP_PKEY_NONE
      32                 :            : #endif
      33                 :            : 
      34                 :            : int s2n_pkey_zero_init(struct s2n_pkey *pkey)
      35                 :    7096734 : {
      36                 :    7096734 :     pkey->pkey = NULL;
      37                 :    7096734 :     pkey->size = NULL;
      38                 :    7096734 :     pkey->sign = NULL;
      39                 :    7096734 :     pkey->verify = NULL;
      40                 :    7096734 :     pkey->encrypt = NULL;
      41                 :    7096734 :     pkey->decrypt = NULL;
      42                 :    7096734 :     return 0;
      43                 :    7096734 : }
      44                 :            : 
      45                 :            : S2N_RESULT s2n_pkey_setup_for_type(struct s2n_pkey *pkey, s2n_pkey_type pkey_type)
      46                 :      10786 : {
      47         [ -  + ]:      10786 :     switch (pkey_type) {
      48         [ +  + ]:       8648 :         case S2N_PKEY_TYPE_RSA:
      49         [ +  + ]:      10639 :         case S2N_PKEY_TYPE_ECDSA:
      50         [ +  + ]:      10786 :         case S2N_PKEY_TYPE_RSA_PSS:
      51         [ -  + ]:      10786 :         case S2N_PKEY_TYPE_MLDSA:
      52                 :      10786 :             return s2n_pkey_evp_init(pkey);
      53         [ -  + ]:          0 :         case S2N_PKEY_TYPE_SENTINEL:
      54         [ -  + ]:          0 :         case S2N_PKEY_TYPE_UNKNOWN:
      55         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
      56                 :      10786 :     }
      57         [ #  # ]:          0 :     RESULT_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
      58                 :          0 : }
      59                 :            : 
      60                 :            : int s2n_pkey_check_key_exists(const struct s2n_pkey *pkey)
      61                 :       1665 : {
      62 [ #  # ][ -  + ]:       1665 :     POSIX_ENSURE_REF(pkey);
      63 [ +  + ][ +  - ]:       1665 :     POSIX_ENSURE_REF(pkey->pkey);
      64                 :       1577 :     return S2N_SUCCESS;
      65                 :       1665 : }
      66                 :            : 
      67                 :            : S2N_RESULT s2n_pkey_size(const struct s2n_pkey *pkey, uint32_t *size_out)
      68                 :       7562 : {
      69 [ -  + ][ #  # ]:       7562 :     RESULT_ENSURE_REF(pkey);
      70 [ -  + ][ #  # ]:       7562 :     RESULT_ENSURE_REF(pkey->size);
      71 [ -  + ][ #  # ]:       7562 :     RESULT_ENSURE_REF(size_out);
      72                 :            : 
      73         [ -  + ]:       7562 :     RESULT_GUARD(pkey->size(pkey, size_out));
      74                 :            : 
      75                 :       7562 :     return S2N_RESULT_OK;
      76                 :       7562 : }
      77                 :            : 
      78                 :            : int s2n_pkey_sign(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg,
      79                 :            :         struct s2n_hash_state *digest, struct s2n_blob *signature)
      80                 :       4415 : {
      81 [ #  # ][ -  + ]:       4415 :     POSIX_ENSURE_REF(pkey->sign);
      82                 :            : 
      83                 :       4415 :     return pkey->sign(pkey, sig_alg, digest, signature);
      84                 :       4415 : }
      85                 :            : 
      86                 :            : int s2n_pkey_verify(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg,
      87                 :            :         struct s2n_hash_state *digest, struct s2n_blob *signature)
      88                 :       3630 : {
      89 [ -  + ][ #  # ]:       3630 :     POSIX_ENSURE_REF(pkey);
      90 [ -  + ][ #  # ]:       3630 :     POSIX_ENSURE_REF(pkey->verify);
      91                 :            : 
      92                 :       3630 :     return pkey->verify(pkey, sig_alg, digest, signature);
      93                 :       3630 : }
      94                 :            : 
      95                 :            : int s2n_pkey_encrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out)
      96                 :        247 : {
      97 [ -  + ][ #  # ]:        247 :     POSIX_ENSURE_REF(pkey->encrypt);
      98                 :            : 
      99                 :        247 :     return pkey->encrypt(pkey, in, out);
     100                 :        247 : }
     101                 :            : 
     102                 :            : int s2n_pkey_decrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out)
     103                 :       1709 : {
     104 [ -  + ][ #  # ]:       1709 :     POSIX_ENSURE_REF(pkey->decrypt);
     105                 :            : 
     106                 :       1709 :     return pkey->decrypt(pkey, in, out);
     107                 :       1709 : }
     108                 :            : 
     109                 :            : int s2n_pkey_match(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key)
     110                 :        585 : {
     111 [ -  + ][ #  # ]:        585 :     POSIX_ENSURE_REF(pub_key);
     112                 :            : 
     113                 :            :     /* Minimally, both keys must be of the same type */
     114                 :        585 :     s2n_pkey_type priv_type = 0, pub_type = 0;
     115         [ -  + ]:        585 :     POSIX_GUARD_RESULT(s2n_pkey_get_type(priv_key->pkey, &priv_type));
     116         [ -  + ]:        585 :     POSIX_GUARD_RESULT(s2n_pkey_get_type(pub_key->pkey, &pub_type));
     117 [ +  - ][ +  + ]:        585 :     POSIX_ENSURE(priv_type == pub_type, S2N_ERR_KEY_MISMATCH);
     118                 :            : 
     119                 :            :     /* If both keys are of the same type, check that the public key
     120                 :            :      * can verify a test signature from the private key.
     121                 :            :      */
     122                 :            : 
     123                 :        561 :     uint8_t input[] = "key check";
     124                 :        561 :     DEFER_CLEANUP(struct s2n_blob signature = { 0 }, s2n_free);
     125                 :            : 
     126                 :            :     /* Choose one signature algorithm to test each type of pkey.
     127                 :            :      * For example, RSA certs can be used for either S2N_SIGNATURE_RSA (PKCS1)
     128                 :            :      * or S2N_SIGNATURE_RSA_PSS_RSAE, but we only test with S2N_SIGNATURE_RSA.
     129                 :            :      */
     130                 :        561 :     s2n_signature_algorithm check_alg = S2N_SIGNATURE_ANONYMOUS;
     131                 :        561 :     s2n_hash_algorithm hash_alg = S2N_HASH_SHA256;
     132                 :        561 :     switch (priv_type) {
     133         [ +  + ]:        167 :         case S2N_PKEY_TYPE_ECDSA:
     134                 :        167 :             check_alg = S2N_SIGNATURE_ECDSA;
     135                 :        167 :             break;
     136         [ +  + ]:        364 :         case S2N_PKEY_TYPE_RSA:
     137                 :        364 :             check_alg = S2N_SIGNATURE_RSA;
     138                 :        364 :             break;
     139         [ +  + ]:         30 :         case S2N_PKEY_TYPE_RSA_PSS:
     140                 :         30 :             check_alg = S2N_SIGNATURE_RSA_PSS_PSS;
     141                 :         30 :             break;
     142         [ -  + ]:          0 :         case S2N_PKEY_TYPE_MLDSA:
     143                 :          0 :             check_alg = S2N_SIGNATURE_MLDSA;
     144                 :          0 :             hash_alg = S2N_HASH_SHAKE256_64;
     145                 :          0 :             break;
     146         [ -  + ]:          0 :         default:
     147         [ #  # ]:          0 :             POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
     148                 :        561 :     }
     149                 :            : 
     150                 :        561 :     DEFER_CLEANUP(struct s2n_hash_state state_in = { 0 }, s2n_hash_free);
     151         [ -  + ]:        561 :     POSIX_GUARD(s2n_hash_new(&state_in));
     152         [ -  + ]:        561 :     POSIX_GUARD(s2n_hash_init(&state_in, hash_alg));
     153         [ -  + ]:        561 :     POSIX_GUARD_RESULT(s2n_pkey_init_hash(pub_key, check_alg, &state_in));
     154         [ -  + ]:        561 :     POSIX_GUARD(s2n_hash_update(&state_in, input, sizeof(input)));
     155                 :            : 
     156                 :        561 :     DEFER_CLEANUP(struct s2n_hash_state state_out = { 0 }, s2n_hash_free);
     157         [ -  + ]:        561 :     POSIX_GUARD(s2n_hash_new(&state_out));
     158         [ -  + ]:        561 :     POSIX_GUARD(s2n_hash_copy(&state_out, &state_in));
     159                 :            : 
     160                 :        561 :     uint32_t size = 0;
     161         [ -  + ]:        561 :     POSIX_GUARD_RESULT(s2n_pkey_size(priv_key, &size));
     162         [ -  + ]:        561 :     POSIX_GUARD(s2n_alloc(&signature, size));
     163                 :            : 
     164                 :            :     /* Note: The Libcrypto RSA EVP_PKEY will cache certain computations used for
     165                 :            :      * RSA signing.
     166                 :            :      * 
     167                 :            :      * This means that the first RSA sign with an EVP_PKEY is ~300 us slower
     168                 :            :      * than subsequent sign operations. The effect is much smaller for ECDSA signatures.
     169                 :            :      * 
     170                 :            :      * If this pkey_sign operation is moved out of config creation, then the
     171                 :            :      * 300 us penalty will be paid by the first handshake done on the config.
     172                 :            :      */
     173         [ -  + ]:        561 :     POSIX_GUARD(s2n_pkey_sign(priv_key, check_alg, &state_in, &signature));
     174 [ +  + ][ +  - ]:        561 :     POSIX_ENSURE(s2n_pkey_verify(pub_key, check_alg, &state_out, &signature) == S2N_SUCCESS,
     175                 :        553 :             S2N_ERR_KEY_MISMATCH);
     176                 :            : 
     177                 :        553 :     return S2N_SUCCESS;
     178                 :        561 : }
     179                 :            : 
     180                 :            : int s2n_pkey_free(struct s2n_pkey *key)
     181                 :    7099852 : {
     182         [ -  + ]:    7099852 :     if (key == NULL) {
     183                 :          0 :         return S2N_SUCCESS;
     184                 :          0 :     }
     185         [ +  + ]:    7099852 :     if (key->pkey != NULL) {
     186                 :       5750 :         EVP_PKEY_free(key->pkey);
     187                 :       5750 :         key->pkey = NULL;
     188                 :       5750 :     }
     189                 :    7099852 :     return S2N_SUCCESS;
     190                 :    7099852 : }
     191                 :            : 
     192                 :            : S2N_RESULT s2n_asn1der_to_private_key(struct s2n_pkey *priv_key, struct s2n_blob *asn1der, int type_hint)
     193                 :        551 : {
     194                 :        551 :     const unsigned char *key_to_parse = asn1der->data;
     195                 :            : 
     196                 :            :     /* We use "d2i_AutoPrivateKey" instead of "PEM_read_bio_PrivateKey" because
     197                 :            :      * s2n-tls prefers to perform its own custom PEM parsing. Historically,
     198                 :            :      * openssl's PEM parsing tended to ignore invalid certificates rather than
     199                 :            :      * error on them. We prefer to fail early rather than continue without
     200                 :            :      * the full and correct chain intended by the application.
     201                 :            :      */
     202                 :        551 :     DEFER_CLEANUP(EVP_PKEY *evp_private_key = d2i_AutoPrivateKey(NULL, &key_to_parse, asn1der->size),
     203                 :        551 :             EVP_PKEY_free_pointer);
     204                 :            : 
     205                 :            :     /* We have found cases where d2i_AutoPrivateKey fails to detect the type of
     206                 :            :      * the key. For example, openssl fails to identify an EC key without the
     207                 :            :      * optional publicKey field.
     208                 :            :      *
     209                 :            :      * If d2i_AutoPrivateKey fails, try once more with the type we parsed from the PEM.
     210                 :            :      */
     211         [ -  + ]:        551 :     if (evp_private_key == NULL) {
     212                 :          0 :         evp_private_key = d2i_PrivateKey(type_hint, NULL, &key_to_parse, asn1der->size);
     213                 :          0 :     }
     214 [ -  + ][ #  # ]:        551 :     RESULT_ENSURE(evp_private_key, S2N_ERR_DECODE_PRIVATE_KEY);
     215                 :            : 
     216                 :            :     /* If key parsing is successful, d2i_AutoPrivateKey increments *key_to_parse to the byte following the parsed data */
     217                 :        551 :     uint32_t parsed_len = key_to_parse - asn1der->data;
     218 [ -  + ][ #  # ]:        551 :     RESULT_ENSURE(parsed_len == asn1der->size, S2N_ERR_DECODE_PRIVATE_KEY);
     219                 :            : 
     220                 :            :     /* Initialize s2n_pkey according to key type */
     221                 :        551 :     s2n_pkey_type type = 0;
     222         [ -  + ]:        551 :     RESULT_GUARD(s2n_pkey_get_type(evp_private_key, &type));
     223         [ -  + ]:        551 :     RESULT_GUARD(s2n_pkey_setup_for_type(priv_key, type));
     224                 :            : 
     225                 :        551 :     priv_key->pkey = evp_private_key;
     226                 :        551 :     ZERO_TO_DISABLE_DEFER_CLEANUP(evp_private_key);
     227                 :            : 
     228                 :        551 :     return S2N_RESULT_OK;
     229                 :        551 : }
     230                 :            : 
     231                 :            : S2N_RESULT s2n_asn1der_to_public_key_and_type(struct s2n_pkey *pub_key,
     232                 :            :         s2n_pkey_type *pkey_type_out, struct s2n_blob *asn1der)
     233                 :        115 : {
     234                 :        115 :     DEFER_CLEANUP(X509 *cert = NULL, X509_free_pointer);
     235         [ -  + ]:        115 :     RESULT_GUARD(s2n_openssl_x509_parse(asn1der, &cert));
     236         [ -  + ]:        115 :     RESULT_GUARD(s2n_pkey_from_x509(cert, pub_key, pkey_type_out));
     237                 :            : 
     238                 :        115 :     return S2N_RESULT_OK;
     239                 :        115 : }
     240                 :            : 
     241                 :            : S2N_RESULT s2n_pkey_get_type(EVP_PKEY *evp_pkey, s2n_pkey_type *pkey_type)
     242                 :      12522 : {
     243 [ -  + ][ #  # ]:      12522 :     RESULT_ENSURE_REF(evp_pkey);
     244 [ -  + ][ #  # ]:      12522 :     RESULT_ENSURE_REF(pkey_type);
     245                 :      12522 :     *pkey_type = S2N_PKEY_TYPE_UNKNOWN;
     246                 :            : 
     247                 :      12522 :     int type = EVP_PKEY_base_id(evp_pkey);
     248                 :      12522 :     switch (type) {
     249         [ +  + ]:       9865 :         case EVP_PKEY_RSA:
     250                 :       9865 :             *pkey_type = S2N_PKEY_TYPE_RSA;
     251                 :       9865 :             break;
     252         [ +  + ]:        263 :         case EVP_PKEY_RSA_PSS:
     253                 :        263 :             *pkey_type = S2N_PKEY_TYPE_RSA_PSS;
     254                 :        263 :             break;
     255         [ +  + ]:       2394 :         case EVP_PKEY_EC:
     256                 :       2394 :             *pkey_type = S2N_PKEY_TYPE_ECDSA;
     257                 :       2394 :             break;
     258                 :            : #if S2N_LIBCRYPTO_SUPPORTS_MLDSA
     259                 :            :         case EVP_PKEY_PQDSA:
     260                 :            :             *pkey_type = S2N_PKEY_TYPE_MLDSA;
     261                 :            :             break;
     262                 :            : #endif
     263         [ -  + ]:          0 :         default:
     264         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_DECODE_CERTIFICATE);
     265                 :      12522 :     }
     266                 :            : 
     267                 :      12522 :     return S2N_RESULT_OK;
     268                 :      12522 : }
     269                 :            : 
     270                 :            : S2N_RESULT s2n_pkey_from_x509(X509 *cert, struct s2n_pkey *pub_key_out,
     271                 :            :         s2n_pkey_type *pkey_type_out)
     272                 :       5199 : {
     273 [ #  # ][ -  + ]:       5199 :     RESULT_ENSURE_REF(cert);
     274 [ -  + ][ #  # ]:       5199 :     RESULT_ENSURE_REF(pub_key_out);
     275 [ #  # ][ -  + ]:       5199 :     RESULT_ENSURE_REF(pkey_type_out);
     276                 :            : 
     277                 :       5199 :     DEFER_CLEANUP(EVP_PKEY *evp_public_key = X509_get_pubkey(cert), EVP_PKEY_free_pointer);
     278 [ -  + ][ #  # ]:       5199 :     RESULT_ENSURE(evp_public_key != NULL, S2N_ERR_DECODE_CERTIFICATE);
     279                 :            : 
     280         [ -  + ]:       5199 :     RESULT_GUARD(s2n_pkey_get_type(evp_public_key, pkey_type_out));
     281         [ -  + ]:       5199 :     RESULT_GUARD(s2n_pkey_setup_for_type(pub_key_out, *pkey_type_out));
     282                 :            : 
     283                 :       5199 :     pub_key_out->pkey = evp_public_key;
     284                 :       5199 :     ZERO_TO_DISABLE_DEFER_CLEANUP(evp_public_key);
     285                 :            : 
     286                 :       5199 :     return S2N_RESULT_OK;
     287                 :       5199 : }
     288                 :            : 
     289                 :            : S2N_RESULT s2n_pkey_init_hash(const struct s2n_pkey *pkey,
     290                 :            :         s2n_signature_algorithm sig_alg, struct s2n_hash_state *hash)
     291                 :       5603 : {
     292         [ -  + ]:       5603 :     if (sig_alg == S2N_SIGNATURE_MLDSA) {
     293         [ #  # ]:          0 :         RESULT_GUARD(s2n_mldsa_init_mu_hash(hash, pkey));
     294                 :          0 :     }
     295                 :       5603 :     return S2N_RESULT_OK;
     296                 :       5603 : }

Generated by: LCOV version 1.14