LCOV - code coverage report
Current view: top level - crypto - s2n_certificate.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 468 537 87.2 %
Date: 2025-08-15 07:28:39 Functions: 38 41 92.7 %
Branches: 306 622 49.2 %

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

Generated by: LCOV version 1.14