LCOV - code coverage report
Current view: top level - tls - s2n_server_cert_request.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 124 126 98.4 %
Date: 2025-08-15 07:28:39 Functions: 12 12 100.0 %
Branches: 87 158 55.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License").
       5                 :            :  * You may not use this file except in compliance with the License.
       6                 :            :  * A copy of the License is located at
       7                 :            :  *
       8                 :            :  *  http://aws.amazon.com/apache2.0
       9                 :            :  *
      10                 :            :  * or in the "license" file accompanying this file. This file is distributed
      11                 :            :  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
      12                 :            :  * express or implied. See the License for the specific language governing
      13                 :            :  * permissions and limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "api/s2n.h"
      17                 :            : #include "crypto/s2n_certificate.h"
      18                 :            : #include "error/s2n_errno.h"
      19                 :            : #include "extensions/s2n_cert_authorities.h"
      20                 :            : #include "extensions/s2n_extension_list.h"
      21                 :            : #include "stuffer/s2n_stuffer.h"
      22                 :            : #include "tls/s2n_cipher_suites.h"
      23                 :            : #include "tls/s2n_config.h"
      24                 :            : #include "tls/s2n_connection.h"
      25                 :            : #include "tls/s2n_signature_algorithms.h"
      26                 :            : #include "tls/s2n_signature_scheme.h"
      27                 :            : #include "tls/s2n_tls.h"
      28                 :            : #include "utils/s2n_array.h"
      29                 :            : #include "utils/s2n_safety.h"
      30                 :            : 
      31                 :            : /* RFC's that define below values:
      32                 :            :  *  - https://tools.ietf.org/html/rfc5246#section-7.4.4
      33                 :            :  *  - https://tools.ietf.org/search/rfc4492#section-5.5
      34                 :            :  */
      35                 :            : typedef enum {
      36                 :            :     S2N_CERT_TYPE_RSA_SIGN = 1,
      37                 :            :     S2N_CERT_TYPE_DSS_SIGN = 2,
      38                 :            :     S2N_CERT_TYPE_RSA_FIXED_DH = 3,
      39                 :            :     S2N_CERT_TYPE_DSS_FIXED_DH = 4,
      40                 :            :     S2N_CERT_TYPE_RSA_EPHEMERAL_DH_RESERVED = 5,
      41                 :            :     S2N_CERT_TYPE_DSS_EPHEMERAL_DH_RESERVED = 6,
      42                 :            :     S2N_CERT_TYPE_FORTEZZA_DMS_RESERVED = 20,
      43                 :            :     S2N_CERT_TYPE_ECDSA_SIGN = 64,
      44                 :            :     S2N_CERT_TYPE_RSA_FIXED_ECDH = 65,
      45                 :            :     S2N_CERT_TYPE_ECDSA_FIXED_ECDH = 66,
      46                 :            : } s2n_cert_type;
      47                 :            : 
      48                 :            : static uint8_t s2n_cert_type_preference_list[] = {
      49                 :            :     S2N_CERT_TYPE_RSA_SIGN,
      50                 :            :     S2N_CERT_TYPE_ECDSA_SIGN
      51                 :            : };
      52                 :            : 
      53                 :            : /*
      54                 :            :  * Include DSS sign certificate type in server certificate request.
      55                 :            :  * Only will be used if cert_req_dss_legacy_compat_enabled is set by calling
      56                 :            :  * s2n_config_enable_cert_req_dss_legacy_compat.
      57                 :            :  */
      58                 :            : static uint8_t s2n_cert_type_preference_list_legacy_dss[] = {
      59                 :            :     S2N_CERT_TYPE_RSA_SIGN,
      60                 :            :     S2N_CERT_TYPE_DSS_SIGN,
      61                 :            :     S2N_CERT_TYPE_ECDSA_SIGN
      62                 :            : };
      63                 :            : 
      64                 :            : static int s2n_recv_client_cert_preferences(struct s2n_stuffer *in, s2n_cert_type *chosen_cert_type_out)
      65                 :         98 : {
      66                 :         98 :     uint8_t cert_types_len = 0;
      67         [ -  + ]:         98 :     POSIX_GUARD(s2n_stuffer_read_uint8(in, &cert_types_len));
      68                 :            : 
      69                 :         98 :     uint8_t *their_cert_type_pref_list = s2n_stuffer_raw_read(in, cert_types_len);
      70 [ -  + ][ #  # ]:         98 :     POSIX_ENSURE_REF(their_cert_type_pref_list);
      71                 :            : 
      72                 :            :     /* Iterate through our preference list from most to least preferred, and return the first match that we find. */
      73         [ +  - ]:         98 :     for (size_t our_cert_pref_idx = 0; our_cert_pref_idx < s2n_array_len(s2n_cert_type_preference_list); our_cert_pref_idx++) {
      74         [ +  - ]:         98 :         for (int their_cert_idx = 0; their_cert_idx < cert_types_len; their_cert_idx++) {
      75         [ +  - ]:         98 :             if (their_cert_type_pref_list[their_cert_idx] == s2n_cert_type_preference_list[our_cert_pref_idx]) {
      76                 :         98 :                 *chosen_cert_type_out = s2n_cert_type_preference_list[our_cert_pref_idx];
      77                 :         98 :                 return 0;
      78                 :         98 :             }
      79                 :         98 :         }
      80                 :         98 :     }
      81                 :            : 
      82         [ #  # ]:          0 :     POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
      83                 :          0 : }
      84                 :            : 
      85                 :            : struct s2n_certificate_authority_list {
      86                 :            :     struct s2n_stuffer iterator;
      87                 :            : };
      88                 :            : 
      89                 :            : struct s2n_certificate_request {
      90                 :            :     struct s2n_certificate_authority_list list;
      91                 :            :     struct s2n_cert_chain_and_key *chain;
      92                 :            : };
      93                 :            : 
      94                 :            : struct s2n_certificate_authority_list *s2n_certificate_request_get_ca_list(struct s2n_certificate_request *request)
      95                 :         17 : {
      96         [ +  + ]:         17 :     return request != NULL ? &request->list : NULL;
      97                 :         17 : }
      98                 :            : 
      99                 :            : int s2n_certificate_request_set_certificate(struct s2n_certificate_request *request, struct s2n_cert_chain_and_key *chain)
     100                 :         17 : {
     101 [ +  - ][ +  + ]:         17 :     POSIX_ENSURE(request, S2N_ERR_INVALID_ARGUMENT);
     102 [ +  + ][ +  - ]:         16 :     POSIX_ENSURE(chain, S2N_ERR_INVALID_ARGUMENT);
     103                 :          8 :     request->chain = chain;
     104                 :          8 :     return S2N_SUCCESS;
     105                 :         16 : }
     106                 :            : 
     107                 :            : bool s2n_certificate_authority_list_has_next(struct s2n_certificate_authority_list *list)
     108                 :        385 : {
     109 [ +  + ][ +  + ]:        385 :     return list != NULL && s2n_stuffer_data_available(&list->iterator) > 0;
     110                 :        385 : }
     111                 :            : 
     112                 :            : S2N_RESULT s2n_certificate_authority_list_read_next(struct s2n_certificate_authority_list *list, uint8_t **name, uint16_t *length)
     113                 :        144 : {
     114 [ -  + ][ #  # ]:        144 :     RESULT_ENSURE_REF(list);
     115 [ -  + ][ #  # ]:        144 :     RESULT_ENSURE_MUT(length);
     116 [ -  + ][ #  # ]:        144 :     RESULT_ENSURE_MUT(name);
     117                 :            : 
     118         [ -  + ]:        144 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&list->iterator, length));
     119 [ -  + ][ #  # ]:        144 :     RESULT_ENSURE_GT(*length, 0);
     120                 :            : 
     121                 :        144 :     *name = s2n_stuffer_raw_read(&list->iterator, *length);
     122 [ -  + ][ #  # ]:        144 :     RESULT_ENSURE_REF(*name);
     123                 :            : 
     124                 :        144 :     return S2N_RESULT_OK;
     125                 :        144 : }
     126                 :            : 
     127                 :            : int s2n_certificate_authority_list_next(struct s2n_certificate_authority_list *list, uint8_t **name, uint16_t *length)
     128                 :        336 : {
     129 [ +  + ][ +  - ]:        336 :     POSIX_ENSURE(list, S2N_ERR_INVALID_ARGUMENT);
     130 [ +  + ][ +  - ]:        288 :     POSIX_ENSURE(name, S2N_ERR_INVALID_ARGUMENT);
     131 [ +  + ][ +  - ]:        240 :     POSIX_ENSURE(length, S2N_ERR_INVALID_ARGUMENT);
     132                 :            : 
     133                 :            :     /* Ensure that if we exit due to errors we've cleared these fields */
     134                 :        192 :     *name = NULL;
     135                 :        192 :     *length = 0;
     136                 :            : 
     137 [ +  + ][ +  - ]:        192 :     POSIX_ENSURE(s2n_certificate_authority_list_has_next(list), S2N_ERR_INVALID_ARGUMENT);
     138 [ -  + ][ #  # ]:        144 :     POSIX_ENSURE(s2n_result_is_ok(s2n_certificate_authority_list_read_next(list, name, length)), S2N_ERR_BAD_MESSAGE);
     139                 :        144 :     return S2N_SUCCESS;
     140                 :        144 : }
     141                 :            : 
     142                 :            : int s2n_certificate_authority_list_reread(struct s2n_certificate_authority_list *list)
     143                 :         96 : {
     144 [ +  + ][ +  - ]:         96 :     POSIX_ENSURE(list, S2N_ERR_INVALID_ARGUMENT);
     145                 :         48 :     return s2n_stuffer_reread(&list->iterator);
     146                 :         96 : }
     147                 :            : 
     148                 :            : static int s2n_set_cert_chain_as_client(struct s2n_connection *conn)
     149                 :        147 : {
     150         [ +  + ]:        147 :     if (s2n_config_get_num_default_certs(conn->config) > 0) {
     151                 :        113 :         struct s2n_cert_chain_and_key *cert = NULL;
     152         [ +  + ]:        113 :         if (conn->config->cert_request_cb) {
     153                 :         16 :             struct s2n_certificate_request request = { 0 };
     154                 :            :             /* Don't try to free this stuffer, it's purely for reading pre-existing blob that outlives it. */
     155         [ -  + ]:         16 :             POSIX_GUARD(s2n_stuffer_init_written(&request.list.iterator, &conn->cert_authorities));
     156 [ #  # ][ -  + ]:         16 :             POSIX_ENSURE(conn->config->cert_request_cb(conn, conn->config->cert_request_cb_ctx, &request) == S2N_SUCCESS, S2N_ERR_CANCELLED);
     157                 :         16 :             cert = request.chain;
     158 [ +  - ][ +  + ]:         16 :             POSIX_ENSURE(cert, S2N_ERR_NO_CERT_FOUND);
     159                 :         97 :         } else {
     160                 :         97 :             cert = s2n_config_get_single_default_cert(conn->config);
     161 [ #  # ][ -  + ]:         97 :             POSIX_ENSURE_REF(cert);
     162                 :         97 :         }
     163                 :        105 :         conn->handshake_params.our_chain_and_key = cert;
     164                 :        105 :         conn->handshake_params.client_cert_pkey_type = s2n_cert_chain_and_key_get_pkey_type(cert);
     165                 :            : 
     166         [ -  + ]:        105 :         POSIX_GUARD_RESULT(s2n_signature_algorithm_select(conn));
     167                 :        105 :     }
     168                 :            : 
     169                 :        139 :     return 0;
     170                 :        147 : }
     171                 :            : 
     172                 :            : int s2n_tls13_cert_req_recv(struct s2n_connection *conn)
     173                 :         52 : {
     174                 :         52 :     struct s2n_stuffer *in = &conn->handshake.io;
     175                 :            : 
     176                 :            :     /* read request context length */
     177                 :         52 :     uint8_t request_context_length = 0;
     178         [ -  + ]:         52 :     POSIX_GUARD(s2n_stuffer_read_uint8(in, &request_context_length));
     179                 :            :     /* RFC 8446: This field SHALL be zero length unless used for the post-handshake authentication */
     180 [ +  + ][ +  - ]:         52 :     S2N_ERROR_IF(request_context_length != 0, S2N_ERR_BAD_MESSAGE);
     181                 :            : 
     182         [ +  + ]:         51 :     POSIX_GUARD(s2n_extension_list_recv(S2N_EXTENSION_LIST_CERT_REQ, conn, in));
     183                 :            : 
     184         [ +  + ]:         49 :     POSIX_GUARD(s2n_set_cert_chain_as_client(conn));
     185                 :            : 
     186                 :         46 :     return S2N_SUCCESS;
     187                 :         49 : }
     188                 :            : 
     189                 :            : int s2n_cert_req_recv(struct s2n_connection *conn)
     190                 :         98 : {
     191 [ #  # ][ -  + ]:         98 :     POSIX_ENSURE_REF(conn);
     192 [ -  + ][ #  # ]:         98 :     POSIX_ENSURE_REF(conn->config);
     193 [ -  + ][ #  # ]:         98 :     POSIX_ENSURE_EQ(conn->mode, S2N_CLIENT);
     194                 :            : 
     195                 :         98 :     struct s2n_stuffer *in = &conn->handshake.io;
     196                 :            : 
     197                 :         98 :     s2n_cert_type cert_type = 0;
     198         [ -  + ]:         98 :     POSIX_GUARD(s2n_recv_client_cert_preferences(in, &cert_type));
     199                 :            : 
     200         [ +  - ]:         98 :     if (conn->actual_protocol_version == S2N_TLS12) {
     201         [ -  + ]:         98 :         POSIX_GUARD(s2n_recv_supported_sig_scheme_list(in, &conn->handshake_params.peer_sig_scheme_list));
     202                 :         98 :     }
     203                 :            : 
     204                 :         98 :     uint16_t cert_authorities_len = 0;
     205         [ -  + ]:         98 :     POSIX_GUARD(s2n_stuffer_read_uint16(in, &cert_authorities_len));
     206                 :            : 
     207                 :            :     /* Stash the certificate authorities into the connection for later parsing
     208                 :            :      * as part of certificate lookup. Note that in TLS 1.3 these are handled as
     209                 :            :      * an extension in the ClientHello or CertificateRequest messages, rather
     210                 :            :      * than a field of the CertificateRequest message.
     211                 :            :      *
     212                 :            :      * The extension is handled in tls/extensions/s2n_cert_authorities.c.
     213                 :            :      */
     214         [ +  + ]:         98 :     if (conn->config->cert_request_cb) {
     215         [ -  + ]:         10 :         POSIX_GUARD(s2n_stuffer_extract_blob(in, &conn->cert_authorities));
     216 [ -  + ][ #  # ]:         10 :         POSIX_ENSURE_EQ(conn->cert_authorities.size, cert_authorities_len);
     217                 :         88 :     } else {
     218         [ -  + ]:         88 :         POSIX_GUARD(s2n_stuffer_skip_read(in, cert_authorities_len));
     219                 :         88 :     }
     220                 :            : 
     221                 :            :     /* In the future we may have more advanced logic to match a set of configured certificates against
     222                 :            :      * The cert authorities extension and the signature algorithms advertised.
     223                 :            :      * For now, this will just set the only certificate configured.
     224                 :            :      */
     225         [ +  + ]:         98 :     POSIX_GUARD(s2n_set_cert_chain_as_client(conn));
     226                 :            : 
     227                 :         93 :     return 0;
     228                 :         98 : }
     229                 :            : 
     230                 :            : int s2n_tls13_cert_req_send(struct s2n_connection *conn)
     231                 :         58 : {
     232                 :         58 :     struct s2n_stuffer *out = &conn->handshake.io;
     233                 :            : 
     234                 :            :     /* Write 0 length request context https://tools.ietf.org/html/rfc8446#section-4.3.2 */
     235         [ -  + ]:         58 :     POSIX_GUARD(s2n_stuffer_write_uint8(out, 0));
     236                 :            : 
     237         [ -  + ]:         58 :     POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERT_REQ, conn, out));
     238                 :            : 
     239                 :         58 :     return S2N_SUCCESS;
     240                 :         58 : }
     241                 :            : 
     242                 :            : int s2n_cert_req_send(struct s2n_connection *conn)
     243                 :        111 : {
     244                 :        111 :     struct s2n_stuffer *out = &conn->handshake.io;
     245                 :            : 
     246                 :        111 :     uint8_t client_cert_preference_list_size = sizeof(s2n_cert_type_preference_list);
     247         [ +  + ]:        111 :     if (conn->config->cert_req_dss_legacy_compat_enabled) {
     248                 :          1 :         client_cert_preference_list_size = sizeof(s2n_cert_type_preference_list_legacy_dss);
     249                 :          1 :     }
     250         [ -  + ]:        111 :     POSIX_GUARD(s2n_stuffer_write_uint8(out, client_cert_preference_list_size));
     251                 :            : 
     252         [ +  + ]:        334 :     for (int i = 0; i < client_cert_preference_list_size; i++) {
     253         [ +  + ]:        223 :         if (conn->config->cert_req_dss_legacy_compat_enabled) {
     254         [ -  + ]:          3 :             POSIX_GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list_legacy_dss[i]));
     255                 :        220 :         } else {
     256         [ -  + ]:        220 :             POSIX_GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list[i]));
     257                 :        220 :         }
     258                 :        223 :     }
     259                 :            : 
     260         [ +  + ]:        111 :     if (conn->actual_protocol_version == S2N_TLS12) {
     261         [ -  + ]:        108 :         POSIX_GUARD_RESULT(s2n_signature_algorithms_supported_list_send(conn, out));
     262                 :        108 :     }
     263                 :            : 
     264                 :            :     /* Before TLS1.3, certificate_authorities is part of the message instead of an extension */
     265         [ -  + ]:        111 :     POSIX_GUARD(s2n_cert_authorities_send(conn, out));
     266                 :            : 
     267                 :        111 :     return S2N_SUCCESS;
     268                 :        111 : }

Generated by: LCOV version 1.14