LCOV - code coverage report
Current view: top level - crypto - s2n_certificate.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 477 546 87.4 %
Date: 2026-07-04 07:27:58 Functions: 38 41 92.7 %
Branches: 316 658 48.0 %

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

Generated by: LCOV version 1.14