LCOV - code coverage report
Current view: top level - crypto - s2n_certificate.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 518 587 88.2 %
Date: 2026-10-06 07:26:09 Functions: 39 42 92.9 %
Branches: 335 700 47.9 %

           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                 :            : #ifndef _GNU_SOURCE
      17                 :            :     #define _GNU_SOURCE
      18                 :            : #endif
      19                 :            : 
      20                 :            : #include "crypto/s2n_certificate.h"
      21                 :            : 
      22                 :            : #include <openssl/pem.h>
      23                 :            : #include <openssl/x509v3.h>
      24                 :            : #include <string.h>
      25                 :            : #include <strings.h>
      26                 :            : 
      27                 :            : #include "api/s2n.h"
      28                 :            : #include "crypto/s2n_mldsa.h"
      29                 :            : #include "crypto/s2n_openssl_x509.h"
      30                 :            : #include "tls/extensions/s2n_extension_list.h"
      31                 :            : #include "tls/s2n_connection.h"
      32                 :            : #include "utils/s2n_array.h"
      33                 :            : #include "utils/s2n_mem.h"
      34                 :            : #include "utils/s2n_safety.h"
      35                 :            : 
      36                 :            : int s2n_cert_set_cert_type(struct s2n_cert *cert, s2n_pkey_type pkey_type)
      37                 :        841 : {
      38 [ -  + ][ #  # ]:        841 :     POSIX_ENSURE_REF(cert);
      39                 :        841 :     cert->pkey_type = pkey_type;
      40         [ -  + ]:        841 :     POSIX_GUARD_RESULT(s2n_pkey_setup_for_type(&cert->public_key, pkey_type));
      41                 :        841 :     return 0;
      42                 :        841 : }
      43                 :            : 
      44                 :            : int s2n_create_cert_chain_from_stuffer(struct s2n_cert_chain *cert_chain_out, struct s2n_stuffer *chain_in_stuffer)
      45                 :        906 : {
      46                 :        906 :     DEFER_CLEANUP(struct s2n_stuffer cert_out_stuffer = { 0 }, s2n_stuffer_free);
      47         [ -  + ]:        906 :     POSIX_GUARD(s2n_stuffer_growable_alloc(&cert_out_stuffer, 2048));
      48                 :            : 
      49                 :        906 :     struct s2n_cert **insert = &cert_chain_out->head;
      50                 :        906 :     uint32_t chain_size = 0;
      51         [ +  + ]:       2928 :     while (s2n_stuffer_has_pem_encapsulated_block(chain_in_stuffer)) {
      52                 :       2053 :         int result = s2n_stuffer_certificate_from_pem(chain_in_stuffer, &cert_out_stuffer);
      53 [ +  - ][ +  + ]:       2053 :         POSIX_ENSURE(result == S2N_SUCCESS, S2N_ERR_INVALID_PEM);
      54                 :            : 
      55                 :       2024 :         DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
      56         [ -  + ]:       2024 :         POSIX_GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert)));
      57         [ -  + ]:       2024 :         POSIX_GUARD(s2n_blob_zero(&mem));
      58                 :            : 
      59                 :       2024 :         struct s2n_cert *new_node = (struct s2n_cert *) (void *) mem.data;
      60         [ -  + ]:       2024 :         POSIX_GUARD(s2n_alloc(&new_node->raw, s2n_stuffer_data_available(&cert_out_stuffer)));
      61         [ +  + ]:       2024 :         POSIX_GUARD(s2n_stuffer_read(&cert_out_stuffer, &new_node->raw));
      62                 :       2022 :         ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
      63                 :            : 
      64                 :            :         /* Additional 3 bytes for the length field in the protocol */
      65                 :       2022 :         chain_size += new_node->raw.size + 3;
      66                 :       2022 :         new_node->next = NULL;
      67                 :       2022 :         *insert = new_node;
      68                 :       2022 :         insert = &new_node->next;
      69                 :       2022 :     };
      70                 :            : 
      71 [ -  + ][ #  # ]:        875 :     POSIX_ENSURE(chain_size > 0, S2N_ERR_NO_CERTIFICATE_IN_PEM);
      72                 :        875 :     cert_chain_out->chain_size = chain_size;
      73                 :            : 
      74                 :        875 :     return S2N_SUCCESS;
      75                 :        875 : }
      76                 :            : 
      77                 :            : int s2n_cert_chain_and_key_set_cert_chain_from_stuffer(struct s2n_cert_chain_and_key *cert_and_key, struct s2n_stuffer *chain_in_stuffer)
      78                 :        847 : {
      79 [ -  + ][ #  # ]:        847 :     POSIX_ENSURE_REF(cert_and_key);
      80 [ -  + ][ #  # ]:        847 :     POSIX_ENSURE_REF(cert_and_key->cert_chain);
      81                 :        847 :     return s2n_create_cert_chain_from_stuffer(cert_and_key->cert_chain, chain_in_stuffer);
      82                 :        847 : }
      83                 :            : 
      84                 :            : int s2n_cert_chain_and_key_set_cert_chain_bytes(struct s2n_cert_chain_and_key *cert_and_key, uint8_t *cert_chain_pem, uint32_t cert_chain_len)
      85                 :         93 : {
      86                 :         93 :     DEFER_CLEANUP(struct s2n_stuffer chain_in_stuffer = { 0 }, s2n_stuffer_free);
      87                 :            : 
      88         [ -  + ]:         93 :     POSIX_GUARD(s2n_stuffer_init_ro_from_string(&chain_in_stuffer, cert_chain_pem, cert_chain_len));
      89         [ -  + ]:         93 :     POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_from_stuffer(cert_and_key, &chain_in_stuffer));
      90                 :            : 
      91                 :         93 :     return S2N_SUCCESS;
      92                 :         93 : }
      93                 :            : 
      94                 :            : int s2n_cert_chain_and_key_set_cert_chain(struct s2n_cert_chain_and_key *cert_and_key, const char *cert_chain_pem)
      95                 :        754 : {
      96                 :        754 :     DEFER_CLEANUP(struct s2n_stuffer chain_in_stuffer = { 0 }, s2n_stuffer_free);
      97                 :            : 
      98                 :            :     /* Turn the chain into a stuffer */
      99         [ -  + ]:        754 :     POSIX_GUARD(s2n_stuffer_alloc_ro_from_string(&chain_in_stuffer, cert_chain_pem));
     100         [ +  + ]:        754 :     POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_from_stuffer(cert_and_key, &chain_in_stuffer));
     101                 :            : 
     102                 :        751 :     return S2N_SUCCESS;
     103                 :        754 : }
     104                 :            : 
     105                 :            : int s2n_cert_chain_and_key_set_private_key_from_stuffer(struct s2n_cert_chain_and_key *cert_and_key,
     106                 :            :         struct s2n_stuffer *key_in_stuffer, struct s2n_stuffer *key_out_stuffer)
     107                 :        763 : {
     108 [ -  + ][ #  # ]:        763 :     POSIX_ENSURE_REF(cert_and_key);
     109 [ -  + ][ #  # ]:        763 :     POSIX_ENSURE_REF(cert_and_key->private_key);
     110                 :            : 
     111                 :        763 :     struct s2n_blob key_blob = { 0 };
     112                 :            : 
     113         [ -  + ]:        763 :     POSIX_GUARD(s2n_pkey_zero_init(cert_and_key->private_key));
     114                 :            : 
     115                 :            :     /* Convert pem to asn1 and asn1 to the private key. Handles both PKCS#1 and PKCS#8 formats */
     116                 :        763 :     int type_hint = 0;
     117         [ +  + ]:        763 :     POSIX_GUARD(s2n_stuffer_private_key_from_pem(key_in_stuffer, key_out_stuffer, &type_hint));
     118                 :        761 :     key_blob.size = s2n_stuffer_data_available(key_out_stuffer);
     119                 :        761 :     key_blob.data = s2n_stuffer_raw_read(key_out_stuffer, key_blob.size);
     120 [ -  + ][ #  # ]:        761 :     POSIX_ENSURE_REF(key_blob.data);
     121                 :            : 
     122         [ +  + ]:        761 :     POSIX_GUARD_RESULT(s2n_asn1der_to_private_key(cert_and_key->private_key, &key_blob, type_hint));
     123                 :        760 :     return S2N_SUCCESS;
     124                 :        761 : }
     125                 :            : 
     126                 :            : int s2n_cert_chain_and_key_set_private_key_bytes(struct s2n_cert_chain_and_key *cert_and_key, uint8_t *private_key_pem, uint32_t private_key_len)
     127                 :         12 : {
     128                 :         12 :     DEFER_CLEANUP(struct s2n_stuffer key_in_stuffer = { 0 }, s2n_stuffer_free);
     129                 :         12 :     DEFER_CLEANUP(struct s2n_stuffer key_out_stuffer = { 0 }, s2n_stuffer_free);
     130                 :            : 
     131                 :            :     /* Put the private key pem in a stuffer */
     132         [ -  + ]:         12 :     POSIX_GUARD(s2n_stuffer_init_ro_from_string(&key_in_stuffer, private_key_pem, private_key_len));
     133         [ -  + ]:         12 :     POSIX_GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, private_key_len));
     134                 :            : 
     135         [ -  + ]:         12 :     POSIX_GUARD(s2n_cert_chain_and_key_set_private_key_from_stuffer(cert_and_key, &key_in_stuffer, &key_out_stuffer));
     136                 :            : 
     137                 :         12 :     return S2N_SUCCESS;
     138                 :         12 : }
     139                 :            : 
     140                 :            : int s2n_cert_chain_and_key_set_private_key(struct s2n_cert_chain_and_key *cert_and_key, const char *private_key_pem)
     141                 :        751 : {
     142 [ -  + ][ #  # ]:        751 :     POSIX_ENSURE_REF(private_key_pem);
     143                 :            : 
     144                 :        751 :     DEFER_CLEANUP(struct s2n_stuffer key_in_stuffer = { 0 }, s2n_stuffer_free);
     145                 :        751 :     DEFER_CLEANUP(struct s2n_stuffer key_out_stuffer = { 0 }, s2n_stuffer_free);
     146                 :            : 
     147                 :            :     /* Put the private key pem in a stuffer */
     148         [ -  + ]:        751 :     POSIX_GUARD(s2n_stuffer_alloc_ro_from_string(&key_in_stuffer, private_key_pem));
     149         [ -  + ]:        751 :     POSIX_GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, strlen(private_key_pem)));
     150                 :            : 
     151         [ +  + ]:        751 :     POSIX_GUARD(s2n_cert_chain_and_key_set_private_key_from_stuffer(cert_and_key, &key_in_stuffer, &key_out_stuffer));
     152                 :            : 
     153                 :        748 :     return S2N_SUCCESS;
     154                 :        751 : }
     155                 :            : 
     156                 :            : int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length)
     157                 :         32 : {
     158 [ +  - ][ +  + ]:         32 :     POSIX_ENSURE_REF(chain_and_key);
     159         [ -  + ]:         31 :     POSIX_GUARD(s2n_free(&chain_and_key->ocsp_status));
     160 [ +  + ][ +  - ]:         31 :     if (data && length) {
     161         [ -  + ]:         30 :         POSIX_GUARD(s2n_alloc(&chain_and_key->ocsp_status, length));
     162 [ #  # ][ -  + ]:         30 :         POSIX_CHECKED_MEMCPY(chain_and_key->ocsp_status.data, data, length);
                 [ +  - ]
     163                 :         30 :     }
     164                 :         31 :     return 0;
     165                 :         31 : }
     166                 :            : 
     167                 :            : int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length)
     168                 :         15 : {
     169 [ +  - ][ +  + ]:         15 :     POSIX_ENSURE_REF(chain_and_key);
     170         [ -  + ]:         14 :     POSIX_GUARD(s2n_free(&chain_and_key->sct_list));
     171 [ +  + ][ +  - ]:         14 :     if (data && length) {
     172         [ -  + ]:         13 :         POSIX_GUARD(s2n_alloc(&chain_and_key->sct_list, length));
     173 [ #  # ][ -  + ]:         13 :         POSIX_CHECKED_MEMCPY(chain_and_key->sct_list.data, data, length);
                 [ +  - ]
     174                 :         13 :     }
     175                 :         14 :     return 0;
     176                 :         14 : }
     177                 :            : 
     178                 :            : struct s2n_cert_chain_and_key *s2n_cert_chain_and_key_new(void)
     179                 :        936 : {
     180                 :        936 :     DEFER_CLEANUP(struct s2n_blob chain_and_key_mem = { 0 }, s2n_free);
     181         [ -  + ]:        936 :     PTR_GUARD_POSIX(s2n_alloc(&chain_and_key_mem, sizeof(struct s2n_cert_chain_and_key)));
     182         [ -  + ]:        936 :     PTR_GUARD_POSIX(s2n_blob_zero(&chain_and_key_mem));
     183                 :            : 
     184                 :        936 :     DEFER_CLEANUP(struct s2n_blob cert_chain_mem = { 0 }, s2n_free);
     185         [ -  + ]:        936 :     PTR_GUARD_POSIX(s2n_alloc(&cert_chain_mem, sizeof(struct s2n_cert_chain)));
     186         [ -  + ]:        936 :     PTR_GUARD_POSIX(s2n_blob_zero(&cert_chain_mem));
     187                 :            : 
     188                 :        936 :     DEFER_CLEANUP(struct s2n_blob pkey_mem = { 0 }, s2n_free);
     189         [ -  + ]:        936 :     PTR_GUARD_POSIX(s2n_alloc(&pkey_mem, sizeof(s2n_cert_private_key)));
     190         [ -  + ]:        936 :     PTR_GUARD_POSIX(s2n_blob_zero(&pkey_mem));
     191                 :            : 
     192                 :        936 :     DEFER_CLEANUP(struct s2n_array *cn_names = NULL, s2n_array_free_p);
     193                 :        936 :     cn_names = s2n_array_new(sizeof(struct s2n_blob));
     194 [ -  + ][ #  # ]:        936 :     PTR_ENSURE_REF(cn_names);
     195                 :            : 
     196                 :        936 :     DEFER_CLEANUP(struct s2n_array *san_names = NULL, s2n_array_free_p);
     197                 :        936 :     san_names = s2n_array_new(sizeof(struct s2n_blob));
     198 [ -  + ][ #  # ]:        936 :     PTR_ENSURE_REF(san_names);
     199                 :            : 
     200                 :        936 :     struct s2n_cert_chain_and_key *chain_and_key = (struct s2n_cert_chain_and_key *) (void *) chain_and_key_mem.data;
     201                 :        936 :     chain_and_key->cert_chain = (struct s2n_cert_chain *) (void *) cert_chain_mem.data;
     202                 :        936 :     chain_and_key->private_key = (s2n_cert_private_key *) (void *) pkey_mem.data;
     203                 :        936 :     chain_and_key->cn_names = cn_names;
     204                 :        936 :     chain_and_key->san_names = san_names;
     205                 :            : 
     206                 :        936 :     ZERO_TO_DISABLE_DEFER_CLEANUP(chain_and_key_mem);
     207                 :        936 :     ZERO_TO_DISABLE_DEFER_CLEANUP(cert_chain_mem);
     208                 :        936 :     ZERO_TO_DISABLE_DEFER_CLEANUP(pkey_mem);
     209                 :        936 :     ZERO_TO_DISABLE_DEFER_CLEANUP(cn_names);
     210                 :        936 :     ZERO_TO_DISABLE_DEFER_CLEANUP(san_names);
     211                 :        936 :     return chain_and_key;
     212                 :        936 : }
     213                 :            : 
     214                 :            : DEFINE_POINTER_CLEANUP_FUNC(GENERAL_NAMES *, GENERAL_NAMES_free);
     215                 :            : 
     216                 :            : int s2n_cert_chain_and_key_load_sans(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert)
     217                 :        823 : {
     218 [ -  + ][ #  # ]:        823 :     POSIX_ENSURE_REF(chain_and_key->san_names);
     219 [ #  # ][ -  + ]:        823 :     POSIX_ENSURE_REF(x509_cert);
     220                 :            : 
     221                 :        823 :     DEFER_CLEANUP(GENERAL_NAMES *san_names = X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL), GENERAL_NAMES_free_pointer);
     222         [ +  + ]:        823 :     if (san_names == NULL) {
     223                 :            :         /* No SAN extension */
     224                 :        110 :         return 0;
     225                 :        110 :     }
     226                 :            : 
     227                 :        713 :     const int num_san_names = sk_GENERAL_NAME_num(san_names);
     228         [ +  + ]:       1432 :     for (int i = 0; i < num_san_names; i++) {
     229                 :        719 :         GENERAL_NAME *san_name = sk_GENERAL_NAME_value(san_names, i);
     230         [ -  + ]:        719 :         if (!san_name) {
     231                 :          0 :             continue;
     232                 :          0 :         }
     233                 :            : 
     234         [ +  + ]:        719 :         if (san_name->type == GEN_DNS) {
     235                 :            :             /* Decoding isn't necessary here since a DNS SAN name is ASCII(type V_ASN1_IA5STRING) */
     236                 :        715 :             const unsigned char *san_str = S2N_ASN1_STRING_DATA(san_name->d.dNSName);
     237                 :        715 :             const size_t san_str_len = ASN1_STRING_length(san_name->d.dNSName);
     238                 :        715 :             struct s2n_blob *san_blob = NULL;
     239         [ -  + ]:        715 :             POSIX_GUARD_RESULT(s2n_array_pushback(chain_and_key->san_names, (void **) &san_blob));
     240         [ -  + ]:        715 :             if (!san_blob) {
     241         [ #  # ]:          0 :                 POSIX_BAIL(S2N_ERR_NULL_SANS);
     242                 :          0 :             }
     243                 :            : 
     244         [ -  + ]:        715 :             if (s2n_alloc(san_blob, san_str_len)) {
     245                 :          0 :                 S2N_ERROR_PRESERVE_ERRNO();
     246                 :          0 :             }
     247                 :            : 
     248 [ #  # ][ -  + ]:        715 :             POSIX_CHECKED_MEMCPY(san_blob->data, san_str, san_str_len);
                 [ +  - ]
     249                 :        715 :             san_blob->size = san_str_len;
     250                 :            :             /* normalize san_blob to lowercase */
     251         [ -  + ]:        715 :             POSIX_GUARD(s2n_blob_char_to_lower(san_blob));
     252                 :        715 :         }
     253                 :        719 :     }
     254                 :            : 
     255                 :        713 :     return 0;
     256                 :        713 : }
     257                 :            : 
     258                 :            : /* Parse CN names from the Subject of the leaf certificate. Technically there can by multiple CNs
     259                 :            :  * in the Subject but practically very few certificates in the wild will have more than one CN.
     260                 :            :  * Since the data for this certificate is coming from the application and not from an untrusted
     261                 :            :  * source, we will try our best to parse all of the CNs.
     262                 :            :  *
     263                 :            :  * A recent CAB thread proposed removing support for multiple CNs:
     264                 :            :  * https://cabforum.org/pipermail/public/2016-April/007242.html
     265                 :            :  */
     266                 :            : 
     267                 :        828 : DEFINE_POINTER_CLEANUP_FUNC(unsigned char *, OPENSSL_free);
     268                 :            : 
     269                 :            : int s2n_cert_chain_and_key_load_cns(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert)
     270                 :        826 : {
     271 [ -  + ][ #  # ]:        826 :     POSIX_ENSURE_REF(chain_and_key->cn_names);
     272 [ -  + ][ #  # ]:        826 :     POSIX_ENSURE_REF(x509_cert);
     273                 :            : 
     274                 :        826 :     S2N_X509_CONST X509_NAME *subject = X509_get_subject_name(x509_cert);
     275         [ -  + ]:        826 :     if (!subject) {
     276                 :          0 :         return 0;
     277                 :          0 :     }
     278                 :            : 
     279                 :        826 :     int lastpos = -1;
     280         [ +  + ]:       1654 :     while ((lastpos = X509_NAME_get_index_by_NID(subject, NID_commonName, lastpos)) >= 0) {
     281                 :        828 :         S2N_X509_CONST X509_NAME_ENTRY *name_entry = X509_NAME_get_entry(subject, lastpos);
     282         [ -  + ]:        828 :         if (!name_entry) {
     283                 :          0 :             continue;
     284                 :          0 :         }
     285                 :            : 
     286                 :        828 :         S2N_X509_CONST ASN1_STRING *asn1_str = X509_NAME_ENTRY_get_data(name_entry);
     287         [ -  + ]:        828 :         if (!asn1_str) {
     288                 :          0 :             continue;
     289                 :          0 :         }
     290                 :            : 
     291                 :            :         /* We need to try and decode the CN since it may be encoded as unicode with a
     292                 :            :          * direct ASCII equivalent. Any non ASCII bytes in the string will fail later when we
     293                 :            :          * actually compare hostnames.
     294                 :            :          *
     295                 :            :          * `ASN1_STRING_to_UTF8` allocates in both the success case and in the zero return case, but
     296                 :            :          * not in the failure case (negative return value). Therefore, we use `ZERO_TO_DISABLE_DEFER_CLEANUP`
     297                 :            :          * in the failure case to prevent double-freeing `utf8_str`. For the zero and success cases, `utf8_str`
     298                 :            :          * will be freed by the `DEFER_CLEANUP`.
     299                 :            :          */
     300                 :        828 :         DEFER_CLEANUP(unsigned char *utf8_str, OPENSSL_free_pointer);
     301                 :        828 :         const int utf8_out_len = ASN1_STRING_to_UTF8(&utf8_str, asn1_str);
     302         [ +  + ]:        828 :         if (utf8_out_len < 0) {
     303                 :            :             /* On failure, ASN1_STRING_to_UTF8 does not allocate any memory */
     304                 :          2 :             ZERO_TO_DISABLE_DEFER_CLEANUP(utf8_str);
     305                 :          2 :             continue;
     306         [ +  + ]:        826 :         } else if (utf8_out_len == 0) {
     307                 :            :             /* We still need to free memory for this case, so let the DEFER_CLEANUP free it
     308                 :            :              * see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7521 and
     309                 :            :              * https://security.archlinux.org/CVE-2017-7521
     310                 :            :             */
     311                 :        823 :         } else {
     312                 :        823 :             struct s2n_blob *cn_name = NULL;
     313         [ -  + ]:        823 :             POSIX_GUARD_RESULT(s2n_array_pushback(chain_and_key->cn_names, (void **) &cn_name));
     314         [ -  + ]:        823 :             if (cn_name == NULL) {
     315         [ #  # ]:          0 :                 POSIX_BAIL(S2N_ERR_NULL_CN_NAME);
     316                 :          0 :             }
     317                 :            : 
     318         [ -  + ]:        823 :             if (s2n_alloc(cn_name, utf8_out_len) < 0) {
     319                 :          0 :                 S2N_ERROR_PRESERVE_ERRNO();
     320                 :          0 :             }
     321 [ -  + ][ #  # ]:        823 :             POSIX_CHECKED_MEMCPY(cn_name->data, utf8_str, utf8_out_len);
                 [ +  - ]
     322                 :        823 :             cn_name->size = utf8_out_len;
     323                 :            :             /* normalize cn_name to lowercase */
     324         [ -  + ]:        823 :             POSIX_GUARD(s2n_blob_char_to_lower(cn_name));
     325                 :        823 :         }
     326                 :        828 :     }
     327                 :            : 
     328                 :        826 :     return 0;
     329                 :        826 : }
     330                 :            : 
     331                 :            : static int s2n_cert_chain_and_key_set_names(struct s2n_cert_chain_and_key *chain_and_key, X509 *cert)
     332                 :        823 : {
     333         [ -  + ]:        823 :     POSIX_GUARD(s2n_cert_chain_and_key_load_sans(chain_and_key, cert));
     334                 :            :     /* For current use cases, we *could* avoid populating the common names if any sans were loaded in
     335                 :            :      * s2n_cert_chain_and_key_load_sans. Let's unconditionally populate this field to avoid surprises
     336                 :            :      * in the future.
     337                 :            :      */
     338         [ -  + ]:        823 :     POSIX_GUARD(s2n_cert_chain_and_key_load_cns(chain_and_key, cert));
     339                 :        823 :     return 0;
     340                 :        823 : }
     341                 :            : 
     342                 :            : int s2n_cert_chain_and_key_load(struct s2n_cert_chain_and_key *chain_and_key)
     343                 :        837 : {
     344 [ #  # ][ -  + ]:        837 :     POSIX_ENSURE_REF(chain_and_key);
     345 [ #  # ][ -  + ]:        837 :     POSIX_ENSURE_REF(chain_and_key->cert_chain);
     346 [ -  + ][ #  # ]:        837 :     POSIX_ENSURE_REF(chain_and_key->cert_chain->head);
     347 [ #  # ][ -  + ]:        837 :     POSIX_ENSURE_REF(chain_and_key->private_key);
     348                 :        837 :     struct s2n_cert *head = chain_and_key->cert_chain->head;
     349                 :            : 
     350                 :        837 :     DEFER_CLEANUP(X509 *leaf_cert = NULL, X509_free_pointer);
     351         [ -  + ]:        837 :     POSIX_GUARD_RESULT(s2n_openssl_x509_parse(&head->raw, &leaf_cert));
     352         [ -  + ]:        837 :     POSIX_GUARD_RESULT(s2n_openssl_x509_get_cert_info(leaf_cert, &head->info));
     353                 :            : 
     354                 :            :     /* Parse the leaf cert for the public key and certificate type */
     355                 :        837 :     DEFER_CLEANUP(struct s2n_pkey public_key = { 0 }, s2n_pkey_free);
     356                 :        837 :     s2n_pkey_type pkey_type = S2N_PKEY_TYPE_UNKNOWN;
     357         [ -  + ]:        837 :     POSIX_GUARD_RESULT(s2n_pkey_from_x509(leaf_cert, &public_key, &pkey_type));
     358                 :            : 
     359 [ -  + ][ #  # ]:        837 :     POSIX_ENSURE(pkey_type != S2N_PKEY_TYPE_UNKNOWN, S2N_ERR_CERT_TYPE_UNSUPPORTED);
     360         [ -  + ]:        837 :     POSIX_GUARD(s2n_cert_set_cert_type(head, pkey_type));
     361                 :            : 
     362                 :            :     /* Validate the leaf cert's public key matches the provided private key */
     363         [ +  + ]:        837 :     if (s2n_pkey_check_key_exists(chain_and_key->private_key) == S2N_SUCCESS) {
     364         [ +  + ]:        756 :         POSIX_GUARD(s2n_pkey_match(&public_key, chain_and_key->private_key));
     365                 :        756 :     }
     366                 :            : 
     367                 :            :     /* Populate name information from the SAN/CN for the leaf certificate */
     368         [ -  + ]:        823 :     POSIX_GUARD(s2n_cert_chain_and_key_set_names(chain_and_key, leaf_cert));
     369                 :            : 
     370                 :            :     /* populate libcrypto nid's required for cert restrictions */
     371                 :        823 :     struct s2n_cert *current = head->next;
     372         [ +  + ]:       1840 :     while (current != NULL) {
     373                 :       1017 :         DEFER_CLEANUP(X509 *parsed_cert = NULL, X509_free_pointer);
     374         [ -  + ]:       1017 :         POSIX_GUARD_RESULT(s2n_openssl_x509_parse(&current->raw, &parsed_cert));
     375         [ -  + ]:       1017 :         POSIX_GUARD_RESULT(s2n_openssl_x509_get_cert_info(parsed_cert, &current->info));
     376                 :            : 
     377                 :       1017 :         current = current->next;
     378                 :       1017 :     }
     379                 :            : 
     380                 :        823 :     return S2N_SUCCESS;
     381                 :        823 : }
     382                 :            : 
     383                 :            : int s2n_cert_chain_and_key_load_pem(struct s2n_cert_chain_and_key *chain_and_key, const char *chain_pem, const char *private_key_pem)
     384                 :        750 : {
     385 [ #  # ][ -  + ]:        750 :     POSIX_ENSURE_REF(chain_and_key);
     386                 :            : 
     387         [ +  + ]:        750 :     POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain(chain_and_key, chain_pem));
     388         [ +  + ]:        747 :     POSIX_GUARD(s2n_cert_chain_and_key_set_private_key(chain_and_key, private_key_pem));
     389                 :            : 
     390         [ +  + ]:        744 :     POSIX_GUARD(s2n_cert_chain_and_key_load(chain_and_key));
     391                 :            : 
     392                 :        736 :     return S2N_SUCCESS;
     393                 :        744 : }
     394                 :            : 
     395                 :            : int s2n_cert_chain_and_key_load_public_pem_bytes(struct s2n_cert_chain_and_key *chain_and_key, uint8_t *chain_pem, uint32_t chain_pem_len)
     396                 :         81 : {
     397 [ -  + ][ #  # ]:         81 :     POSIX_ENSURE_REF(chain_and_key);
     398         [ -  + ]:         81 :     POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_bytes(chain_and_key, chain_pem, chain_pem_len));
     399         [ -  + ]:         81 :     POSIX_GUARD(s2n_cert_chain_and_key_load(chain_and_key));
     400                 :         81 :     return S2N_SUCCESS;
     401                 :         81 : }
     402                 :            : 
     403                 :            : int s2n_cert_chain_and_key_load_pem_bytes(struct s2n_cert_chain_and_key *chain_and_key, uint8_t *chain_pem,
     404                 :            :         uint32_t chain_pem_len, uint8_t *private_key_pem, uint32_t private_key_pem_len)
     405                 :         12 : {
     406 [ -  + ][ #  # ]:         12 :     POSIX_ENSURE_REF(chain_and_key);
     407                 :            : 
     408         [ -  + ]:         12 :     POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_bytes(chain_and_key, chain_pem, chain_pem_len));
     409         [ -  + ]:         12 :     POSIX_GUARD(s2n_cert_chain_and_key_set_private_key_bytes(chain_and_key, private_key_pem, private_key_pem_len));
     410                 :            : 
     411         [ +  + ]:         12 :     POSIX_GUARD(s2n_cert_chain_and_key_load(chain_and_key));
     412                 :            : 
     413                 :          6 :     return S2N_SUCCESS;
     414                 :         12 : }
     415                 :            : 
     416                 :            : S2N_CLEANUP_RESULT s2n_cert_chain_and_key_ptr_free(struct s2n_cert_chain_and_key **cert_and_key)
     417                 :        512 : {
     418 [ -  + ][ #  # ]:        512 :     RESULT_ENSURE_REF(cert_and_key);
     419         [ -  + ]:        512 :     RESULT_GUARD_POSIX(s2n_cert_chain_and_key_free(*cert_and_key));
     420                 :        512 :     *cert_and_key = NULL;
     421                 :        512 :     return S2N_RESULT_OK;
     422                 :        512 : }
     423                 :            : 
     424                 :            : int s2n_cert_chain_and_key_free(struct s2n_cert_chain_and_key *cert_and_key)
     425                 :        988 : {
     426         [ +  + ]:        988 :     if (cert_and_key == NULL) {
     427                 :         52 :         return 0;
     428                 :         52 :     }
     429                 :            : 
     430                 :            :     /* Walk the chain and free the certs */
     431         [ +  - ]:        936 :     if (cert_and_key->cert_chain) {
     432                 :        936 :         struct s2n_cert *node = cert_and_key->cert_chain->head;
     433         [ +  + ]:       3009 :         while (node) {
     434                 :            :             /* Free the cert */
     435         [ -  + ]:       2073 :             POSIX_GUARD(s2n_free(&node->raw));
     436                 :            :             /* update head so it won't point to freed memory */
     437                 :       2073 :             cert_and_key->cert_chain->head = node->next;
     438                 :            :             /* Free the node */
     439         [ -  + ]:       2073 :             POSIX_GUARD(s2n_free_object((uint8_t **) &node, sizeof(struct s2n_cert)));
     440                 :       2073 :             node = cert_and_key->cert_chain->head;
     441                 :       2073 :         }
     442                 :            : 
     443         [ -  + ]:        936 :         POSIX_GUARD(s2n_free_object((uint8_t **) &cert_and_key->cert_chain, sizeof(struct s2n_cert_chain)));
     444                 :        936 :     }
     445                 :            : 
     446         [ +  + ]:        936 :     if (cert_and_key->private_key) {
     447         [ -  + ]:        930 :         POSIX_GUARD(s2n_pkey_free(cert_and_key->private_key));
     448         [ -  + ]:        930 :         POSIX_GUARD(s2n_free_object((uint8_t **) &cert_and_key->private_key, sizeof(s2n_cert_private_key)));
     449                 :        930 :     }
     450                 :            : 
     451                 :        936 :     uint32_t len = 0;
     452                 :            : 
     453         [ +  - ]:        936 :     if (cert_and_key->san_names) {
     454         [ -  + ]:        936 :         POSIX_GUARD_RESULT(s2n_array_num_elements(cert_and_key->san_names, &len));
     455         [ +  + ]:       1651 :         for (uint32_t i = 0; i < len; i++) {
     456                 :        715 :             struct s2n_blob *san_name = NULL;
     457         [ -  + ]:        715 :             POSIX_GUARD_RESULT(s2n_array_get(cert_and_key->san_names, i, (void **) &san_name));
     458         [ -  + ]:        715 :             POSIX_GUARD(s2n_free(san_name));
     459                 :        715 :         }
     460         [ -  + ]:        936 :         POSIX_GUARD_RESULT(s2n_array_free(cert_and_key->san_names));
     461                 :        936 :         cert_and_key->san_names = NULL;
     462                 :        936 :     }
     463                 :            : 
     464         [ +  - ]:        936 :     if (cert_and_key->cn_names) {
     465         [ -  + ]:        936 :         POSIX_GUARD_RESULT(s2n_array_num_elements(cert_and_key->cn_names, &len));
     466         [ +  + ]:       1759 :         for (uint32_t i = 0; i < len; i++) {
     467                 :        823 :             struct s2n_blob *cn_name = NULL;
     468         [ -  + ]:        823 :             POSIX_GUARD_RESULT(s2n_array_get(cert_and_key->cn_names, i, (void **) &cn_name));
     469         [ -  + ]:        823 :             POSIX_GUARD(s2n_free(cn_name));
     470                 :        823 :         }
     471         [ -  + ]:        936 :         POSIX_GUARD_RESULT(s2n_array_free(cert_and_key->cn_names));
     472                 :        936 :         cert_and_key->cn_names = NULL;
     473                 :        936 :     }
     474                 :            : 
     475         [ -  + ]:        936 :     POSIX_GUARD(s2n_free(&cert_and_key->ocsp_status));
     476         [ -  + ]:        936 :     POSIX_GUARD(s2n_free(&cert_and_key->sct_list));
     477                 :            : 
     478         [ -  + ]:        936 :     POSIX_GUARD(s2n_free_object((uint8_t **) &cert_and_key, sizeof(struct s2n_cert_chain_and_key)));
     479                 :        936 :     return 0;
     480                 :        936 : }
     481                 :            : 
     482                 :            : int s2n_cert_chain_free(struct s2n_cert_chain *cert_chain)
     483                 :          1 : {
     484                 :            :     /* Walk the chain and free the certs/nodes allocated prior to failure */
     485         [ +  - ]:          1 :     if (cert_chain) {
     486                 :          1 :         struct s2n_cert *node = cert_chain->head;
     487         [ -  + ]:          1 :         while (node) {
     488                 :            :             /* Free the cert */
     489         [ #  # ]:          0 :             POSIX_GUARD(s2n_free(&node->raw));
     490                 :            :             /* update head so it won't point to freed memory */
     491                 :          0 :             cert_chain->head = node->next;
     492                 :            :             /* Free the node */
     493         [ #  # ]:          0 :             POSIX_GUARD(s2n_free_object((uint8_t **) &node, sizeof(struct s2n_cert)));
     494                 :          0 :             node = cert_chain->head;
     495                 :          0 :         }
     496                 :          1 :     }
     497                 :            : 
     498                 :          1 :     return S2N_SUCCESS;
     499                 :          1 : }
     500                 :            : 
     501                 :            : int s2n_send_cert_chain(struct s2n_connection *conn, struct s2n_stuffer *out, struct s2n_cert_chain_and_key *chain_and_key)
     502                 :       5947 : {
     503 [ -  + ][ #  # ]:       5947 :     POSIX_ENSURE_REF(conn);
     504 [ -  + ][ #  # ]:       5947 :     POSIX_ENSURE_REF(out);
     505 [ -  + ][ #  # ]:       5947 :     POSIX_ENSURE_REF(chain_and_key);
     506                 :       5947 :     struct s2n_cert_chain *chain = chain_and_key->cert_chain;
     507 [ -  + ][ #  # ]:       5947 :     POSIX_ENSURE_REF(chain);
     508                 :       5947 :     struct s2n_cert *cur_cert = chain->head;
     509 [ -  + ][ #  # ]:       5947 :     POSIX_ENSURE_REF(cur_cert);
     510                 :            : 
     511                 :       5947 :     struct s2n_stuffer_reservation cert_chain_size = { 0 };
     512         [ -  + ]:       5947 :     POSIX_GUARD(s2n_stuffer_reserve_uint24(out, &cert_chain_size));
     513                 :            : 
     514                 :            :     /* Send certs and extensions (in TLS 1.3) */
     515                 :       5947 :     bool first_entry = true;
     516         [ +  + ]:      21459 :     while (cur_cert) {
     517 [ -  + ][ #  # ]:      15512 :         POSIX_ENSURE_REF(cur_cert);
     518         [ -  + ]:      15512 :         POSIX_GUARD(s2n_stuffer_write_uint24(out, cur_cert->raw.size));
     519         [ -  + ]:      15512 :         POSIX_GUARD(s2n_stuffer_write_bytes(out, cur_cert->raw.data, cur_cert->raw.size));
     520                 :            : 
     521                 :            :         /* According to https://tools.ietf.org/html/rfc8446#section-4.4.2,
     522                 :            :          * If an extension applies to the entire chain, it SHOULD be included in
     523                 :            :          * the first CertificateEntry.
     524                 :            :          * While the spec allow extensions to be included in other certificate
     525                 :            :          * entries, only the first matter to use here */
     526         [ +  + ]:      15512 :         if (conn->actual_protocol_version >= S2N_TLS13) {
     527         [ +  + ]:       8730 :             if (first_entry) {
     528         [ -  + ]:       3473 :                 POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERTIFICATE, conn, out));
     529                 :       3473 :                 first_entry = false;
     530                 :       5257 :             } else {
     531         [ -  + ]:       5257 :                 POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_EMPTY, conn, out));
     532                 :       5257 :             }
     533                 :       8730 :         }
     534                 :      15512 :         cur_cert = cur_cert->next;
     535                 :      15512 :     }
     536                 :            : 
     537         [ -  + ]:       5947 :     POSIX_GUARD(s2n_stuffer_write_vector_size(&cert_chain_size));
     538                 :            : 
     539                 :       5947 :     return 0;
     540                 :       5947 : }
     541                 :            : 
     542                 :            : int s2n_send_empty_cert_chain(struct s2n_stuffer *out)
     543                 :         34 : {
     544 [ #  # ][ -  + ]:         34 :     POSIX_ENSURE_REF(out);
     545         [ -  + ]:         34 :     POSIX_GUARD(s2n_stuffer_write_uint24(out, 0));
     546                 :         34 :     return 0;
     547                 :         34 : }
     548                 :            : 
     549                 :            : static int s2n_does_cert_san_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name)
     550                 :          0 : {
     551 [ #  # ][ #  # ]:          0 :     POSIX_ENSURE_REF(chain_and_key);
     552 [ #  # ][ #  # ]:          0 :     POSIX_ENSURE_REF(dns_name);
     553                 :            : 
     554                 :          0 :     struct s2n_array *san_names = chain_and_key->san_names;
     555                 :          0 :     uint32_t len = 0;
     556         [ #  # ]:          0 :     POSIX_GUARD_RESULT(s2n_array_num_elements(san_names, &len));
     557         [ #  # ]:          0 :     for (uint32_t i = 0; i < len; i++) {
     558                 :          0 :         struct s2n_blob *san_name = NULL;
     559         [ #  # ]:          0 :         POSIX_GUARD_RESULT(s2n_array_get(san_names, i, (void **) &san_name));
     560 [ #  # ][ #  # ]:          0 :         POSIX_ENSURE_REF(san_name);
     561 [ #  # ][ #  # ]:          0 :         if ((dns_name->size == san_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) san_name->data, dns_name->size) == 0)) {
     562                 :          0 :             return 1;
     563                 :          0 :         }
     564                 :          0 :     }
     565                 :            : 
     566                 :          0 :     return 0;
     567                 :          0 : }
     568                 :            : 
     569                 :            : static int s2n_does_cert_cn_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name)
     570                 :          0 : {
     571 [ #  # ][ #  # ]:          0 :     POSIX_ENSURE_REF(chain_and_key);
     572 [ #  # ][ #  # ]:          0 :     POSIX_ENSURE_REF(dns_name);
     573                 :            : 
     574                 :          0 :     struct s2n_array *cn_names = chain_and_key->cn_names;
     575                 :          0 :     uint32_t len = 0;
     576         [ #  # ]:          0 :     POSIX_GUARD_RESULT(s2n_array_num_elements(cn_names, &len));
     577         [ #  # ]:          0 :     for (uint32_t i = 0; i < len; i++) {
     578                 :          0 :         struct s2n_blob *cn_name = NULL;
     579         [ #  # ]:          0 :         POSIX_GUARD_RESULT(s2n_array_get(cn_names, i, (void **) &cn_name));
     580 [ #  # ][ #  # ]:          0 :         POSIX_ENSURE_REF(cn_name);
     581 [ #  # ][ #  # ]:          0 :         if ((dns_name->size == cn_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) cn_name->data, dns_name->size) == 0)) {
     582                 :          0 :             return 1;
     583                 :          0 :         }
     584                 :          0 :     }
     585                 :            : 
     586                 :          0 :     return 0;
     587                 :          0 : }
     588                 :            : 
     589                 :            : int s2n_cert_chain_and_key_matches_dns_name(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name)
     590                 :          0 : {
     591                 :          0 :     uint32_t len = 0;
     592         [ #  # ]:          0 :     POSIX_GUARD_RESULT(s2n_array_num_elements(chain_and_key->san_names, &len));
     593         [ #  # ]:          0 :     if (len > 0) {
     594         [ #  # ]:          0 :         if (s2n_does_cert_san_match_hostname(chain_and_key, dns_name)) {
     595                 :          0 :             return 1;
     596                 :          0 :         }
     597                 :          0 :     } else {
     598                 :            :         /* Per https://tools.ietf.org/html/rfc6125#section-6.4.4 we only will
     599                 :            :          * consider the CN for matching if no valid DNS entries are provided
     600                 :            :          * in a SAN.
     601                 :            :          */
     602         [ #  # ]:          0 :         if (s2n_does_cert_cn_match_hostname(chain_and_key, dns_name)) {
     603                 :          0 :             return 1;
     604                 :          0 :         }
     605                 :          0 :     }
     606                 :            : 
     607                 :          0 :     return 0;
     608                 :          0 : }
     609                 :            : 
     610                 :            : int s2n_cert_chain_and_key_set_ctx(struct s2n_cert_chain_and_key *cert_and_key, void *ctx)
     611                 :        100 : {
     612 [ #  # ][ -  + ]:        100 :     POSIX_ENSURE_REF(cert_and_key);
     613                 :        100 :     cert_and_key->context = ctx;
     614                 :        100 :     return 0;
     615                 :        100 : }
     616                 :            : 
     617                 :            : void *s2n_cert_chain_and_key_get_ctx(struct s2n_cert_chain_and_key *cert_and_key)
     618                 :        200 : {
     619 [ #  # ][ -  + ]:        200 :     PTR_ENSURE_REF(cert_and_key);
     620                 :        200 :     return cert_and_key->context;
     621                 :        200 : }
     622                 :            : 
     623                 :            : s2n_pkey_type s2n_cert_chain_and_key_get_pkey_type(struct s2n_cert_chain_and_key *chain_and_key)
     624                 :       2658 : {
     625         [ -  + ]:       2658 :     if (chain_and_key == NULL
     626         [ -  + ]:       2658 :             || chain_and_key->cert_chain == NULL
     627         [ -  + ]:       2658 :             || chain_and_key->cert_chain->head == NULL) {
     628                 :          0 :         return S2N_PKEY_TYPE_UNKNOWN;
     629                 :          0 :     }
     630                 :       2658 :     return chain_and_key->cert_chain->head->pkey_type;
     631                 :       2658 : }
     632                 :            : 
     633                 :            : s2n_cert_private_key *s2n_cert_chain_and_key_get_private_key(struct s2n_cert_chain_and_key *chain_and_key)
     634                 :        895 : {
     635 [ #  # ][ -  + ]:        895 :     PTR_ENSURE_REF(chain_and_key);
     636                 :        895 :     return chain_and_key->private_key;
     637                 :        895 : }
     638                 :            : 
     639                 :            : int s2n_cert_chain_get_length(const struct s2n_cert_chain_and_key *chain_and_key, uint32_t *cert_length)
     640                 :         31 : {
     641 [ +  + ][ +  - ]:         31 :     POSIX_ENSURE_REF(chain_and_key);
     642 [ +  + ][ +  - ]:         30 :     POSIX_ENSURE_REF(cert_length);
     643                 :            : 
     644                 :         29 :     struct s2n_cert *head_cert = chain_and_key->cert_chain->head;
     645 [ #  # ][ -  + ]:         29 :     POSIX_ENSURE_REF(head_cert);
     646                 :         29 :     *cert_length = 1;
     647                 :         29 :     struct s2n_cert *next_cert = head_cert->next;
     648         [ +  + ]:        233 :     while (next_cert != NULL) {
     649                 :        204 :         *cert_length += 1;
     650                 :        204 :         next_cert = next_cert->next;
     651                 :        204 :     }
     652                 :            : 
     653                 :         29 :     return S2N_SUCCESS;
     654                 :         29 : }
     655                 :            : 
     656                 :            : int s2n_cert_chain_get_cert(const struct s2n_cert_chain_and_key *chain_and_key, struct s2n_cert **out_cert,
     657                 :            :         const uint32_t cert_idx)
     658                 :         10 : {
     659 [ +  + ][ +  - ]:         10 :     POSIX_ENSURE_REF(chain_and_key);
     660 [ +  + ][ +  - ]:          9 :     POSIX_ENSURE_REF(out_cert);
     661                 :            : 
     662                 :          8 :     struct s2n_cert *cur_cert = chain_and_key->cert_chain->head;
     663 [ #  # ][ -  + ]:          8 :     POSIX_ENSURE_REF(cur_cert);
     664                 :          8 :     uint32_t counter = 0;
     665                 :            : 
     666                 :          8 :     struct s2n_cert *next_cert = cur_cert->next;
     667                 :            : 
     668 [ +  + ][ +  + ]:         13 :     while ((next_cert != NULL) && (counter < cert_idx)) {
     669                 :          5 :         cur_cert = next_cert;
     670                 :          5 :         next_cert = next_cert->next;
     671                 :          5 :         counter++;
     672                 :          5 :     }
     673                 :            : 
     674 [ +  - ][ +  + ]:          8 :     POSIX_ENSURE(counter == cert_idx, S2N_ERR_NO_CERT_FOUND);
     675 [ -  + ][ #  # ]:          7 :     POSIX_ENSURE(cur_cert != NULL, S2N_ERR_NO_CERT_FOUND);
     676                 :          7 :     *out_cert = cur_cert;
     677                 :            : 
     678                 :          7 :     return S2N_SUCCESS;
     679                 :          7 : }
     680                 :            : 
     681                 :            : int s2n_cert_get_der(const struct s2n_cert *cert, const uint8_t **out_cert_der, uint32_t *cert_length)
     682                 :          5 : {
     683 [ +  + ][ +  - ]:          5 :     POSIX_ENSURE_REF(cert);
     684 [ +  + ][ +  - ]:          4 :     POSIX_ENSURE_REF(out_cert_der);
     685 [ +  + ][ +  - ]:          3 :     POSIX_ENSURE_REF(cert_length);
     686                 :            : 
     687                 :          2 :     *cert_length = cert->raw.size;
     688                 :          2 :     *out_cert_der = cert->raw.data;
     689                 :            : 
     690                 :          2 :     return S2N_SUCCESS;
     691                 :          3 : }
     692                 :            : 
     693                 :            : static int s2n_asn1_obj_free(ASN1_OBJECT **data)
     694                 :         17 : {
     695         [ +  - ]:         17 :     if (*data != NULL) {
     696                 :         17 :         ASN1_OBJECT_free(*data);
     697                 :         17 :     }
     698                 :         17 :     return S2N_SUCCESS;
     699                 :         17 : }
     700                 :            : 
     701                 :            : static int s2n_asn1_string_free(ASN1_STRING **data)
     702                 :         16 : {
     703         [ +  + ]:         16 :     if (*data != NULL) {
     704                 :          8 :         ASN1_STRING_free(*data);
     705                 :          8 :     }
     706                 :         16 :     return S2N_SUCCESS;
     707                 :         16 : }
     708                 :            : 
     709                 :            : static int s2n_utf8_string_from_extension_data(const uint8_t *extension_data, uint32_t extension_len, uint8_t *out_data, uint32_t *out_len)
     710                 :         16 : {
     711                 :         16 :     DEFER_CLEANUP(ASN1_STRING *asn1_str = NULL, s2n_asn1_string_free);
     712                 :            :     /* Note that d2i_ASN1_UTF8STRING increments *der_in to the byte following the parsed data.
     713                 :            :      * Using a temporary variable is mandatory to prevent memory free-ing errors.
     714                 :            :      * Ref to the warning section here for more information:
     715                 :            :      * https://www.openssl.org/docs/man1.1.0/man3/d2i_ASN1_UTF8STRING.html.
     716                 :            :      */
     717                 :         16 :     const uint8_t *asn1_str_data = extension_data;
     718                 :         16 :     asn1_str = d2i_ASN1_UTF8STRING(NULL, (const unsigned char **) (void *) &asn1_str_data, extension_len);
     719 [ +  + ][ +  - ]:         16 :     POSIX_ENSURE(asn1_str != NULL, S2N_ERR_INVALID_X509_EXTENSION_TYPE);
     720                 :            :     /* ASN1_STRING_type() returns the type of `asn1_str`, using standard constants such as V_ASN1_OCTET_STRING.
     721                 :            :      * Ref: https://www.openssl.org/docs/man1.1.0/man3/ASN1_STRING_type.html.
     722                 :            :      */
     723                 :          8 :     int type = ASN1_STRING_type(asn1_str);
     724 [ -  + ][ #  # ]:          8 :     POSIX_ENSURE(type == V_ASN1_UTF8STRING, S2N_ERR_INVALID_X509_EXTENSION_TYPE);
     725                 :            : 
     726                 :          8 :     int len = ASN1_STRING_length(asn1_str);
     727 [ #  # ][ -  + ]:          8 :     POSIX_ENSURE_GTE(len, 0);
     728         [ +  + ]:          8 :     if (out_data != NULL) {
     729 [ +  - ][ +  + ]:          5 :         POSIX_ENSURE((int64_t) *out_len >= (int64_t) len, S2N_ERR_INSUFFICIENT_MEM_SIZE);
     730                 :            :         /* ASN1_STRING_get0_data(x) returns an internal pointer to the data of
     731                 :            :          * x. Since this is an internal pointer it should not be freed or
     732                 :            :          * modified in any way.
     733                 :            :          * Ref: https://docs.openssl.org/master/man3/ASN1_STRING_length/
     734                 :            :          */
     735                 :          3 :         const unsigned char *internal_data = S2N_ASN1_STRING_DATA(asn1_str);
     736 [ -  + ][ #  # ]:          3 :         POSIX_ENSURE_REF(internal_data);
     737 [ -  + ][ #  # ]:          3 :         POSIX_CHECKED_MEMCPY(out_data, internal_data, len);
                 [ +  - ]
     738                 :          3 :     }
     739                 :          6 :     *out_len = len;
     740                 :          6 :     return S2N_SUCCESS;
     741                 :          8 : }
     742                 :            : 
     743                 :            : int s2n_cert_get_utf8_string_from_extension_data_length(const uint8_t *extension_data, uint32_t extension_len, uint32_t *utf8_str_len)
     744                 :         10 : {
     745 [ +  + ][ +  - ]:         10 :     POSIX_ENSURE_REF(extension_data);
     746 [ +  + ][ +  - ]:          9 :     POSIX_ENSURE_GT(extension_len, 0);
     747 [ +  - ][ +  + ]:          8 :     POSIX_ENSURE_REF(utf8_str_len);
     748                 :            : 
     749         [ +  + ]:          7 :     POSIX_GUARD(s2n_utf8_string_from_extension_data(extension_data, extension_len, NULL, utf8_str_len));
     750                 :            : 
     751                 :          3 :     return S2N_SUCCESS;
     752                 :          7 : }
     753                 :            : 
     754                 :            : int s2n_cert_get_utf8_string_from_extension_data(const uint8_t *extension_data, uint32_t extension_len, uint8_t *out_data, uint32_t *out_len)
     755                 :         13 : {
     756 [ +  - ][ +  + ]:         13 :     POSIX_ENSURE_REF(extension_data);
     757 [ +  - ][ +  + ]:         12 :     POSIX_ENSURE_GT(extension_len, 0);
     758 [ +  + ][ +  - ]:         11 :     POSIX_ENSURE_REF(out_data);
     759 [ +  + ][ +  - ]:         10 :     POSIX_ENSURE_REF(out_len);
     760                 :            : 
     761         [ +  + ]:          9 :     POSIX_GUARD(s2n_utf8_string_from_extension_data(extension_data, extension_len, out_data, out_len));
     762                 :            : 
     763                 :          3 :     return S2N_SUCCESS;
     764                 :          9 : }
     765                 :            : 
     766                 :            : static int s2n_parse_x509_extension(struct s2n_cert *cert, const uint8_t *oid,
     767                 :            :         uint8_t *ext_value, uint32_t *ext_value_len, bool *critical)
     768                 :         17 : {
     769 [ -  + ][ #  # ]:         17 :     POSIX_ENSURE_REF(cert->raw.data);
     770                 :            :     /* Obtain the openssl x509 cert from the ASN1 DER certificate input.
     771                 :            :      * Note that d2i_X509 increments *der_in to the byte following the parsed data.
     772                 :            :      * Using a temporary variable is mandatory to prevent memory free-ing errors.
     773                 :            :      * Ref to the warning section here for more information:
     774                 :            :      * https://www.openssl.org/docs/man1.1.0/man3/d2i_X509.html.
     775                 :            :      */
     776                 :         17 :     uint8_t *der_in = cert->raw.data;
     777                 :         17 :     DEFER_CLEANUP(X509 *x509_cert = d2i_X509(NULL, (const unsigned char **) (void *) &der_in, cert->raw.size),
     778                 :         17 :             X509_free_pointer);
     779 [ -  + ][ #  # ]:         17 :     POSIX_ENSURE_REF(x509_cert);
     780                 :            : 
     781                 :            :     /* Retrieve the number of x509 extensions present in the certificate
     782                 :            :      * X509_get_ext_count returns the number of extensions in the x509 certificate.
     783                 :            :      * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext_count.html.
     784                 :            :      */
     785                 :         17 :     int ext_count_value = X509_get_ext_count(x509_cert);
     786 [ -  + ][ #  # ]:         17 :     POSIX_ENSURE_GT(ext_count_value, 0);
     787                 :         17 :     size_t ext_count = (size_t) ext_count_value;
     788                 :            : 
     789                 :            :     /* OBJ_txt2obj() converts the input text string into an ASN1_OBJECT structure.
     790                 :            :      * If no_name is 0 then long names and short names will be interpreted as well as numerical forms.
     791                 :            :      * If no_name is 1 only the numerical form is acceptable.
     792                 :            :      * Ref: https://www.openssl.org/docs/man1.1.0/man3/OBJ_txt2obj.html.
     793                 :            :      */
     794                 :         17 :     DEFER_CLEANUP(ASN1_OBJECT *asn1_obj_in = OBJ_txt2obj((const char *) oid, 0), s2n_asn1_obj_free);
     795 [ #  # ][ -  + ]:         17 :     POSIX_ENSURE_REF(asn1_obj_in);
     796                 :            : 
     797         [ +  + ]:         73 :     for (size_t loc = 0; loc < ext_count; loc++) {
     798                 :         71 :         S2N_X509_CONST ASN1_OCTET_STRING *asn1_str = NULL;
     799                 :         71 :         bool match_found = false;
     800                 :            : 
     801                 :            :         /* Retrieve the x509 extension at location loc.
     802                 :            :          * X509_get_ext() retrieves extension loc from x.
     803                 :            :          * The index loc can take any value from 0 to X509_get_ext_count(x) - 1.
     804                 :            :          * The returned extension is an internal pointer which must not be freed up by the application.
     805                 :            :          * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext.html.
     806                 :            :          */
     807                 :         71 :         S2N_X509_CONST X509_EXTENSION *x509_ext = X509_get_ext(x509_cert, loc);
     808 [ -  + ][ #  # ]:         71 :         POSIX_ENSURE_REF(x509_ext);
     809                 :            : 
     810                 :            :         /* Retrieve the extension object/OID/extnId.
     811                 :            :          * X509_EXTENSION_get_object() returns the extension type of `x509_ext` as an ASN1_OBJECT pointer.
     812                 :            :          * The returned pointer is an internal value which must not be freed up.
     813                 :            :          * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_EXTENSION_get_object.html.
     814                 :            :          */
     815                 :         71 :         S2N_X509_CONST ASN1_OBJECT *asn1_obj = X509_EXTENSION_get_object(x509_ext);
     816 [ #  # ][ -  + ]:         71 :         POSIX_ENSURE_REF(asn1_obj);
     817                 :            : 
     818                 :            :         /* OBJ_cmp() compares two ASN1_OBJECT objects. If the two are identical 0 is returned.
     819                 :            :          * Ref: https://www.openssl.org/docs/man1.1.0/man3/OBJ_cmp.html.
     820                 :            :          */
     821                 :         71 :         match_found = (0 == OBJ_cmp(asn1_obj_in, asn1_obj));
     822                 :            : 
     823                 :            :         /* If match found, retrieve the corresponding OID value for the x509 extension */
     824         [ +  + ]:         71 :         if (match_found) {
     825                 :            :             /* X509_EXTENSION_get_data() returns the data of extension `x509_ext`.
     826                 :            :              * The returned pointer is an internal value which must not be freed up.
     827                 :            :              * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_EXTENSION_get_data.html.
     828                 :            :              */
     829                 :         15 :             asn1_str = X509_EXTENSION_get_data(x509_ext);
     830 [ #  # ][ -  + ]:         15 :             POSIX_ENSURE_REF(asn1_str);
     831                 :            :             /* ASN1_STRING_length() returns the length of the content of `asn1_str`.
     832                 :            :             * Ref: https://www.openssl.org/docs/man1.1.0/man3/ASN1_STRING_length.html.
     833                 :            :             */
     834                 :         15 :             int len = ASN1_STRING_length(asn1_str);
     835         [ +  + ]:         15 :             if (ext_value != NULL) {
     836 [ -  + ][ #  # ]:          8 :                 POSIX_ENSURE_GTE(len, 0);
     837 [ +  + ][ +  - ]:          8 :                 POSIX_ENSURE(*ext_value_len >= (uint32_t) len, S2N_ERR_INSUFFICIENT_MEM_SIZE);
     838                 :            :                 /* ASN1_STRING_get0_data(x) returns an internal pointer to the data of
     839                 :            :                  * x. Since this is an internal pointer it should not be freed or
     840                 :            :                  * modified in any way.
     841                 :            :                  * Ref: https://docs.openssl.org/master/man3/ASN1_STRING_length/
     842                 :            :                  */
     843                 :          7 :                 const unsigned char *internal_data = S2N_ASN1_STRING_DATA(asn1_str);
     844 [ #  # ][ -  + ]:          7 :                 POSIX_ENSURE_REF(internal_data);
     845 [ #  # ][ -  + ]:          7 :                 POSIX_CHECKED_MEMCPY(ext_value, internal_data, len);
                 [ +  - ]
     846                 :          7 :             }
     847         [ +  + ]:         14 :             if (critical != NULL) {
     848                 :            :                 /* Retrieve the x509 extension's critical value.
     849                 :            :                  * X509_EXTENSION_get_critical() returns the criticality of extension `x509_ext`,
     850                 :            :                  * it returns 1 for critical and 0 for non-critical.
     851                 :            :                  * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_EXTENSION_get_critical.html.
     852                 :            :                  */
     853                 :          7 :                 *critical = X509_EXTENSION_get_critical(x509_ext);
     854                 :          7 :             }
     855                 :         14 :             *ext_value_len = len;
     856                 :         14 :             return S2N_SUCCESS;
     857                 :         15 :         }
     858                 :         71 :     }
     859                 :            : 
     860         [ +  - ]:          2 :     POSIX_BAIL(S2N_ERR_X509_EXTENSION_VALUE_NOT_FOUND);
     861                 :          2 : }
     862                 :            : 
     863                 :            : int s2n_cert_get_x509_extension_value_length(struct s2n_cert *cert, const uint8_t *oid, uint32_t *ext_value_len)
     864                 :         11 : {
     865 [ +  + ][ +  - ]:         11 :     POSIX_ENSURE_REF(cert);
     866 [ +  + ][ +  - ]:         10 :     POSIX_ENSURE_REF(oid);
     867 [ +  + ][ +  - ]:          9 :     POSIX_ENSURE_REF(ext_value_len);
     868                 :            : 
     869         [ +  + ]:          8 :     POSIX_GUARD(s2n_parse_x509_extension(cert, oid, NULL, ext_value_len, NULL));
     870                 :            : 
     871                 :          7 :     return S2N_SUCCESS;
     872                 :          8 : }
     873                 :            : 
     874                 :            : int s2n_cert_get_x509_extension_value(struct s2n_cert *cert, const uint8_t *oid,
     875                 :            :         uint8_t *ext_value, uint32_t *ext_value_len, bool *critical)
     876                 :         14 : {
     877 [ +  - ][ +  + ]:         14 :     POSIX_ENSURE_REF(cert);
     878 [ +  + ][ +  - ]:         13 :     POSIX_ENSURE_REF(oid);
     879 [ +  - ][ +  + ]:         12 :     POSIX_ENSURE_REF(ext_value);
     880 [ +  + ][ +  - ]:         11 :     POSIX_ENSURE_REF(ext_value_len);
     881 [ +  + ][ +  - ]:         10 :     POSIX_ENSURE_REF(critical);
     882                 :            : 
     883         [ +  + ]:          9 :     POSIX_GUARD(s2n_parse_x509_extension(cert, oid, ext_value, ext_value_len, critical));
     884                 :            : 
     885                 :          7 :     return S2N_SUCCESS;
     886                 :          9 : }
     887                 :            : 
     888                 :            : /* Maximum buffer size for public key string:
     889                 :            :  * - RSA: "rsa" (3) + max digits for key size (5 for 65536) + null = 9 bytes
     890                 :            :  * - ECDSA: "ecdsa_secp521r1" (15) + null = 16 bytes
     891                 :            :  * - ML-DSA: "mldsa87" (7) + null = 8 bytes
     892                 :            :  * Maximum: 16 bytes
     893                 :            :  */
     894                 :            : #define S2N_PUBLIC_KEY_STRING_MAX_SIZE 16
     895                 :            : 
     896                 :            : S2N_RESULT s2n_cert_info_format_public_key_string(const struct s2n_cert_info *cert_info,
     897                 :            :         char *output, uint32_t output_size, uint32_t *required_size)
     898                 :        212 : {
     899 [ -  + ][ #  # ]:        212 :     RESULT_ENSURE_REF(cert_info);
     900 [ -  + ][ #  # ]:        212 :     RESULT_ENSURE_REF(required_size);
     901                 :            : 
     902                 :            :     /* Static NID-to-string lookup table for ECDSA and ML-DSA key types */
     903                 :        212 :     static const struct {
     904                 :        212 :         int nid;
     905                 :        212 :         const char *str;
     906                 :        212 :     } static_mappings[] = {
     907                 :        212 :         { NID_X9_62_prime256v1, "ecdsa_secp256r1" },
     908                 :        212 :         { NID_secp384r1, "ecdsa_secp384r1" },
     909                 :        212 :         { NID_secp521r1, "ecdsa_secp521r1" },
     910                 :        212 :         { S2N_NID_MLDSA44, "mldsa44" },
     911                 :        212 :         { S2N_NID_MLDSA65, "mldsa65" },
     912                 :        212 :         { S2N_NID_MLDSA87, "mldsa87" },
     913                 :        212 :     };
     914                 :            : 
     915                 :        212 :     const char *result_str = NULL;
     916                 :        212 :     uint32_t result_size = 0;
     917                 :        212 :     char rsa_buffer[S2N_PUBLIC_KEY_STRING_MAX_SIZE] = { 0 };
     918                 :            : 
     919                 :        212 :     int public_key_nid = cert_info->public_key_nid;
     920                 :            : 
     921                 :            :     /* RSA and RSA-PSS: dynamic format "rsa<bits>" */
     922 [ +  + ][ +  + ]:        212 :     if (public_key_nid == NID_rsaEncryption || public_key_nid == NID_rsassaPss) {
     923                 :        208 :         int written = snprintf(rsa_buffer, sizeof(rsa_buffer), "rsa%d", cert_info->public_key_bits);
     924 [ -  + ][ #  # ]:        208 :         RESULT_ENSURE_GT(written, 0);
     925 [ -  + ][ #  # ]:        208 :         RESULT_ENSURE_LT(written, (int) sizeof(rsa_buffer));
     926                 :        208 :         result_str = rsa_buffer;
     927                 :        208 :         result_size = (uint32_t) written + 1; /* +1 for null terminator */
     928                 :        208 :     } else {
     929                 :            :         /* ECDSA and ML-DSA: lookup by public_key_nid */
     930         [ +  - ]:          7 :         for (size_t i = 0; i < s2n_array_len(static_mappings); i++) {
     931 [ +  - ][ +  + ]:          7 :             if (public_key_nid != NID_undef && public_key_nid == static_mappings[i].nid) {
     932                 :          4 :                 result_str = static_mappings[i].str;
     933                 :          4 :                 result_size = strlen(result_str) + 1;
     934                 :          4 :                 break;
     935                 :          4 :             }
     936                 :          7 :         }
     937 [ #  # ][ -  + ]:          4 :         RESULT_ENSURE(result_str != NULL, S2N_ERR_CERT_TYPE_UNSUPPORTED);
     938                 :          4 :     }
     939                 :            : 
     940                 :            :     /* result_size includes the null terminator */
     941                 :        212 :     *required_size = result_size;
     942                 :            : 
     943                 :            :     /* Check if output buffer is provided and large enough */
     944 [ -  + ][ +  + ]:        212 :     if (output == NULL || output_size < result_size) {
     945         [ +  - ]:          1 :         RESULT_BAIL(S2N_ERR_INSUFFICIENT_MEM_SIZE);
     946                 :          1 :     }
     947                 :            : 
     948                 :            :     /* Copy the formatted string to output buffer (including null terminator) */
     949 [ -  + ][ #  # ]:        211 :     RESULT_CHECKED_MEMCPY(output, result_str, result_size);
                 [ +  - ]
     950                 :            : 
     951                 :        211 :     return S2N_RESULT_OK;
     952                 :        211 : }

Generated by: LCOV version 1.14