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 "tls/s2n_auth_selection.h" 17 : : 18 : : #include "crypto/s2n_certificate.h" 19 : : #include "crypto/s2n_signature.h" 20 : : #include "tls/s2n_cipher_suites.h" 21 : : #include "tls/s2n_kex.h" 22 : : #include "tls/s2n_signature_algorithms.h" 23 : : #include "utils/s2n_safety.h" 24 : : 25 : : /* This module should contain any logic related to choosing a valid combination of 26 : : * signature algorithm, authentication method, and certificate to use for authentication. 27 : : * 28 : : * We choose our auth methods by: 29 : : * 1. Finding a cipher suite with an auth method that we have valid certs for. In TLS1.3, 30 : : * this is a no-op -- cipher suites do not specify an auth method. 31 : : * 2. Choosing a signature algorithm that matches both the auth method (if set) and the 32 : : * available certs. 33 : : * 3. Selecting the cert that matches the chosen signature algorithm. 34 : : * 35 : : * This is a break from the original s2n pre-TLS1.3 flow, when we could choose certs and 36 : : * ciphers at the same time. Our cipher suites differentiate between "RSA" and "ECDSA", 37 : : * but not between "RSA" and "RSA-PSS". To make that decision, we need to wait until 38 : : * we've chosen a signature algorithm. This allows us to use RSA-PSS with existing 39 : : * TLS1.2 cipher suites. 40 : : */ 41 : : 42 : : int s2n_get_auth_method_for_cert_type(s2n_pkey_type cert_type, s2n_authentication_method *auth_method) 43 : 14493 : { 44 [ - + ]: 14493 : switch (cert_type) { 45 [ + + ]: 8666 : case S2N_PKEY_TYPE_RSA: 46 [ + + ]: 10332 : case S2N_PKEY_TYPE_RSA_PSS: 47 : 10332 : *auth_method = S2N_AUTHENTICATION_RSA; 48 : 10332 : return S2N_SUCCESS; 49 [ + + ]: 2523 : case S2N_PKEY_TYPE_ECDSA: 50 : 2523 : *auth_method = S2N_AUTHENTICATION_ECDSA; 51 : 2523 : return S2N_SUCCESS; 52 [ + + ]: 1636 : case S2N_PKEY_TYPE_MLDSA: 53 [ + + ]: 1638 : case S2N_PKEY_TYPE_UNKNOWN: 54 [ - + ]: 1638 : case S2N_PKEY_TYPE_SENTINEL: 55 [ + - ]: 1638 : POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); 56 : 14493 : } 57 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); 58 : 0 : } 59 : : 60 : : static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg, struct s2n_cipher_suite *cipher_suite) 61 : 6718 : { 62 [ - + ][ # # ]: 6718 : POSIX_ENSURE_REF(cipher_suite); 63 : : 64 : 6718 : s2n_pkey_type cert_type_for_sig_alg = S2N_PKEY_TYPE_UNKNOWN; 65 [ - + ]: 6718 : POSIX_GUARD_RESULT(s2n_signature_algorithm_get_pkey_type(sig_alg, &cert_type_for_sig_alg)); 66 : : 67 : : /* Non-ephemeral key exchange methods require encryption, and RSA-PSS certificates 68 : : * do not support encryption. 69 : : * 70 : : * Therefore, if a cipher suite uses a non-ephemeral kex, then any signature 71 : : * algorithm that requires RSA-PSS certificates is not valid. 72 : : */ 73 : 6718 : const struct s2n_kex *kex = cipher_suite->key_exchange_alg; 74 [ - + ][ # # ]: 6718 : POSIX_ENSURE_REF(kex); 75 [ + + ]: 6718 : if (!kex->is_ephemeral) { 76 [ + - ][ + + ]: 1491 : POSIX_ENSURE_NE(cert_type_for_sig_alg, S2N_PKEY_TYPE_RSA_PSS); 77 : 1491 : } 78 : : 79 : : /* If a cipher suite includes an auth method, then the signature algorithm 80 : : * must match that auth method. 81 : : */ 82 [ + + ]: 6717 : if (cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { 83 : 2833 : s2n_authentication_method auth_method_for_sig_alg; 84 [ - + ]: 2833 : POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type_for_sig_alg, &auth_method_for_sig_alg)); 85 [ + - ][ + + ]: 2833 : POSIX_ENSURE_EQ(cipher_suite->auth_method, auth_method_for_sig_alg); 86 : 2833 : } 87 : : 88 : 6172 : return S2N_SUCCESS; 89 : 6717 : } 90 : : 91 : : static int s2n_certs_exist_for_sig_scheme(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) 92 : 30311 : { 93 [ # # ][ - + ]: 30311 : POSIX_ENSURE_REF(sig_scheme); 94 : : 95 : 30311 : s2n_pkey_type cert_type = S2N_PKEY_TYPE_UNKNOWN; 96 [ - + ]: 30311 : POSIX_GUARD_RESULT(s2n_signature_algorithm_get_pkey_type(sig_scheme->sig_alg, &cert_type)); 97 : : 98 : : /* A valid cert must exist for the authentication method. */ 99 : 30311 : struct s2n_cert_chain_and_key *cert = s2n_get_compatible_cert_chain_and_key(conn, cert_type); 100 [ + + ][ + - ]: 30311 : POSIX_ENSURE_REF(cert); 101 : : 102 : : /* For TLS1.3 sig_algs that include a curve, the group must also match. */ 103 [ + + ][ + + ]: 7553 : if (sig_scheme->signature_curve && conn->actual_protocol_version >= S2N_TLS13) { 104 [ # # ][ - + ]: 1446 : POSIX_ENSURE_REF(cert->private_key); 105 [ - + ][ # # ]: 1446 : POSIX_ENSURE_REF(cert->cert_chain); 106 [ - + ][ # # ]: 1446 : POSIX_ENSURE_REF(cert->cert_chain->head); 107 [ # # ][ - + ]: 1446 : POSIX_ENSURE_EQ(cert->cert_chain->head->pkey_type, S2N_PKEY_TYPE_ECDSA); 108 [ + + ][ + - ]: 1446 : POSIX_ENSURE_EQ(cert->cert_chain->head->info.public_key_nid, sig_scheme->signature_curve->libcrypto_nid); 109 : 1446 : } 110 : : 111 : 6836 : return S2N_SUCCESS; 112 : 7553 : } 113 : : 114 : : static int s2n_certs_exist_for_auth_method(struct s2n_connection *conn, s2n_authentication_method auth_method) 115 : 9127 : { 116 [ + + ]: 9127 : if (auth_method == S2N_AUTHENTICATION_METHOD_SENTINEL) { 117 : 4975 : return S2N_SUCCESS; 118 : 4975 : } 119 : : 120 : 4152 : s2n_authentication_method auth_method_for_cert_type; 121 [ + - ]: 9407 : for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { 122 [ + + ]: 9407 : POSIX_GUARD(s2n_get_auth_method_for_cert_type(i, &auth_method_for_cert_type)); 123 : : 124 [ + + ]: 7771 : if (auth_method != auth_method_for_cert_type) { 125 : 2938 : continue; 126 : 2938 : } 127 : : 128 [ + + ]: 4833 : if (s2n_get_compatible_cert_chain_and_key(conn, i) != NULL) { 129 : 2516 : return S2N_SUCCESS; 130 : 2516 : } 131 : 4833 : } 132 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); 133 : 0 : } 134 : : 135 : : /* TLS1.3 ciphers are always valid, as they don't include an auth method. 136 : : * 137 : : * A pre-TLS1.3 cipher suite is valid if: 138 : : * - At least one compatible cert is configured 139 : : * 140 : : * This method is called by the server when choosing a cipher suite. 141 : : */ 142 : : int s2n_is_cipher_suite_valid_for_auth(struct s2n_connection *conn, struct s2n_cipher_suite *cipher_suite) 143 : 9127 : { 144 [ # # ][ - + ]: 9127 : POSIX_ENSURE_REF(cipher_suite); 145 : : 146 [ + + ]: 9127 : POSIX_GUARD(s2n_certs_exist_for_auth_method(conn, cipher_suite->auth_method)); 147 : : 148 : 7491 : return S2N_SUCCESS; 149 : 9127 : } 150 : : 151 : : /* A signature algorithm is valid if: 152 : : * - At least one compatible cert is configured. 153 : : * - The signature algorithm is allowed by the cipher suite's auth method 154 : : * (if running as a pre-TLS1.3 server). 155 : : * 156 : : * This method is called by the both server and client when choosing a signature algorithm. 157 : : */ 158 : : int s2n_is_sig_scheme_valid_for_auth(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) 159 : 30311 : { 160 [ - + ][ # # ]: 30311 : POSIX_ENSURE_REF(conn); 161 [ - + ][ # # ]: 30311 : POSIX_ENSURE_REF(conn->secure); 162 [ - + ][ # # ]: 30311 : POSIX_ENSURE_REF(sig_scheme); 163 : : 164 : 30311 : struct s2n_cipher_suite *cipher_suite = conn->secure->cipher_suite; 165 [ - + ][ # # ]: 30311 : POSIX_ENSURE_REF(cipher_suite); 166 : : 167 [ + + ]: 30311 : POSIX_GUARD(s2n_certs_exist_for_sig_scheme(conn, sig_scheme)); 168 : : 169 : : /* For the client side, signature algorithm does not need to match the cipher suite. */ 170 [ + + ]: 6836 : if (conn->mode == S2N_SERVER) { 171 [ + + ]: 6718 : POSIX_GUARD(s2n_is_sig_alg_valid_for_cipher_suite(sig_scheme->sig_alg, cipher_suite)); 172 : 6718 : } 173 : 6290 : return S2N_SUCCESS; 174 : 6836 : } 175 : : 176 : : /* A cert is valid if: 177 : : * - The configured cipher suite's auth method (if present) supports the cert. 178 : : * 179 : : * We could also verify that at least one of our supported sig algs 180 : : * supports the cert, but that seems unnecessary. If we don't have a valid 181 : : * sig alg, we'll fail on CertVerify. 182 : : * 183 : : * This method is called by the client when receiving the server's cert. 184 : : */ 185 : : int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type cert_type) 186 : 4328 : { 187 [ - + ][ # # ]: 4328 : POSIX_ENSURE_REF(conn); 188 [ - + ][ # # ]: 4328 : POSIX_ENSURE_REF(conn->secure); 189 [ # # ][ - + ]: 4328 : POSIX_ENSURE_REF(conn->secure->cipher_suite); 190 : 4328 : s2n_authentication_method conn_auth_method = conn->secure->cipher_suite->auth_method; 191 : : 192 : : /* TLS1.3 cipher suites do not specify an auth type */ 193 [ + + ]: 4328 : if (conn_auth_method == S2N_AUTHENTICATION_METHOD_SENTINEL) { 194 : 2079 : return S2N_SUCCESS; 195 : 2079 : } 196 : : 197 : 2249 : s2n_authentication_method cert_auth_method = 0; 198 [ + + ]: 2249 : POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type, &cert_auth_method)); 199 [ + + ][ + - ]: 2247 : POSIX_ENSURE(cert_auth_method == conn_auth_method, S2N_ERR_CERT_TYPE_UNSUPPORTED); 200 : 2244 : return S2N_SUCCESS; 201 : 2247 : } 202 : : 203 : : /* Choose the cert associated with our configured signature algorithm. 204 : : * 205 : : * This method is called by the server after configuring its cipher suite and sig algs. 206 : : */ 207 : : int s2n_select_certs_for_server_auth(struct s2n_connection *conn, struct s2n_cert_chain_and_key **chosen_certs) 208 : 6303 : { 209 [ # # ][ - + ]: 6303 : POSIX_ENSURE_REF(conn); 210 [ - + ][ # # ]: 6303 : POSIX_ENSURE_REF(conn->handshake_params.server_cert_sig_scheme); 211 : 6303 : s2n_signature_algorithm sig_alg = conn->handshake_params.server_cert_sig_scheme->sig_alg; 212 : : 213 : 6303 : s2n_pkey_type cert_type = S2N_PKEY_TYPE_UNKNOWN; 214 [ - + ]: 6303 : POSIX_GUARD_RESULT(s2n_signature_algorithm_get_pkey_type(sig_alg, &cert_type)); 215 : : 216 : 6303 : *chosen_certs = s2n_get_compatible_cert_chain_and_key(conn, cert_type); 217 [ + + ][ + - ]: 6303 : S2N_ERROR_IF(*chosen_certs == NULL, S2N_ERR_CERT_TYPE_UNSUPPORTED); 218 : : 219 : 6297 : return S2N_SUCCESS; 220 : 6303 : }