LCOV - code coverage report
Current view: top level - tls - s2n_x509_validator.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 590 634 93.1 %
Date: 2026-05-19 07:27:36 Functions: 36 38 94.7 %
Branches: 394 792 49.7 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License").
       5                 :            :  * You may not use this file except in compliance with the License.
       6                 :            :  * A copy of the License is located at
       7                 :            :  *
       8                 :            :  *  http://aws.amazon.com/apache2.0
       9                 :            :  *
      10                 :            :  * or in the "license" file accompanying this file. This file is distributed
      11                 :            :  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
      12                 :            :  * express or implied. See the License for the specific language governing
      13                 :            :  * permissions and limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <arpa/inet.h>
      17                 :            : #include <netinet/in.h>
      18                 :            : #include <openssl/asn1.h>
      19                 :            : #include <openssl/err.h>
      20                 :            : #include <openssl/x509.h>
      21                 :            : #include <sys/socket.h>
      22                 :            : 
      23                 :            : #include "crypto/s2n_libcrypto.h"
      24                 :            : #include "crypto/s2n_openssl_x509.h"
      25                 :            : #include "crypto/s2n_pkey.h"
      26                 :            : #include "tls/extensions/s2n_extension_list.h"
      27                 :            : #include "tls/s2n_config.h"
      28                 :            : #include "tls/s2n_connection.h"
      29                 :            : #include "tls/s2n_crl.h"
      30                 :            : #include "tls/s2n_security_policies.h"
      31                 :            : #include "utils/s2n_result.h"
      32                 :            : #include "utils/s2n_rfc5952.h"
      33                 :            : #include "utils/s2n_safety.h"
      34                 :            : 
      35                 :            : #if S2N_OCSP_STAPLING_SUPPORTED
      36                 :            :     #include <openssl/ocsp.h>
      37                 :            : DEFINE_POINTER_CLEANUP_FUNC(OCSP_RESPONSE *, OCSP_RESPONSE_free);
      38                 :            : DEFINE_POINTER_CLEANUP_FUNC(OCSP_BASICRESP *, OCSP_BASICRESP_free);
      39                 :            : 
      40                 :            : #endif
      41                 :            : 
      42                 :            : #ifndef X509_V_FLAG_PARTIAL_CHAIN
      43                 :            :     #define X509_V_FLAG_PARTIAL_CHAIN 0x80000
      44                 :            : #endif
      45                 :            : 
      46                 :    3561415 : #define DEFAULT_MAX_CHAIN_DEPTH 7
      47                 :            : /* Time used by default for nextUpdate if none provided in OCSP: 1 hour since thisUpdate. */
      48                 :            : #define DEFAULT_OCSP_NEXT_UPDATE_PERIOD 3600
      49                 :            : 
      50                 :            : /* s2n's internal clock measures epoch-nanoseconds stored with a uint64_t. The
      51                 :            :  * maximum representable timestamp is Sunday, July 21, 2554. time_t measures
      52                 :            :  * epoch-seconds in a int64_t or int32_t (platform dependent). If time_t is an
      53                 :            :  * int32_t, the maximum representable timestamp is January 19, 2038.
      54                 :            :  *
      55                 :            :  * This means that converting from the internal clock to a time_t is not safe,
      56                 :            :  * because the internal clock might hold a value that is too large to represent
      57                 :            :  * in a time_t. This constant represents the largest internal clock value that
      58                 :            :  * can be safely represented as a time_t.
      59                 :            :  */
      60                 :            : #define MAX_32_TIMESTAMP_NANOS 2147483647 * ONE_SEC_IN_NANOS
      61                 :            : 
      62                 :          0 : #define OSSL_VERIFY_CALLBACK_IGNORE_ERROR 1
      63                 :            : 
      64                 :        380 : DEFINE_POINTER_CLEANUP_FUNC(STACK_OF(X509_CRL) *, sk_X509_CRL_free);
      65                 :            : DEFINE_POINTER_CLEANUP_FUNC(STACK_OF(GENERAL_NAME) *, GENERAL_NAMES_free);
      66                 :            : 
      67                 :            : uint8_t s2n_x509_ocsp_stapling_supported(void)
      68                 :        314 : {
      69                 :        314 :     return S2N_OCSP_STAPLING_SUPPORTED;
      70                 :        314 : }
      71                 :            : 
      72                 :            : void s2n_x509_trust_store_init_empty(struct s2n_x509_trust_store *store)
      73                 :       3005 : {
      74                 :       3005 :     store->trust_store = NULL;
      75                 :       3005 : }
      76                 :            : 
      77                 :            : uint8_t s2n_x509_trust_store_has_certs(struct s2n_x509_trust_store *store)
      78                 :        417 : {
      79         [ +  + ]:        417 :     return store->trust_store ? (uint8_t) 1 : (uint8_t) 0;
      80                 :        417 : }
      81                 :            : 
      82                 :            : int s2n_x509_trust_store_add_pem(struct s2n_x509_trust_store *store, const char *pem)
      83                 :         56 : {
      84 [ -  + ][ #  # ]:         56 :     POSIX_ENSURE_REF(store);
      85 [ -  + ][ #  # ]:         56 :     POSIX_ENSURE_REF(pem);
      86                 :            : 
      87         [ +  + ]:         56 :     if (!store->trust_store) {
      88                 :         35 :         store->trust_store = X509_STORE_new();
      89 [ -  + ][ #  # ]:         35 :         POSIX_ENSURE_REF(store->trust_store);
      90                 :         35 :     }
      91                 :            : 
      92                 :         56 :     DEFER_CLEANUP(struct s2n_stuffer pem_in_stuffer = { 0 }, s2n_stuffer_free);
      93                 :         56 :     DEFER_CLEANUP(struct s2n_stuffer der_out_stuffer = { 0 }, s2n_stuffer_free);
      94                 :            : 
      95         [ -  + ]:         56 :     POSIX_GUARD(s2n_stuffer_alloc_ro_from_string(&pem_in_stuffer, pem));
      96         [ -  + ]:         56 :     POSIX_GUARD(s2n_stuffer_growable_alloc(&der_out_stuffer, 2048));
      97                 :            : 
      98                 :        274 :     do {
      99                 :        274 :         DEFER_CLEANUP(struct s2n_blob next_cert = { 0 }, s2n_free);
     100                 :            : 
     101         [ +  + ]:        274 :         POSIX_GUARD(s2n_stuffer_certificate_from_pem(&pem_in_stuffer, &der_out_stuffer));
     102         [ -  + ]:        273 :         POSIX_GUARD(s2n_alloc(&next_cert, s2n_stuffer_data_available(&der_out_stuffer)));
     103         [ -  + ]:        273 :         POSIX_GUARD(s2n_stuffer_read(&der_out_stuffer, &next_cert));
     104                 :            : 
     105                 :        273 :         const uint8_t *data = next_cert.data;
     106                 :        273 :         DEFER_CLEANUP(X509 *ca_cert = d2i_X509(NULL, &data, next_cert.size), X509_free_pointer);
     107 [ -  + ][ #  # ]:        273 :         S2N_ERROR_IF(ca_cert == NULL, S2N_ERR_DECODE_CERTIFICATE);
     108                 :            : 
     109         [ -  + ]:        273 :         if (!X509_STORE_add_cert(store->trust_store, ca_cert)) {
     110                 :          0 :             unsigned long error = ERR_get_error();
     111 [ #  # ][ #  # ]:          0 :             POSIX_ENSURE(ERR_GET_REASON(error) == X509_R_CERT_ALREADY_IN_HASH_TABLE, S2N_ERR_DECODE_CERTIFICATE);
     112                 :          0 :         }
     113         [ +  + ]:        273 :     } while (s2n_stuffer_data_available(&pem_in_stuffer));
     114                 :            : 
     115                 :         55 :     return 0;
     116                 :         56 : }
     117                 :            : 
     118                 :            : int s2n_x509_trust_store_from_ca_file(struct s2n_x509_trust_store *store, const char *ca_pem_filename, const char *ca_dir)
     119                 :        318 : {
     120         [ +  + ]:        318 :     if (!store->trust_store) {
     121                 :        107 :         store->trust_store = X509_STORE_new();
     122 [ #  # ][ -  + ]:        107 :         POSIX_ENSURE_REF(store->trust_store);
     123                 :        107 :     }
     124                 :            : 
     125                 :        318 :     int err_code = X509_STORE_load_locations(store->trust_store, ca_pem_filename, ca_dir);
     126         [ +  + ]:        318 :     if (!err_code) {
     127                 :          2 :         s2n_x509_trust_store_wipe(store);
     128         [ +  - ]:          2 :         POSIX_BAIL(S2N_ERR_X509_TRUST_STORE);
     129                 :          2 :     }
     130                 :            : 
     131                 :        316 :     return 0;
     132                 :        318 : }
     133                 :            : 
     134                 :            : void s2n_x509_trust_store_wipe(struct s2n_x509_trust_store *store)
     135                 :       3657 : {
     136         [ +  + ]:       3657 :     if (store->trust_store) {
     137                 :       2635 :         X509_STORE_free(store->trust_store);
     138                 :       2635 :         store->trust_store = NULL;
     139                 :       2635 :         store->loaded_system_certs = false;
     140                 :       2635 :     }
     141                 :       3657 : }
     142                 :            : 
     143                 :            : int s2n_x509_validator_init_no_x509_validation(struct s2n_x509_validator *validator)
     144                 :      10255 : {
     145 [ #  # ][ -  + ]:      10255 :     POSIX_ENSURE_REF(validator);
     146                 :      10255 :     validator->trust_store = NULL;
     147                 :      10255 :     validator->store_ctx = NULL;
     148                 :      10255 :     validator->skip_cert_validation = 1;
     149                 :      10255 :     validator->check_stapled_ocsp = 0;
     150                 :      10255 :     validator->max_chain_depth = DEFAULT_MAX_CHAIN_DEPTH;
     151                 :      10255 :     validator->state = INIT;
     152                 :      10255 :     validator->cert_chain_from_wire = sk_X509_new_null();
     153                 :      10255 :     validator->crl_lookup_list = NULL;
     154                 :      10255 :     validator->cert_validation_info = (struct s2n_cert_validation_info){ 0 };
     155                 :      10255 :     validator->cert_validation_cb_invoked = false;
     156                 :            : 
     157                 :      10255 :     return 0;
     158                 :      10255 : }
     159                 :            : 
     160                 :            : int s2n_x509_validator_init(struct s2n_x509_validator *validator, struct s2n_x509_trust_store *trust_store, uint8_t check_ocsp)
     161                 :    3551160 : {
     162 [ -  + ][ #  # ]:    3551160 :     POSIX_ENSURE_REF(trust_store);
     163                 :    3551160 :     validator->trust_store = trust_store;
     164                 :    3551160 :     validator->skip_cert_validation = 0;
     165                 :    3551160 :     validator->check_stapled_ocsp = check_ocsp;
     166                 :    3551160 :     validator->max_chain_depth = DEFAULT_MAX_CHAIN_DEPTH;
     167                 :    3551160 :     validator->store_ctx = NULL;
     168         [ +  + ]:    3551160 :     if (validator->trust_store->trust_store) {
     169                 :    3549839 :         validator->store_ctx = X509_STORE_CTX_new();
     170 [ -  + ][ #  # ]:    3549839 :         POSIX_ENSURE_REF(validator->store_ctx);
     171                 :    3549839 :     }
     172                 :    3551160 :     validator->cert_chain_from_wire = sk_X509_new_null();
     173                 :    3551160 :     validator->state = INIT;
     174                 :    3551160 :     validator->crl_lookup_list = NULL;
     175                 :    3551160 :     validator->cert_validation_info = (struct s2n_cert_validation_info){ 0 };
     176                 :    3551160 :     validator->cert_validation_cb_invoked = false;
     177                 :            : 
     178                 :    3551160 :     return 0;
     179                 :    3551160 : }
     180                 :            : 
     181                 :            : static inline void wipe_cert_chain(STACK_OF(X509) *cert_chain)
     182                 :    7236762 : {
     183         [ +  + ]:    7236762 :     if (cert_chain) {
     184                 :    3561415 :         sk_X509_pop_free(cert_chain, X509_free);
     185                 :    3561415 :     }
     186                 :    7236762 : }
     187                 :            : 
     188                 :            : int s2n_x509_validator_wipe(struct s2n_x509_validator *validator)
     189                 :    7236762 : {
     190         [ +  + ]:    7236762 :     if (validator->store_ctx) {
     191                 :    3549839 :         X509_STORE_CTX_free(validator->store_ctx);
     192                 :    3549839 :         validator->store_ctx = NULL;
     193                 :    3549839 :     }
     194                 :    7236762 :     wipe_cert_chain(validator->cert_chain_from_wire);
     195                 :    7236762 :     validator->cert_chain_from_wire = NULL;
     196                 :    7236762 :     validator->trust_store = NULL;
     197                 :    7236762 :     validator->skip_cert_validation = 0;
     198                 :    7236762 :     validator->state = UNINIT;
     199                 :    7236762 :     validator->max_chain_depth = 0;
     200         [ +  + ]:    7236762 :     if (validator->crl_lookup_list) {
     201         [ -  + ]:         17 :         POSIX_GUARD_RESULT(s2n_array_free(validator->crl_lookup_list));
     202                 :         17 :         validator->crl_lookup_list = NULL;
     203                 :         17 :     }
     204                 :            : 
     205                 :    7236762 :     return S2N_SUCCESS;
     206                 :    7236762 : }
     207                 :            : 
     208                 :            : int s2n_x509_validator_set_max_chain_depth(struct s2n_x509_validator *validator, uint16_t max_depth)
     209                 :          3 : {
     210 [ #  # ][ -  + ]:          3 :     POSIX_ENSURE_REF(validator);
     211 [ +  + ][ +  - ]:          3 :     S2N_ERROR_IF(max_depth == 0, S2N_ERR_INVALID_ARGUMENT);
     212                 :            : 
     213                 :          2 :     validator->max_chain_depth = max_depth;
     214                 :          2 :     return 0;
     215                 :          3 : }
     216                 :            : 
     217                 :            : static S2N_RESULT s2n_verify_host_information_san_entry(struct s2n_connection *conn, GENERAL_NAME *current_name, bool *san_found)
     218                 :        341 : {
     219 [ -  + ][ #  # ]:        341 :     RESULT_ENSURE_REF(conn);
     220 [ #  # ][ -  + ]:        341 :     RESULT_ENSURE_REF(current_name);
     221 [ -  + ][ #  # ]:        341 :     RESULT_ENSURE_REF(san_found);
     222                 :            : 
     223 [ +  + ][ +  + ]:        341 :     if (current_name->type == GEN_DNS || current_name->type == GEN_URI) {
     224                 :        339 :         *san_found = true;
     225                 :            : 
     226                 :        339 :         const char *name = (const char *) ASN1_STRING_data(current_name->d.ia5);
     227 [ -  + ][ #  # ]:        339 :         RESULT_ENSURE_REF(name);
     228                 :        339 :         int name_len = ASN1_STRING_length(current_name->d.ia5);
     229 [ -  + ][ #  # ]:        339 :         RESULT_ENSURE_GT(name_len, 0);
     230                 :            : 
     231 [ +  - ][ +  + ]:        339 :         RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
     232                 :            : 
     233                 :        325 :         return S2N_RESULT_OK;
     234                 :        339 :     }
     235                 :            : 
     236         [ +  + ]:          2 :     if (current_name->type == GEN_IPADD) {
     237                 :          1 :         *san_found = true;
     238                 :            : 
     239                 :            :         /* try to validate an IP address if it's in the subject alt name. */
     240                 :          1 :         const unsigned char *ip_addr = current_name->d.iPAddress->data;
     241 [ -  + ][ #  # ]:          1 :         RESULT_ENSURE_REF(ip_addr);
     242                 :          1 :         int ip_addr_len = current_name->d.iPAddress->length;
     243 [ -  + ][ #  # ]:          1 :         RESULT_ENSURE_GT(ip_addr_len, 0);
     244                 :            : 
     245 [ -  + ][ #  # ]:          2 :         RESULT_STACK_BLOB(address, INET6_ADDRSTRLEN + 1, INET6_ADDRSTRLEN + 1);
                 [ -  + ]
     246                 :            : 
     247         [ -  + ]:          1 :         if (ip_addr_len == 4) {
     248         [ #  # ]:          0 :             RESULT_GUARD(s2n_inet_ntop(AF_INET, ip_addr, &address));
     249         [ +  - ]:          1 :         } else if (ip_addr_len == 16) {
     250         [ -  + ]:          1 :             RESULT_GUARD(s2n_inet_ntop(AF_INET6, ip_addr, &address));
     251                 :          1 :         } else {
     252                 :            :             /* we aren't able to parse this value so skip it */
     253         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
     254                 :          0 :         }
     255                 :            : 
     256                 :            :         /* strlen should be safe here since we made sure we were null terminated AND that inet_ntop succeeded */
     257                 :          1 :         const char *name = (const char *) address.data;
     258                 :          1 :         size_t name_len = strlen(name);
     259                 :            : 
     260 [ #  # ][ -  + ]:          1 :         RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
     261                 :            : 
     262                 :          1 :         return S2N_RESULT_OK;
     263                 :          1 :     }
     264                 :            : 
     265                 :            :     /* we don't understand this entry type so skip it */
     266         [ +  - ]:          1 :     RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
     267                 :          1 : }
     268                 :            : 
     269                 :            : static S2N_RESULT s2n_verify_host_information_san(struct s2n_connection *conn, X509 *public_cert, bool *san_found)
     270                 :        394 : {
     271 [ #  # ][ -  + ]:        394 :     RESULT_ENSURE_REF(conn);
     272 [ -  + ][ #  # ]:        394 :     RESULT_ENSURE_REF(public_cert);
     273 [ -  + ][ #  # ]:        394 :     RESULT_ENSURE_REF(san_found);
     274                 :            : 
     275                 :        394 :     *san_found = false;
     276                 :            : 
     277                 :        394 :     DEFER_CLEANUP(STACK_OF(GENERAL_NAME) *names_list = NULL, GENERAL_NAMES_free_pointer);
     278                 :        394 :     names_list = X509_get_ext_d2i(public_cert, NID_subject_alt_name, NULL, NULL);
     279 [ +  - ][ +  + ]:        394 :     RESULT_ENSURE(names_list, S2N_ERR_CERT_UNTRUSTED);
     280                 :            : 
     281                 :        338 :     int n = sk_GENERAL_NAME_num(names_list);
     282 [ #  # ][ -  + ]:        338 :     RESULT_ENSURE(n > 0, S2N_ERR_CERT_UNTRUSTED);
     283                 :            : 
     284                 :        338 :     s2n_result result = S2N_RESULT_OK;
     285         [ +  + ]:        353 :     for (int i = 0; i < n; i++) {
     286                 :        341 :         GENERAL_NAME *current_name = sk_GENERAL_NAME_value(names_list, i);
     287                 :            : 
     288                 :            :         /* return success on the first entry that passes verification */
     289                 :        341 :         result = s2n_verify_host_information_san_entry(conn, current_name, san_found);
     290         [ +  + ]:        341 :         if (s2n_result_is_ok(result)) {
     291                 :        326 :             return S2N_RESULT_OK;
     292                 :        326 :         }
     293                 :        341 :     }
     294                 :            : 
     295                 :            :     /* if an error was set by one of the entries, then just propagate the error from the last SAN entry call */
     296         [ +  - ]:         12 :     RESULT_GUARD(result);
     297                 :            : 
     298         [ #  # ]:          0 :     RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
     299                 :          0 : }
     300                 :            : 
     301                 :            : static S2N_RESULT s2n_verify_host_information_common_name(struct s2n_connection *conn, X509 *public_cert, bool *cn_found)
     302                 :         57 : {
     303 [ -  + ][ #  # ]:         57 :     RESULT_ENSURE_REF(conn);
     304 [ -  + ][ #  # ]:         57 :     RESULT_ENSURE_REF(public_cert);
     305 [ #  # ][ -  + ]:         57 :     RESULT_ENSURE_REF(cn_found);
     306                 :            : 
     307                 :         57 :     X509_NAME *subject_name = X509_get_subject_name(public_cert);
     308 [ -  + ][ #  # ]:         57 :     RESULT_ENSURE(subject_name, S2N_ERR_CERT_UNTRUSTED);
     309                 :            : 
     310                 :         57 :     int curr_idx = -1;
     311                 :        113 :     while (true) {
     312                 :        113 :         int next_idx = X509_NAME_get_index_by_NID(subject_name, NID_commonName, curr_idx);
     313         [ +  + ]:        113 :         if (next_idx >= 0) {
     314                 :         56 :             curr_idx = next_idx;
     315                 :         57 :         } else {
     316                 :         57 :             break;
     317                 :         57 :         }
     318                 :        113 :     }
     319                 :            : 
     320 [ +  - ][ +  + ]:         57 :     RESULT_ENSURE(curr_idx >= 0, S2N_ERR_CERT_UNTRUSTED);
     321                 :            : 
     322                 :         56 :     ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name, curr_idx));
     323 [ -  + ][ #  # ]:         56 :     RESULT_ENSURE(common_name, S2N_ERR_CERT_UNTRUSTED);
     324                 :            : 
     325                 :            :     /* X520CommonName allows the following ANSI string types per RFC 5280 Appendix A.1 */
     326 [ #  # ][ -  + ]:         56 :     RESULT_ENSURE(ASN1_STRING_type(common_name) == V_ASN1_TELETEXSTRING
         [ #  # ][ -  + ]
         [ -  + ][ +  - ]
     327                 :         56 :                     || ASN1_STRING_type(common_name) == V_ASN1_PRINTABLESTRING
     328                 :         56 :                     || ASN1_STRING_type(common_name) == V_ASN1_UNIVERSALSTRING
     329                 :         56 :                     || ASN1_STRING_type(common_name) == V_ASN1_UTF8STRING
     330                 :         56 :                     || ASN1_STRING_type(common_name) == V_ASN1_BMPSTRING,
     331                 :         56 :             S2N_ERR_CERT_UNTRUSTED);
     332                 :            : 
     333                 :            :     /* at this point we have a valid CN value */
     334                 :         56 :     *cn_found = true;
     335                 :            : 
     336                 :         56 :     char peer_cn[255] = { 0 };
     337                 :         56 :     int cn_len = ASN1_STRING_length(common_name);
     338 [ -  + ][ #  # ]:         56 :     RESULT_ENSURE_GT(cn_len, 0);
     339                 :         56 :     uint32_t len = (uint32_t) cn_len;
     340 [ -  + ][ #  # ]:         56 :     RESULT_ENSURE_LTE(len, s2n_array_len(peer_cn) - 1);
     341 [ -  + ][ #  # ]:         56 :     RESULT_CHECKED_MEMCPY(peer_cn, ASN1_STRING_data(common_name), len);
                 [ +  - ]
     342                 :            : 
     343                 :            :     /* According to https://www.rfc-editor.org/rfc/rfc6125#section-6.4.4,
     344                 :            :      * the CN fallback only applies to fully qualified DNS domain names.
     345                 :            :      *
     346                 :            :      * An IP address is not a fully qualified DNS domain name. Per RFC 6125
     347                 :            :      * section 6.2.1, IP reference identities must only be matched against
     348                 :            :      * iPAddress SAN entries, never against CN values. Reject the CN if it
     349                 :            :      * parses as an IPv4 or IPv6 address.
     350                 :            :      */
     351                 :         56 :     unsigned char ip_buf[sizeof(struct in6_addr)] = { 0 };
     352 [ +  + ][ +  + ]:         56 :     if (inet_pton(AF_INET, peer_cn, ip_buf) == 1 || inet_pton(AF_INET6, peer_cn, ip_buf) == 1) {
     353         [ +  - ]:          2 :         RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
     354                 :          2 :     }
     355                 :            : 
     356 [ #  # ][ -  + ]:         54 :     RESULT_ENSURE(conn->verify_host_fn(peer_cn, len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
     357                 :            : 
     358                 :         54 :     return S2N_RESULT_OK;
     359                 :         54 : }
     360                 :            : 
     361                 :            : /*
     362                 :            :  * For each name in the cert. Iterate them. Call the callback. If one returns true, then consider it validated,
     363                 :            :  * if none of them return true, the cert is considered invalid.
     364                 :            :  */
     365                 :            : static S2N_RESULT s2n_verify_host_information(struct s2n_connection *conn, X509 *public_cert)
     366                 :        394 : {
     367                 :        394 :     bool entry_found = false;
     368                 :            : 
     369                 :            :     /* Check SubjectAltNames before CommonName as per RFC 6125 6.4.4 */
     370                 :        394 :     s2n_result result = s2n_verify_host_information_san(conn, public_cert, &entry_found);
     371                 :            : 
     372                 :            :     /*
     373                 :            :      *= https://www.rfc-editor.org/rfc/rfc6125#section-6.4.4
     374                 :            :      *# As noted, a client MUST NOT seek a match for a reference identifier
     375                 :            :      *# of CN-ID if the presented identifiers include a DNS-ID, SRV-ID,
     376                 :            :      *# URI-ID, or any application-specific identifier types supported by the
     377                 :            :      *# client.
     378                 :            :      */
     379         [ +  + ]:        394 :     if (entry_found) {
     380                 :        337 :         return result;
     381                 :        337 :     }
     382                 :            : 
     383                 :            :     /*
     384                 :            :      *= https://www.rfc-editor.org/rfc/rfc6125#section-6.4.4
     385                 :            :      *# Therefore, if and only if the presented identifiers do not include a
     386                 :            :      *# DNS-ID, SRV-ID, URI-ID, or any application-specific identifier types
     387                 :            :      *# supported by the client, then the client MAY as a last resort check
     388                 :            :      *# for a string whose form matches that of a fully qualified DNS domain
     389                 :            :      *# name in a Common Name field of the subject field (i.e., a CN-ID).
     390                 :            :      */
     391                 :         57 :     result = s2n_verify_host_information_common_name(conn, public_cert, &entry_found);
     392         [ +  + ]:         57 :     if (entry_found) {
     393                 :         56 :         return result;
     394                 :         56 :     }
     395                 :            : 
     396                 :            :     /* make a null-terminated string in case the callback tries to use strlen */
     397                 :          1 :     const char *name = "";
     398                 :          1 :     size_t name_len = 0;
     399                 :            : 
     400                 :            :     /* at this point, we don't have anything to identify the certificate with so pass an empty string to the callback */
     401 [ #  # ][ -  + ]:          1 :     RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
     402                 :            : 
     403                 :          1 :     return S2N_RESULT_OK;
     404                 :          1 : }
     405                 :            : 
     406                 :            : S2N_RESULT s2n_x509_validator_read_asn1_cert(struct s2n_stuffer *cert_chain_in_stuffer,
     407                 :            :         struct s2n_blob *asn1_cert)
     408                 :      15564 : {
     409                 :      15564 :     uint32_t certificate_size = 0;
     410                 :            : 
     411         [ -  + ]:      15564 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint24(cert_chain_in_stuffer, &certificate_size));
     412 [ +  + ][ +  - ]:      15564 :     RESULT_ENSURE(certificate_size > 0, S2N_ERR_CERT_INVALID);
     413 [ +  - ][ +  + ]:      15560 :     RESULT_ENSURE(certificate_size <= s2n_stuffer_data_available(cert_chain_in_stuffer), S2N_ERR_CERT_INVALID);
     414                 :            : 
     415                 :      15556 :     asn1_cert->size = certificate_size;
     416                 :      15556 :     asn1_cert->data = s2n_stuffer_raw_read(cert_chain_in_stuffer, certificate_size);
     417 [ -  + ][ #  # ]:      15556 :     RESULT_ENSURE_REF(asn1_cert->data);
     418                 :            : 
     419                 :      15556 :     return S2N_RESULT_OK;
     420                 :      15556 : }
     421                 :            : 
     422                 :            : /**
     423                 :            : * Validates that each certificate in a peer's cert chain contains only signature algorithms in a security policy's
     424                 :            : * certificate_signatures_preference list.
     425                 :            : */
     426                 :            : S2N_RESULT s2n_x509_validator_check_cert_preferences(struct s2n_connection *conn, X509 *cert)
     427                 :        887 : {
     428 [ #  # ][ -  + ]:        887 :     RESULT_ENSURE_REF(conn);
     429 [ -  + ][ #  # ]:        887 :     RESULT_ENSURE_REF(cert);
     430                 :            : 
     431                 :        887 :     const struct s2n_security_policy *security_policy = NULL;
     432         [ -  + ]:        887 :     RESULT_GUARD_POSIX(s2n_connection_get_security_policy(conn, &security_policy));
     433                 :            : 
     434                 :            :     /**
     435                 :            :      * We only restrict the signature algorithm on the certificates in the
     436                 :            :      * peer's certificate chain if the certificate_signature_preferences field
     437                 :            :      * is set in the security policy. This is contrary to the RFC, which
     438                 :            :      * specifies that the signatures in the "signature_algorithms" extension
     439                 :            :      * apply to signatures in the certificate chain in certain scenarios, so RFC
     440                 :            :      * compliance would imply validating that the certificate chain signature
     441                 :            :      * algorithm matches one of the algorithms specified in the
     442                 :            :      * "signature_algorithms" extension.
     443                 :            :      *
     444                 :            :      *= https://www.rfc-editor.org/rfc/rfc5246#section-7.4.2
     445                 :            :      *= type=exception
     446                 :            :      *= reason=not implemented due to lack of utility
     447                 :            :      *# If the client provided a "signature_algorithms" extension, then all
     448                 :            :      *# certificates provided by the server MUST be signed by a
     449                 :            :      *# hash/signature algorithm pair that appears in that extension.
     450                 :            :      *
     451                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.3
     452                 :            :      *= type=exception
     453                 :            :      *= reason=not implemented due to lack of utility
     454                 :            :      *# If no "signature_algorithms_cert" extension is present, then the
     455                 :            :      *# "signature_algorithms" extension also applies to signatures appearing in
     456                 :            :      *# certificates.
     457                 :            :      */
     458                 :        887 :     struct s2n_cert_info info = { 0 };
     459         [ -  + ]:        887 :     RESULT_GUARD(s2n_openssl_x509_get_cert_info(cert, &info));
     460                 :            : 
     461         [ +  + ]:        887 :     bool certificate_preferences_defined = security_policy->certificate_signature_preferences != NULL
     462         [ -  + ]:        887 :             || security_policy->certificate_key_preferences != NULL;
     463 [ +  + ][ +  + ]:        887 :     if (certificate_preferences_defined && !info.self_signed && conn->actual_protocol_version == S2N_TLS13) {
                 [ +  + ]
     464                 :            :         /* Ensure that the certificate signature does not use SHA-1. While this check
     465                 :            :          * would ideally apply to all connections, we only enforce it when certificate
     466                 :            :          * preferences exist to stay backwards compatible.
     467                 :            :          */
     468 [ +  - ][ +  + ]:         96 :         RESULT_ENSURE(info.signature_digest_nid != NID_sha1, S2N_ERR_CERT_UNTRUSTED);
     469                 :         96 :     }
     470                 :            : 
     471         [ +  + ]:        884 :     if (!info.self_signed) {
     472         [ +  + ]:        636 :         RESULT_GUARD(s2n_security_policy_validate_cert_signature(security_policy, &info, S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT));
     473                 :        636 :     }
     474         [ +  + ]:        883 :     RESULT_GUARD(s2n_security_policy_validate_cert_key(security_policy, &info, S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT));
     475                 :            : 
     476                 :        882 :     return S2N_RESULT_OK;
     477                 :        883 : }
     478                 :            : 
     479                 :            : S2N_RESULT s2n_x509_validator_get_validated_cert_chain(const struct s2n_x509_validator *validator,
     480                 :            :         struct s2n_validated_cert_chain *validated_cert_chain)
     481                 :        711 : {
     482 [ #  # ][ -  + ]:        711 :     RESULT_ENSURE_REF(validator);
     483 [ #  # ][ -  + ]:        711 :     RESULT_ENSURE_REF(validated_cert_chain);
     484                 :            : 
     485 [ +  - ][ +  + ]:        711 :     RESULT_ENSURE(s2n_x509_validator_is_cert_chain_validated(validator), S2N_ERR_INVALID_CERT_STATE);
     486 [ #  # ][ -  + ]:        710 :     RESULT_ENSURE_REF(validator->store_ctx);
     487                 :            : 
     488                 :        710 : #if S2N_LIBCRYPTO_SUPPORTS_GET0_CHAIN
     489                 :            :     /* X509_STORE_CTX_get0_chain is used when available, since it returns a pointer to the
     490                 :            :      * validated cert chain in the X509_STORE_CTX, avoiding an allocation/copy.
     491                 :            :      */
     492                 :        710 :     validated_cert_chain->stack = X509_STORE_CTX_get0_chain(validator->store_ctx);
     493                 :            : #else
     494                 :            :     /* Otherwise, X509_STORE_CTX_get1_chain is used instead, which allocates a new cert chain. */
     495                 :            :     validated_cert_chain->stack = X509_STORE_CTX_get1_chain(validator->store_ctx);
     496                 :            : #endif
     497                 :            : 
     498 [ #  # ][ -  + ]:        710 :     RESULT_ENSURE_REF(validated_cert_chain->stack);
     499                 :            : 
     500                 :        710 :     return S2N_RESULT_OK;
     501                 :        710 : }
     502                 :            : 
     503                 :            : S2N_CLEANUP_RESULT s2n_x509_validator_validated_cert_chain_free(struct s2n_validated_cert_chain *validated_cert_chain)
     504                 :        710 : {
     505 [ -  + ][ #  # ]:        710 :     RESULT_ENSURE_REF(validated_cert_chain);
     506                 :            : 
     507                 :            : #if !S2N_LIBCRYPTO_SUPPORTS_GET0_CHAIN
     508                 :            :     /* When X509_STORE_CTX_get0_chain isn't supported, X509_STORE_CTX_get1_chain is used instead,
     509                 :            :      * which allocates a new cert chain that is owned by s2n-tls and MUST be freed.
     510                 :            :      *
     511                 :            :      * X509_STORE_CTX_get0_chain returns a pointer to the cert chain within the X509_STORE_CTX,
     512                 :            :      * which is NOT owned by s2n-tls and MUST NOT be manually freed.
     513                 :            :      */
     514                 :            :     RESULT_GUARD(s2n_openssl_x509_stack_pop_free(&validated_cert_chain->stack));
     515                 :            : #endif
     516                 :            : 
     517                 :            :     /* Even though the cert chain reference is still valid in the case that get0_chain is used, set
     518                 :            :      * it to null for consistency with the get1_chain case.
     519                 :            :      */
     520                 :        710 :     validated_cert_chain->stack = NULL;
     521                 :            : 
     522                 :        710 :     return S2N_RESULT_OK;
     523                 :        710 : }
     524                 :            : 
     525                 :            : /* Validates that the root certificate uses a key allowed by the security policy
     526                 :            :  * certificate preferences.
     527                 :            :  */
     528                 :            : static S2N_RESULT s2n_x509_validator_check_root_cert(struct s2n_x509_validator *validator, struct s2n_connection *conn)
     529                 :        335 : {
     530 [ -  + ][ #  # ]:        335 :     RESULT_ENSURE_REF(validator);
     531 [ #  # ][ -  + ]:        335 :     RESULT_ENSURE_REF(conn);
     532                 :            : 
     533                 :        335 :     const struct s2n_security_policy *security_policy = NULL;
     534         [ -  + ]:        335 :     RESULT_GUARD_POSIX(s2n_connection_get_security_policy(conn, &security_policy));
     535 [ -  + ][ #  # ]:        335 :     RESULT_ENSURE_REF(security_policy);
     536                 :            : 
     537                 :        335 :     DEFER_CLEANUP(struct s2n_validated_cert_chain validated_cert_chain = { 0 }, s2n_x509_validator_validated_cert_chain_free);
     538         [ -  + ]:        335 :     RESULT_GUARD(s2n_x509_validator_get_validated_cert_chain(validator, &validated_cert_chain));
     539                 :        335 :     STACK_OF(X509) *cert_chain = validated_cert_chain.stack;
     540 [ -  + ][ #  # ]:        335 :     RESULT_ENSURE_REF(cert_chain);
     541                 :            : 
     542                 :        335 :     const int certs_in_chain = sk_X509_num(cert_chain);
     543 [ -  + ][ #  # ]:        335 :     RESULT_ENSURE(certs_in_chain > 0, S2N_ERR_CERT_UNTRUSTED);
     544                 :        335 :     X509 *root = sk_X509_value(cert_chain, certs_in_chain - 1);
     545 [ #  # ][ -  + ]:        335 :     RESULT_ENSURE_REF(root);
     546                 :            : 
     547                 :        335 :     struct s2n_cert_info info = { 0 };
     548         [ -  + ]:        335 :     RESULT_GUARD(s2n_openssl_x509_get_cert_info(root, &info));
     549                 :            : 
     550         [ +  + ]:        335 :     RESULT_GUARD(s2n_security_policy_validate_cert_key(security_policy, &info,
     551                 :        334 :             S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT));
     552                 :            : 
     553                 :        334 :     return S2N_RESULT_OK;
     554                 :        335 : }
     555                 :            : 
     556                 :            : static S2N_RESULT s2n_x509_validator_read_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn,
     557                 :            :         uint8_t *cert_chain_in, uint32_t cert_chain_len)
     558                 :       4957 : {
     559 [ +  - ][ +  + ]:       4957 :     RESULT_ENSURE(validator->skip_cert_validation || s2n_x509_trust_store_has_certs(validator->trust_store), S2N_ERR_CERT_UNTRUSTED);
                 [ +  + ]
     560 [ -  + ][ #  # ]:       4954 :     RESULT_ENSURE(validator->state == INIT, S2N_ERR_INVALID_CERT_STATE);
     561                 :            : 
     562                 :       4954 :     struct s2n_blob cert_chain_blob = { 0 };
     563         [ -  + ]:       4954 :     RESULT_GUARD_POSIX(s2n_blob_init(&cert_chain_blob, cert_chain_in, cert_chain_len));
     564                 :       4954 :     DEFER_CLEANUP(struct s2n_stuffer cert_chain_in_stuffer = { 0 }, s2n_stuffer_free);
     565                 :            : 
     566         [ -  + ]:       4954 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&cert_chain_in_stuffer, &cert_chain_blob));
     567         [ -  + ]:       4954 :     RESULT_GUARD_POSIX(s2n_stuffer_write(&cert_chain_in_stuffer, &cert_chain_blob));
     568                 :            : 
     569         [ +  + ]:      18010 :     while (s2n_stuffer_data_available(&cert_chain_in_stuffer)
     570         [ +  + ]:      18010 :             && sk_X509_num(validator->cert_chain_from_wire) < validator->max_chain_depth) {
     571                 :      13068 :         struct s2n_blob asn1_cert = { 0 };
     572         [ +  + ]:      13068 :         RESULT_GUARD(s2n_x509_validator_read_asn1_cert(&cert_chain_in_stuffer, &asn1_cert));
     573                 :            : 
     574                 :            :         /* We only do the trailing byte validation when parsing the leaf cert to
     575                 :            :          * match historical s2n-tls behavior.
     576                 :            :          */
     577                 :      13060 :         DEFER_CLEANUP(X509 *cert = NULL, X509_free_pointer);
     578         [ +  + ]:      13060 :         if (sk_X509_num(validator->cert_chain_from_wire) == 0) {
     579         [ +  + ]:       4946 :             RESULT_GUARD(s2n_openssl_x509_parse(&asn1_cert, &cert));
     580                 :       8114 :         } else {
     581         [ -  + ]:       8114 :             RESULT_GUARD(s2n_openssl_x509_parse_without_length_validation(&asn1_cert, &cert));
     582                 :       8114 :         }
     583                 :            : 
     584         [ +  + ]:      13058 :         if (!validator->skip_cert_validation) {
     585         [ +  + ]:        881 :             RESULT_GUARD(s2n_x509_validator_check_cert_preferences(conn, cert));
     586                 :        881 :         }
     587                 :            : 
     588                 :            :         /* add the cert to the chain */
     589 [ #  # ][ -  + ]:      13056 :         RESULT_ENSURE(sk_X509_push(validator->cert_chain_from_wire, cert) > 0,
     590                 :      13056 :                 S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
     591                 :            : 
     592                 :            :         /* After the cert is added to cert_chain_from_wire, it will be freed
     593                 :            :          * with the call to s2n_x509_validator_wipe. We disable the cleanup
     594                 :            :          * function since cleanup is no longer "owned" by cert.
     595                 :            :          */
     596                 :      13056 :         ZERO_TO_DISABLE_DEFER_CLEANUP(cert);
     597                 :            : 
     598                 :            :         /* certificate extensions is a field in TLS 1.3 - https://tools.ietf.org/html/rfc8446#section-4.4.2 */
     599         [ +  + ]:      13056 :         if (conn->actual_protocol_version >= S2N_TLS13) {
     600                 :       6427 :             s2n_parsed_extensions_list parsed_extensions_list = { 0 };
     601         [ -  + ]:       6427 :             RESULT_GUARD_POSIX(s2n_extension_list_parse(&cert_chain_in_stuffer, &parsed_extensions_list));
     602                 :       6427 :         }
     603                 :      13056 :     }
     604                 :            : 
     605                 :            :     /* if this occurred we exceeded validator->max_chain_depth */
     606 [ +  - ][ +  + ]:       4942 :     RESULT_ENSURE(validator->skip_cert_validation || s2n_stuffer_data_available(&cert_chain_in_stuffer) == 0,
                 [ +  + ]
     607                 :       4941 :             S2N_ERR_CERT_MAX_CHAIN_DEPTH_EXCEEDED);
     608 [ +  - ][ +  + ]:       4941 :     RESULT_ENSURE(sk_X509_num(validator->cert_chain_from_wire) > 0, S2N_ERR_NO_CERT_FOUND);
     609                 :            : 
     610                 :       4940 :     return S2N_RESULT_OK;
     611                 :       4941 : }
     612                 :            : 
     613                 :            : static S2N_RESULT s2n_x509_validator_process_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn,
     614                 :            :         uint8_t *cert_chain_in, uint32_t cert_chain_len)
     615                 :       4957 : {
     616 [ #  # ][ -  + ]:       4957 :     RESULT_ENSURE(validator->state == INIT, S2N_ERR_INVALID_CERT_STATE);
     617                 :            : 
     618         [ +  + ]:       4957 :     RESULT_GUARD(s2n_x509_validator_read_cert_chain(validator, conn, cert_chain_in, cert_chain_len));
     619                 :            : 
     620         [ +  + ]:       4940 :     if (validator->skip_cert_validation) {
     621                 :       4546 :         return S2N_RESULT_OK;
     622                 :       4546 :     }
     623                 :            : 
     624                 :        394 :     X509 *leaf = sk_X509_value(validator->cert_chain_from_wire, 0);
     625 [ #  # ][ -  + ]:        394 :     RESULT_ENSURE_REF(leaf);
     626                 :            : 
     627         [ +  - ]:        394 :     if (conn->verify_host_fn) {
     628         [ +  + ]:        394 :         RESULT_GUARD(s2n_verify_host_information(conn, leaf));
     629                 :        394 :     }
     630                 :            : 
     631 [ #  # ][ -  + ]:        381 :     RESULT_GUARD_OSSL(X509_STORE_CTX_init(validator->store_ctx, validator->trust_store->trust_store, leaf,
     632                 :        381 :                               validator->cert_chain_from_wire),
     633                 :        381 :             S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
     634                 :            : 
     635         [ +  + ]:        381 :     if (conn->config->crl_lookup_cb) {
     636         [ +  + ]:         17 :         RESULT_GUARD(s2n_crl_invoke_lookup_callbacks(conn, validator));
     637         [ +  + ]:         16 :         RESULT_GUARD(s2n_crl_handle_lookup_callback_result(validator));
     638                 :         16 :     }
     639                 :            : 
     640                 :        379 :     validator->state = READY_TO_VERIFY;
     641                 :            : 
     642                 :        379 :     return S2N_RESULT_OK;
     643                 :        381 : }
     644                 :            : 
     645                 :            : static S2N_RESULT s2n_x509_validator_set_no_check_time_flag(struct s2n_x509_validator *validator)
     646                 :          8 : {
     647 [ -  + ][ #  # ]:          8 :     RESULT_ENSURE_REF(validator);
     648 [ #  # ][ -  + ]:          8 :     RESULT_ENSURE_REF(validator->store_ctx);
     649                 :            : 
     650                 :          8 :     X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(validator->store_ctx);
     651 [ -  + ][ #  # ]:          8 :     RESULT_ENSURE_REF(param);
     652                 :            : 
     653                 :          8 : #ifdef S2N_LIBCRYPTO_SUPPORTS_FLAG_NO_CHECK_TIME
     654 [ -  + ][ #  # ]:          8 :     RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_NO_CHECK_TIME),
     655                 :          8 :             S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
     656                 :            : #else
     657                 :            :     RESULT_BAIL(S2N_ERR_UNIMPLEMENTED);
     658                 :            : #endif
     659                 :            : 
     660                 :          8 :     return S2N_RESULT_OK;
     661                 :          8 : }
     662                 :            : 
     663                 :            : int s2n_disable_time_validation_ossl_verify_callback(int default_ossl_ret, X509_STORE_CTX *ctx)
     664                 :          0 : {
     665                 :          0 :     int err = X509_STORE_CTX_get_error(ctx);
     666                 :          0 :     switch (err) {
     667         [ #  # ]:          0 :         case X509_V_ERR_CERT_NOT_YET_VALID:
     668         [ #  # ]:          0 :         case X509_V_ERR_CERT_HAS_EXPIRED:
     669                 :          0 :             return OSSL_VERIFY_CALLBACK_IGNORE_ERROR;
     670         [ #  # ]:          0 :         default:
     671                 :          0 :             break;
     672                 :          0 :     }
     673                 :            : 
     674                 :            :     /* If CRL validation is enabled, setting the time validation verify callback will override the
     675                 :            :      * CRL verify callback. The CRL verify callback is manually triggered to work around this
     676                 :            :      * issue.
     677                 :            :      *
     678                 :            :      * The CRL verify callback ignores validation errors exclusively for CRL timestamp fields. So,
     679                 :            :      * if CRL validation isn't enabled, the CRL verify callback is a no-op.
     680                 :            :      */
     681                 :          0 :     return s2n_crl_ossl_verify_callback(default_ossl_ret, ctx);
     682                 :          0 : }
     683                 :            : 
     684                 :            : static S2N_RESULT s2n_x509_validator_disable_time_validation(struct s2n_connection *conn,
     685                 :            :         struct s2n_x509_validator *validator)
     686                 :          8 : {
     687 [ #  # ][ -  + ]:          8 :     RESULT_ENSURE_REF(conn);
     688 [ -  + ][ #  # ]:          8 :     RESULT_ENSURE_REF(conn->config);
     689 [ -  + ][ #  # ]:          8 :     RESULT_ENSURE_REF(validator);
     690 [ #  # ][ -  + ]:          8 :     RESULT_ENSURE_REF(validator->store_ctx);
     691                 :            : 
     692                 :            :     /* Setting an X509_STORE verify callback is not recommended with AWS-LC:
     693                 :            :      * https://github.com/aws/aws-lc/blob/aa90e509f2e940916fbe9fdd469a4c90c51824f6/include/openssl/x509.h#L2980-L2990
     694                 :            :      *
     695                 :            :      * If the libcrypto supports the ability to disable time validation with an X509_VERIFY_PARAM
     696                 :            :      * NO_CHECK_TIME flag, this method is preferred.
     697                 :            :      *
     698                 :            :      * However, older versions of AWS-LC and OpenSSL 1.0.2 do not support this flag. In this case,
     699                 :            :      * an X509_STORE verify callback is used. This is acceptable in older versions of AWS-LC
     700                 :            :      * because the versions are fixed, and updates to AWS-LC will not break the callback
     701                 :            :      * implementation.
     702                 :            :      */
     703         [ +  - ]:          8 :     if (s2n_libcrypto_supports_flag_no_check_time()) {
     704         [ -  + ]:          8 :         RESULT_GUARD(s2n_x509_validator_set_no_check_time_flag(validator));
     705                 :          8 :     } else {
     706                 :          0 :         X509_STORE_CTX_set_verify_cb(validator->store_ctx,
     707                 :          0 :                 s2n_disable_time_validation_ossl_verify_callback);
     708                 :          0 :     }
     709                 :            : 
     710                 :          8 :     return S2N_RESULT_OK;
     711                 :          8 : }
     712                 :            : 
     713                 :            : int s2n_no_op_verify_custom_crit_oids_cb(X509_STORE_CTX *ctx, X509 *x509, STACK_OF(ASN1_OBJECT) *oids)
     714                 :          0 : {
     715                 :          0 :     return 1;
     716                 :          0 : }
     717                 :            : 
     718                 :            : static S2N_RESULT s2n_x509_validator_add_custom_extensions(struct s2n_x509_validator *validator, struct s2n_connection *conn)
     719                 :        380 : {
     720 [ -  + ][ #  # ]:        380 :     RESULT_ENSURE_REF(validator);
     721 [ -  + ][ #  # ]:        380 :     RESULT_ENSURE_REF(validator->store_ctx);
     722 [ #  # ][ -  + ]:        380 :     RESULT_ENSURE_REF(conn);
     723 [ -  + ][ #  # ]:        380 :     RESULT_ENSURE_REF(conn->config);
     724                 :            : 
     725         [ -  + ]:        380 :     if (conn->config->custom_x509_extension_oids) {
     726                 :            : #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_OID
     727                 :            :         size_t custom_oid_count = sk_ASN1_OBJECT_num(conn->config->custom_x509_extension_oids);
     728                 :            :         for (size_t i = 0; i < custom_oid_count; i++) {
     729                 :            :             ASN1_OBJECT *critical_oid = sk_ASN1_OBJECT_value(conn->config->custom_x509_extension_oids, i);
     730                 :            :             RESULT_ENSURE_REF(critical_oid);
     731                 :            :             RESULT_GUARD_OSSL(X509_STORE_CTX_add_custom_crit_oid(validator->store_ctx, critical_oid),
     732                 :            :                     S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
     733                 :            :         }
     734                 :            :         /* To enable AWS-LC accepting custom extensions, an X509_STORE_CTX_verify_crit_oids_cb must be set.
     735                 :            :          * See https://github.com/aws/aws-lc/blob/f0b4afedd7d45fc2517643d890b654856c57f994/include/openssl/x509.h#L2913-L2918.
     736                 :            :          * 
     737                 :            :          * The `X509_STORE_CTX_verify_crit_oids_cb` callback can be used to implement the validation for the
     738                 :            :          * custom certificate extensions. However, s2n-tls consumers are expected to implement this validation
     739                 :            :          * in the `s2n_cert_validation_callback` instead. So, a no-op callback is provided to AWS-LC.
     740                 :            :          */
     741                 :            :         X509_STORE_CTX_set_verify_crit_oids(validator->store_ctx, s2n_no_op_verify_custom_crit_oids_cb);
     742                 :            : #else
     743         [ #  # ]:          0 :         RESULT_BAIL(S2N_ERR_UNIMPLEMENTED);
     744                 :          0 : #endif
     745                 :          0 :     }
     746                 :        380 :     return S2N_RESULT_OK;
     747                 :        380 : }
     748                 :            : 
     749                 :            : static S2N_RESULT s2n_x509_validator_verify_intent_for_cert(struct s2n_connection *conn, X509 *cert, bool is_leaf)
     750                 :        307 : {
     751 [ -  + ][ #  # ]:        307 :     RESULT_ENSURE_REF(cert);
     752                 :            : 
     753                 :            :     /* The X509_PURPOSE values indicate the purpose that certificates must specify. For servers,
     754                 :            :      * received client certificates MUST have a TLS client purpose. For clients, received server
     755                 :            :      * certificates MUST have a TLS server purpose.
     756                 :            :      */
     757                 :        307 :     int purpose = X509_PURPOSE_SSL_CLIENT;
     758         [ +  + ]:        307 :     if (conn->mode == S2N_CLIENT) {
     759                 :        222 :         purpose = X509_PURPOSE_SSL_SERVER;
     760                 :        222 :     }
     761                 :            : 
     762 [ +  + ][ +  - ]:        307 :     RESULT_GUARD_OSSL(X509_check_purpose(cert, purpose, !is_leaf), S2N_ERR_CERT_INTENT_INVALID);
     763                 :            : 
     764                 :        288 :     return S2N_RESULT_OK;
     765                 :        307 : }
     766                 :            : 
     767                 :            : S2N_RESULT s2n_x509_validator_verify_intent(struct s2n_x509_validator *validator, struct s2n_connection *conn)
     768                 :        354 : {
     769 [ -  + ][ #  # ]:        354 :     RESULT_ENSURE_REF(conn);
     770 [ -  + ][ #  # ]:        354 :     RESULT_ENSURE_REF(conn->config);
     771                 :            : 
     772         [ +  + ]:        354 :     if (conn->config->disable_x509_intent_verification) {
     773                 :         46 :         return S2N_RESULT_OK;
     774                 :         46 :     }
     775                 :            : 
     776                 :        308 :     DEFER_CLEANUP(struct s2n_validated_cert_chain validated_cert_chain = { 0 }, s2n_x509_validator_validated_cert_chain_free);
     777         [ -  + ]:        308 :     RESULT_GUARD(s2n_x509_validator_get_validated_cert_chain(validator, &validated_cert_chain));
     778                 :            : 
     779                 :        308 :     int cert_count = sk_X509_num(validated_cert_chain.stack);
     780 [ #  # ][ -  + ]:        308 :     RESULT_ENSURE_GT(cert_count, 0);
     781                 :            : 
     782                 :            :     /* The validated cert chain returned from the libcrypto includes the trust anchor. The trust
     783                 :            :      * anchor is omitted from intent verification since its TLS intent is implicitly indicated by
     784                 :            :      * its presence in the s2n-tls trust store.
     785                 :            :      */
     786                 :        308 :     cert_count -= 1;
     787                 :            : 
     788         [ +  + ]:        596 :     for (int i = 0; i < cert_count; i++) {
     789                 :        307 :         X509 *cert = sk_X509_value(validated_cert_chain.stack, i);
     790 [ -  + ][ #  # ]:        307 :         RESULT_ENSURE_REF(cert);
     791                 :            : 
     792                 :        307 :         bool is_leaf = (i == 0);
     793         [ +  + ]:        307 :         RESULT_GUARD(s2n_x509_validator_verify_intent_for_cert(conn, cert, is_leaf));
     794                 :        307 :     }
     795                 :            : 
     796                 :        289 :     return S2N_RESULT_OK;
     797                 :        308 : }
     798                 :            : 
     799                 :            : static S2N_RESULT s2n_x509_validator_verify_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn)
     800                 :        380 : {
     801 [ -  + ][ #  # ]:        380 :     RESULT_ENSURE(validator->state == READY_TO_VERIFY, S2N_ERR_INVALID_CERT_STATE);
     802                 :            : 
     803                 :        380 :     X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(validator->store_ctx);
     804                 :        380 :     X509_VERIFY_PARAM_set_depth(param, validator->max_chain_depth);
     805                 :            : 
     806                 :        380 :     DEFER_CLEANUP(STACK_OF(X509_CRL) *crl_stack = NULL, sk_X509_CRL_free_pointer);
     807                 :            : 
     808         [ +  + ]:        380 :     if (conn->config->crl_lookup_cb) {
     809                 :         16 :         X509_STORE_CTX_set_verify_cb(validator->store_ctx, s2n_crl_ossl_verify_callback);
     810                 :            : 
     811                 :         16 :         crl_stack = sk_X509_CRL_new_null();
     812         [ -  + ]:         16 :         RESULT_GUARD(s2n_crl_get_crls_from_lookup_list(validator, crl_stack));
     813                 :            : 
     814                 :            :         /* Set the CRL list that the libcrypto will use to validate certificates with */
     815                 :         16 :         X509_STORE_CTX_set0_crls(validator->store_ctx, crl_stack);
     816                 :            : 
     817                 :            :         /* Enable CRL validation for certificates in X509_verify_cert */
     818 [ -  + ][ #  # ]:         16 :         RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK),
     819                 :         16 :                 S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
     820                 :            : 
     821                 :            :         /* Enable CRL validation for all certificates, not just the leaf */
     822 [ -  + ][ #  # ]:         16 :         RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK_ALL),
     823                 :         16 :                 S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
     824                 :         16 :     }
     825                 :            : 
     826                 :            :     /* Disabling time validation may set a NO_CHECK_TIME flag on the X509_STORE_CTX. Calling
     827                 :            :      * X509_STORE_CTX_set_time will override this flag. To prevent this, X509_STORE_CTX_set_time is
     828                 :            :      * only called if time validation is enabled.
     829                 :            :      */
     830         [ +  + ]:        380 :     if (conn->config->disable_x509_time_validation) {
     831         [ -  + ]:          8 :         RESULT_GUARD(s2n_x509_validator_disable_time_validation(conn, validator));
     832                 :        372 :     } else {
     833                 :        372 :         uint64_t current_sys_time = 0;
     834         [ -  + ]:        372 :         RESULT_GUARD(s2n_config_wall_clock(conn->config, &current_sys_time));
     835                 :        372 :         if (sizeof(time_t) == 4) {
     836                 :            :             /* cast value to uint64_t to prevent overflow errors */
     837 [ #  # ][ #  # ]:          0 :             RESULT_ENSURE_LTE(current_sys_time, (uint64_t) MAX_32_TIMESTAMP_NANOS);
     838                 :          0 :         }
     839                 :            : 
     840                 :            :         /* this wants seconds not nanoseconds */
     841                 :        372 :         time_t current_time = (time_t) (current_sys_time / ONE_SEC_IN_NANOS);
     842                 :        372 :         X509_STORE_CTX_set_time(validator->store_ctx, 0, current_time);
     843                 :        372 :     }
     844                 :            : 
     845                 :            :     /* It's assumed that if a valid certificate chain is received with an issuer that's present in
     846                 :            :      * the trust store, the certificate chain should be trusted. This should be the case even if
     847                 :            :      * the issuer in the trust store isn't a root certificate. Setting the PARTIAL_CHAIN flag
     848                 :            :      * allows the libcrypto to trust certificates in the trust store that aren't root certificates.
     849                 :            :      */
     850                 :        380 :     X509_STORE_CTX_set_flags(validator->store_ctx, X509_V_FLAG_PARTIAL_CHAIN);
     851                 :            : 
     852         [ -  + ]:        380 :     RESULT_GUARD(s2n_x509_validator_add_custom_extensions(validator, conn));
     853                 :            : 
     854                 :        380 :     int verify_ret = X509_verify_cert(validator->store_ctx);
     855         [ +  + ]:        380 :     if (verify_ret <= 0) {
     856                 :         26 :         int ossl_error = X509_STORE_CTX_get_error(validator->store_ctx);
     857                 :         26 :         switch (ossl_error) {
     858         [ +  + ]:          3 :             case X509_V_ERR_CERT_NOT_YET_VALID:
     859         [ +  - ]:          3 :                 RESULT_BAIL(S2N_ERR_CERT_NOT_YET_VALID);
     860         [ +  + ]:          5 :             case X509_V_ERR_CERT_HAS_EXPIRED:
     861         [ +  - ]:          5 :                 RESULT_BAIL(S2N_ERR_CERT_EXPIRED);
     862         [ +  + ]:          7 :             case X509_V_ERR_CERT_REVOKED:
     863         [ +  - ]:          7 :                 RESULT_BAIL(S2N_ERR_CERT_REVOKED);
     864         [ +  + ]:          1 :             case X509_V_ERR_UNABLE_TO_GET_CRL:
     865         [ -  + ]:          1 :             case X509_V_ERR_DIFFERENT_CRL_SCOPE:
     866         [ +  - ]:          1 :                 RESULT_BAIL(S2N_ERR_CRL_LOOKUP_FAILED);
     867         [ -  + ]:          0 :             case X509_V_ERR_CRL_SIGNATURE_FAILURE:
     868         [ #  # ]:          0 :                 RESULT_BAIL(S2N_ERR_CRL_SIGNATURE);
     869         [ -  + ]:          0 :             case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
     870         [ #  # ]:          0 :                 RESULT_BAIL(S2N_ERR_CRL_ISSUER);
     871         [ -  + ]:          0 :             case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
     872         [ #  # ]:          0 :                 RESULT_BAIL(S2N_ERR_CRL_UNHANDLED_CRITICAL_EXTENSION);
     873         [ -  + ]:          0 :             case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
     874         [ #  # ]:          0 :                 RESULT_BAIL(S2N_ERR_CERT_UNHANDLED_CRITICAL_EXTENSION);
     875         [ +  + ]:         10 :             default:
     876         [ +  - ]:         10 :                 RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
     877                 :         26 :         }
     878                 :         26 :     }
     879                 :            : 
     880                 :        354 :     validator->state = VALIDATED;
     881                 :            : 
     882                 :        354 :     return S2N_RESULT_OK;
     883                 :        380 : }
     884                 :            : 
     885                 :            : static S2N_RESULT s2n_x509_validator_parse_leaf_certificate_extensions(struct s2n_connection *conn,
     886                 :            :         uint8_t *cert_chain_in, uint32_t cert_chain_len,
     887                 :            :         s2n_parsed_extensions_list *first_certificate_extensions)
     888                 :       2494 : {
     889                 :            :     /* certificate extensions is a field in TLS 1.3 - https://tools.ietf.org/html/rfc8446#section-4.4.2 */
     890 [ -  + ][ #  # ]:       2494 :     RESULT_ENSURE_GTE(conn->actual_protocol_version, S2N_TLS13);
     891                 :            : 
     892                 :       2494 :     struct s2n_blob cert_chain_blob = { 0 };
     893         [ -  + ]:       2494 :     RESULT_GUARD_POSIX(s2n_blob_init(&cert_chain_blob, cert_chain_in, cert_chain_len));
     894                 :       2494 :     DEFER_CLEANUP(struct s2n_stuffer cert_chain_in_stuffer = { 0 }, s2n_stuffer_free);
     895                 :            : 
     896         [ -  + ]:       2494 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&cert_chain_in_stuffer, &cert_chain_blob));
     897         [ -  + ]:       2494 :     RESULT_GUARD_POSIX(s2n_stuffer_write(&cert_chain_in_stuffer, &cert_chain_blob));
     898                 :            : 
     899                 :       2494 :     struct s2n_blob asn1_cert = { 0 };
     900         [ -  + ]:       2494 :     RESULT_GUARD(s2n_x509_validator_read_asn1_cert(&cert_chain_in_stuffer, &asn1_cert));
     901                 :            : 
     902                 :       2494 :     s2n_parsed_extensions_list parsed_extensions_list = { 0 };
     903         [ -  + ]:       2494 :     RESULT_GUARD_POSIX(s2n_extension_list_parse(&cert_chain_in_stuffer, &parsed_extensions_list));
     904                 :       2494 :     *first_certificate_extensions = parsed_extensions_list;
     905                 :            : 
     906                 :       2494 :     return S2N_RESULT_OK;
     907                 :       2494 : }
     908                 :            : 
     909                 :            : S2N_RESULT s2n_x509_validator_validate_cert_chain_pre_cb(struct s2n_x509_validator *validator, struct s2n_connection *conn,
     910                 :            :         uint8_t *cert_chain_in, uint32_t cert_chain_len)
     911                 :       4977 : {
     912 [ -  + ][ #  # ]:       4977 :     RESULT_ENSURE_REF(conn);
     913 [ -  + ][ #  # ]:       4977 :     RESULT_ENSURE_REF(conn->config);
     914                 :            : 
     915                 :       4977 :     switch (validator->state) {
     916         [ +  + ]:       4957 :         case INIT:
     917                 :       4957 :             break;
     918         [ +  + ]:         20 :         case AWAITING_CRL_CALLBACK:
     919         [ +  + ]:         20 :             RESULT_GUARD(s2n_crl_handle_lookup_callback_result(validator));
     920                 :          1 :             break;
     921         [ -  + ]:          1 :         default:
     922         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_INVALID_CERT_STATE);
     923                 :       4977 :     }
     924                 :            : 
     925         [ +  + ]:       4958 :     if (validator->state == INIT) {
     926         [ +  + ]:       4957 :         RESULT_GUARD(s2n_x509_validator_process_cert_chain(validator, conn, cert_chain_in, cert_chain_len));
     927                 :       4957 :     }
     928                 :            : 
     929         [ +  + ]:       4926 :     if (validator->state == READY_TO_VERIFY) {
     930         [ +  + ]:        380 :         RESULT_GUARD(s2n_x509_validator_verify_cert_chain(validator, conn));
     931         [ +  + ]:        354 :         RESULT_GUARD(s2n_x509_validator_verify_intent(validator, conn));
     932         [ +  + ]:        335 :         RESULT_GUARD(s2n_x509_validator_check_root_cert(validator, conn));
     933                 :        335 :     }
     934                 :            : 
     935         [ +  + ]:       4880 :     if (conn->actual_protocol_version >= S2N_TLS13) {
     936                 :            :         /* Only process certificate extensions received in the first certificate. Extensions received in all other
     937                 :            :          * certificates are ignored.
     938                 :            :          *
     939                 :            :          *= https://www.rfc-editor.org/rfc/rfc8446#section-4.4.2
     940                 :            :          *# If an extension applies to the entire chain, it SHOULD be included in
     941                 :            :          *# the first CertificateEntry.
     942                 :            :          */
     943                 :       2494 :         s2n_parsed_extensions_list first_certificate_extensions = { 0 };
     944         [ -  + ]:       2494 :         RESULT_GUARD(s2n_x509_validator_parse_leaf_certificate_extensions(conn, cert_chain_in, cert_chain_len, &first_certificate_extensions));
     945         [ -  + ]:       2494 :         RESULT_GUARD_POSIX(s2n_extension_list_process(S2N_EXTENSION_LIST_CERTIFICATE, conn, &first_certificate_extensions));
     946                 :       2494 :     }
     947                 :            : 
     948                 :       4880 :     return S2N_RESULT_OK;
     949                 :       4880 : }
     950                 :            : 
     951                 :            : static S2N_RESULT s2n_x509_validator_handle_cert_validation_callback_result(struct s2n_x509_validator *validator)
     952                 :         46 : {
     953 [ -  + ][ #  # ]:         46 :     RESULT_ENSURE_REF(validator);
     954                 :            : 
     955         [ +  + ]:         46 :     if (!validator->cert_validation_info.finished) {
     956         [ +  - ]:         27 :         RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED);
     957                 :         27 :     }
     958                 :            : 
     959 [ +  + ][ +  - ]:         19 :     RESULT_ENSURE(validator->cert_validation_info.accepted, S2N_ERR_CERT_REJECTED);
     960                 :         10 :     return S2N_RESULT_OK;
     961                 :         19 : }
     962                 :            : 
     963                 :            : S2N_RESULT s2n_x509_validator_validate_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn,
     964                 :            :         uint8_t *cert_chain_in, uint32_t cert_chain_len, s2n_pkey_type *pkey_type, struct s2n_pkey *public_key_out)
     965                 :       5004 : {
     966 [ #  # ][ -  + ]:       5004 :     RESULT_ENSURE_REF(validator);
     967                 :            : 
     968         [ +  + ]:       5004 :     if (validator->cert_validation_cb_invoked) {
     969         [ +  + ]:         27 :         RESULT_GUARD(s2n_x509_validator_handle_cert_validation_callback_result(validator));
     970                 :       4977 :     } else {
     971         [ +  + ]:       4977 :         RESULT_GUARD(s2n_x509_validator_validate_cert_chain_pre_cb(validator, conn, cert_chain_in, cert_chain_len));
     972                 :            : 
     973         [ +  + ]:       4880 :         if (conn->config->cert_validation_cb) {
     974 [ +  + ][ +  - ]:         29 :             RESULT_ENSURE(conn->config->cert_validation_cb(conn, &(validator->cert_validation_info), conn->config->cert_validation_ctx) == S2N_SUCCESS,
     975                 :         19 :                     S2N_ERR_CANCELLED);
     976                 :         19 :             validator->cert_validation_cb_invoked = true;
     977         [ +  + ]:         19 :             RESULT_GUARD(s2n_x509_validator_handle_cert_validation_callback_result(validator));
     978                 :         19 :         }
     979                 :       4880 :     }
     980                 :            : 
     981                 :            :     /* retrieve information from leaf cert */
     982 [ #  # ][ -  + ]:       4861 :     RESULT_ENSURE_GT(sk_X509_num(validator->cert_chain_from_wire), 0);
     983                 :       4861 :     X509 *leaf_cert = sk_X509_value(validator->cert_chain_from_wire, 0);
     984 [ #  # ][ -  + ]:       4861 :     RESULT_ENSURE_REF(leaf_cert);
     985                 :       4861 :     DEFER_CLEANUP(struct s2n_pkey public_key = { 0 }, s2n_pkey_free);
     986         [ -  + ]:       4861 :     RESULT_GUARD(s2n_pkey_from_x509(leaf_cert, &public_key, pkey_type));
     987                 :            : 
     988                 :       4861 :     *public_key_out = public_key;
     989                 :            : 
     990                 :            :     /* Reset the old struct, so we don't clean up public_key_out */
     991                 :       4861 :     ZERO_TO_DISABLE_DEFER_CLEANUP(public_key);
     992                 :            : 
     993                 :       4861 :     return S2N_RESULT_OK;
     994                 :       4861 : }
     995                 :            : 
     996                 :            : S2N_RESULT s2n_x509_validator_validate_cert_stapled_ocsp_response(struct s2n_x509_validator *validator,
     997                 :            :         struct s2n_connection *conn, const uint8_t *ocsp_response_raw, uint32_t ocsp_response_length)
     998                 :         36 : {
     999 [ +  + ][ +  + ]:         36 :     if (validator->skip_cert_validation || !validator->check_stapled_ocsp) {
    1000                 :          8 :         validator->state = OCSP_VALIDATED;
    1001                 :          8 :         return S2N_RESULT_OK;
    1002                 :          8 :     }
    1003                 :            : 
    1004 [ -  + ][ #  # ]:         28 :     RESULT_ENSURE(validator->state == VALIDATED, S2N_ERR_INVALID_CERT_STATE);
    1005                 :            : 
    1006                 :            : #if !S2N_OCSP_STAPLING_SUPPORTED
    1007                 :            :     /* Default to safety */
    1008                 :            :     RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
    1009                 :            : #else
    1010                 :            : 
    1011 [ -  + ][ #  # ]:         28 :     RESULT_ENSURE_REF(ocsp_response_raw);
    1012                 :            : 
    1013                 :         28 :     DEFER_CLEANUP(OCSP_RESPONSE *ocsp_response = d2i_OCSP_RESPONSE(NULL, &ocsp_response_raw, ocsp_response_length),
    1014                 :         28 :             OCSP_RESPONSE_free_pointer);
    1015 [ +  - ][ +  + ]:         28 :     RESULT_ENSURE(ocsp_response != NULL, S2N_ERR_INVALID_OCSP_RESPONSE);
    1016                 :            : 
    1017                 :         27 :     int ocsp_status = OCSP_response_status(ocsp_response);
    1018 [ #  # ][ -  + ]:         27 :     RESULT_ENSURE(ocsp_status == OCSP_RESPONSE_STATUS_SUCCESSFUL, S2N_ERR_CERT_UNTRUSTED);
    1019                 :            : 
    1020                 :         27 :     DEFER_CLEANUP(OCSP_BASICRESP *basic_response = OCSP_response_get1_basic(ocsp_response), OCSP_BASICRESP_free_pointer);
    1021 [ -  + ][ #  # ]:         27 :     RESULT_ENSURE(basic_response != NULL, S2N_ERR_INVALID_OCSP_RESPONSE);
    1022                 :            : 
    1023                 :         27 :     DEFER_CLEANUP(struct s2n_validated_cert_chain validated_cert_chain = { 0 }, s2n_x509_validator_validated_cert_chain_free);
    1024         [ -  + ]:         27 :     RESULT_GUARD(s2n_x509_validator_get_validated_cert_chain(validator, &validated_cert_chain));
    1025                 :         27 :     STACK_OF(X509) *cert_chain = validated_cert_chain.stack;
    1026 [ -  + ][ #  # ]:         27 :     RESULT_ENSURE_REF(cert_chain);
    1027                 :            : 
    1028                 :         27 :     const int certs_in_chain = sk_X509_num(cert_chain);
    1029 [ -  + ][ #  # ]:         27 :     RESULT_ENSURE(certs_in_chain > 0, S2N_ERR_NO_CERT_FOUND);
    1030                 :            : 
    1031                 :            :     /* leaf is the top: not the bottom. */
    1032                 :         27 :     X509 *subject = sk_X509_value(cert_chain, 0);
    1033                 :         27 :     X509 *issuer = NULL;
    1034                 :            :     /* find the issuer in the chain. If it's not there. Fail everything. */
    1035         [ +  + ]:         54 :     for (int i = 0; i < certs_in_chain; ++i) {
    1036                 :         53 :         X509 *issuer_candidate = sk_X509_value(cert_chain, i);
    1037                 :         53 :         const int issuer_value = X509_check_issued(issuer_candidate, subject);
    1038                 :            : 
    1039         [ +  + ]:         53 :         if (issuer_value == X509_V_OK) {
    1040                 :         26 :             issuer = issuer_candidate;
    1041                 :         26 :             break;
    1042                 :         26 :         }
    1043                 :         53 :     }
    1044 [ +  + ][ +  - ]:         27 :     RESULT_ENSURE(issuer != NULL, S2N_ERR_CERT_UNTRUSTED);
    1045                 :            : 
    1046                 :            :     /* Important: this checks that the stapled ocsp response CAN be verified, not that it has been verified. */
    1047                 :         26 :     const int ocsp_verify_res = OCSP_basic_verify(basic_response, cert_chain, validator->trust_store->trust_store, 0);
    1048 [ +  - ][ +  + ]:         26 :     RESULT_GUARD_OSSL(ocsp_verify_res, S2N_ERR_CERT_UNTRUSTED);
    1049                 :            : 
    1050                 :            :     /* do the crypto checks on the response.*/
    1051                 :         24 :     int status = 0;
    1052                 :         24 :     int reason = 0;
    1053                 :            : 
    1054                 :            :     /* SHA-1 is the only supported hash algorithm for the CertID due to its established use in 
    1055                 :            :      * OCSP responders. 
    1056                 :            :      */
    1057                 :         24 :     OCSP_CERTID *cert_id = OCSP_cert_to_id(EVP_sha1(), subject, issuer);
    1058 [ #  # ][ -  + ]:         24 :     RESULT_ENSURE_REF(cert_id);
    1059                 :            : 
    1060                 :            :     /**
    1061                 :            :      *= https://www.rfc-editor.org/rfc/rfc6960#section-2.4
    1062                 :            :      *#
    1063                 :            :      *# thisUpdate      The most recent time at which the status being
    1064                 :            :      *#                 indicated is known by the responder to have been
    1065                 :            :      *#                 correct.
    1066                 :            :      *#
    1067                 :            :      *# nextUpdate      The time at or before which newer information will be
    1068                 :            :      *#                 available about the status of the certificate.
    1069                 :            :      **/
    1070                 :         24 :     ASN1_GENERALIZEDTIME *revtime = NULL, *thisupd = NULL, *nextupd = NULL;
    1071                 :            :     /* Actual verification of the response */
    1072                 :         24 :     const int ocsp_resp_find_status_res = OCSP_resp_find_status(basic_response, cert_id, &status, &reason, &revtime, &thisupd, &nextupd);
    1073                 :         24 :     OCSP_CERTID_free(cert_id);
    1074 [ +  + ][ +  - ]:         24 :     RESULT_GUARD_OSSL(ocsp_resp_find_status_res, S2N_ERR_CERT_UNTRUSTED);
    1075                 :            : 
    1076                 :         23 :     uint64_t current_sys_time_nanoseconds = 0;
    1077         [ -  + ]:         23 :     RESULT_GUARD(s2n_config_wall_clock(conn->config, &current_sys_time_nanoseconds));
    1078                 :         23 :     if (sizeof(time_t) == 4) {
    1079                 :            :         /* cast value to uint64_t to prevent overflow errors */
    1080 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_LTE(current_sys_time_nanoseconds, (uint64_t) MAX_32_TIMESTAMP_NANOS);
    1081                 :          0 :     }
    1082                 :            :     /* convert the current_sys_time (which is in nanoseconds) to seconds */
    1083                 :         23 :     time_t current_sys_time_seconds = (time_t) (current_sys_time_nanoseconds / ONE_SEC_IN_NANOS);
    1084                 :            : 
    1085                 :         23 :     DEFER_CLEANUP(ASN1_GENERALIZEDTIME *current_sys_time = ASN1_GENERALIZEDTIME_set(NULL, current_sys_time_seconds), s2n_openssl_asn1_time_free_pointer);
    1086 [ -  + ][ #  # ]:         23 :     RESULT_ENSURE_REF(current_sys_time);
    1087                 :            : 
    1088                 :            :     /**
    1089                 :            :      * It is fine to use ASN1_TIME functions with ASN1_GENERALIZEDTIME structures
    1090                 :            :      * From openssl documentation:
    1091                 :            :      * It is recommended that functions starting with ASN1_TIME be used instead
    1092                 :            :      * of those starting with ASN1_UTCTIME or ASN1_GENERALIZEDTIME. The
    1093                 :            :      * functions starting with ASN1_UTCTIME and ASN1_GENERALIZEDTIME act only on
    1094                 :            :      * that specific time format. The functions starting with ASN1_TIME will
    1095                 :            :      * operate on either format.
    1096                 :            :      * https://www.openssl.org/docs/man1.1.1/man3/ASN1_TIME_to_generalizedtime.html
    1097                 :            :      *
    1098                 :            :      * ASN1_TIME_compare has a much nicer API, but is not available in Openssl
    1099                 :            :      * 1.0.1, so we use ASN1_TIME_diff.
    1100                 :            :      */
    1101                 :         23 :     int pday = 0;
    1102                 :         23 :     int psec = 0;
    1103 [ #  # ][ -  + ]:         23 :     RESULT_GUARD_OSSL(ASN1_TIME_diff(&pday, &psec, thisupd, current_sys_time), S2N_ERR_CERT_UNTRUSTED);
    1104                 :            :     /* ensure that current_time is after or the same as "this update" */
    1105 [ +  - ][ +  + ]:         23 :     RESULT_ENSURE(pday >= 0 && psec >= 0, S2N_ERR_CERT_INVALID);
                 [ +  + ]
    1106                 :            : 
    1107                 :            :     /* ensure that current_time is before or the same as "next update" */
    1108         [ +  + ]:         20 :     if (nextupd) {
    1109 [ -  + ][ #  # ]:         19 :         RESULT_GUARD_OSSL(ASN1_TIME_diff(&pday, &psec, current_sys_time, nextupd), S2N_ERR_CERT_UNTRUSTED);
    1110 [ +  - ][ +  + ]:         19 :         RESULT_ENSURE(pday >= 0 && psec >= 0, S2N_ERR_CERT_EXPIRED);
                 [ +  + ]
    1111                 :         19 :     } else {
    1112                 :            :         /**
    1113                 :            :          * if nextupd isn't present, assume that nextupd is
    1114                 :            :          * DEFAULT_OCSP_NEXT_UPDATE_PERIOD after thisupd. This means that if the
    1115                 :            :          * current time is more than DEFAULT_OCSP_NEXT_UPDATE_PERIOD
    1116                 :            :          * seconds ahead of thisupd, we consider it invalid. We already compared
    1117                 :            :          * current_sys_time to thisupd, so reuse those values
    1118                 :            :          */
    1119                 :          1 :         uint64_t seconds_after_thisupd = pday * (3600 * 24) + psec;
    1120 [ #  # ][ -  + ]:          1 :         RESULT_ENSURE(seconds_after_thisupd < DEFAULT_OCSP_NEXT_UPDATE_PERIOD, S2N_ERR_CERT_EXPIRED);
    1121                 :          1 :     }
    1122                 :            : 
    1123                 :         16 :     switch (status) {
    1124         [ +  + ]:         15 :         case V_OCSP_CERTSTATUS_GOOD:
    1125                 :         15 :             validator->state = OCSP_VALIDATED;
    1126                 :         15 :             return S2N_RESULT_OK;
    1127         [ +  + ]:          1 :         case V_OCSP_CERTSTATUS_REVOKED:
    1128         [ +  - ]:          1 :             RESULT_BAIL(S2N_ERR_CERT_REVOKED);
    1129         [ -  + ]:          0 :         default:
    1130         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
    1131                 :         16 :     }
    1132                 :         16 : #endif /* S2N_OCSP_STAPLING_SUPPORTED */
    1133                 :         16 : }
    1134                 :            : 
    1135                 :            : bool s2n_x509_validator_is_cert_chain_validated(const struct s2n_x509_validator *validator)
    1136                 :        739 : {
    1137 [ +  - ][ +  + ]:        739 :     return validator && (validator->state == VALIDATED || validator->state == OCSP_VALIDATED);
                 [ +  + ]
    1138                 :        739 : }
    1139                 :            : 
    1140                 :            : int s2n_cert_validation_accept(struct s2n_cert_validation_info *info)
    1141                 :         38 : {
    1142 [ +  - ][ +  + ]:         38 :     POSIX_ENSURE_REF(info);
    1143 [ +  - ][ +  + ]:         37 :     POSIX_ENSURE(!info->finished, S2N_ERR_INVALID_STATE);
    1144                 :            : 
    1145                 :         17 :     info->finished = true;
    1146                 :         17 :     info->accepted = true;
    1147                 :            : 
    1148                 :         17 :     return S2N_SUCCESS;
    1149                 :         37 : }
    1150                 :            : 
    1151                 :            : int s2n_cert_validation_reject(struct s2n_cert_validation_info *info)
    1152                 :         37 : {
    1153 [ +  + ][ +  - ]:         37 :     POSIX_ENSURE_REF(info);
    1154 [ +  + ][ +  - ]:         36 :     POSIX_ENSURE(!info->finished, S2N_ERR_INVALID_STATE);
    1155                 :            : 
    1156                 :         16 :     info->finished = true;
    1157                 :         16 :     info->accepted = false;
    1158                 :            : 
    1159                 :         16 :     return S2N_SUCCESS;
    1160                 :         36 : }

Generated by: LCOV version 1.14