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 : 14603 : { 44 [ - + ]: 14603 : switch (cert_type) { 45 [ + + ]: 8595 : case S2N_PKEY_TYPE_RSA: 46 [ + + ]: 10309 : case S2N_PKEY_TYPE_RSA_PSS: 47 : 10309 : *auth_method = S2N_AUTHENTICATION_RSA; 48 : 10309 : return S2N_SUCCESS; 49 [ + + ]: 2608 : case S2N_PKEY_TYPE_ECDSA: 50 : 2608 : *auth_method = S2N_AUTHENTICATION_ECDSA; 51 : 2608 : return S2N_SUCCESS; 52 [ + + ]: 1684 : case S2N_PKEY_TYPE_MLDSA: 53 [ + + ]: 1686 : case S2N_PKEY_TYPE_UNKNOWN: 54 [ - + ]: 1686 : case S2N_PKEY_TYPE_SENTINEL: 55 [ + - ]: 1686 : POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); 56 : 14603 : } 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 : 6878 : { 62 [ - + ][ # # ]: 6878 : POSIX_ENSURE_REF(cipher_suite); 63 : : 64 : 6878 : s2n_pkey_type cert_type_for_sig_alg = S2N_PKEY_TYPE_UNKNOWN; 65 [ - + ]: 6878 : 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 : 6878 : const struct s2n_kex *kex = cipher_suite->key_exchange_alg; 74 [ - + ][ # # ]: 6878 : POSIX_ENSURE_REF(kex); 75 [ + + ]: 6878 : if (!kex->is_ephemeral) { 76 [ + + ][ + - ]: 1209 : POSIX_ENSURE_NE(cert_type_for_sig_alg, S2N_PKEY_TYPE_RSA_PSS); 77 : 1209 : } 78 : : 79 : : /* If a cipher suite includes an auth method, then the signature algorithm 80 : : * must match that auth method. 81 : : */ 82 [ + + ]: 6877 : if (cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { 83 : 2637 : s2n_authentication_method auth_method_for_sig_alg; 84 [ - + ]: 2637 : POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type_for_sig_alg, &auth_method_for_sig_alg)); 85 [ + + ][ + - ]: 2637 : POSIX_ENSURE_EQ(cipher_suite->auth_method, auth_method_for_sig_alg); 86 : 2637 : } 87 : : 88 : 6332 : return S2N_SUCCESS; 89 : 6877 : } 90 : : 91 : : static int s2n_certs_exist_for_sig_scheme(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) 92 : 32554 : { 93 [ - + ][ # # ]: 32554 : POSIX_ENSURE_REF(sig_scheme); 94 : : 95 : 32554 : s2n_pkey_type cert_type = S2N_PKEY_TYPE_UNKNOWN; 96 [ - + ]: 32554 : POSIX_GUARD_RESULT(s2n_signature_algorithm_get_pkey_type(sig_scheme->sig_alg, &cert_type)); 97 : : /* A valid cert must exist for the authentication method. */ 98 : 32554 : struct s2n_cert_chain_and_key *cert = s2n_get_compatible_cert_chain_and_key(conn, cert_type); 99 [ + + ][ + - ]: 32554 : POSIX_ENSURE_REF(cert); 100 : : 101 : : /* In TLS 1.3, signature scheme may further restrict the certs */ 102 [ + + ]: 7870 : if (conn->actual_protocol_version >= S2N_TLS13) { 103 [ + + ][ + + ]: 5130 : if (cert_type == S2N_PKEY_TYPE_RSA || cert_type == S2N_PKEY_TYPE_RSA_PSS) { 104 : : /* a RSA cert is valid for any corresponding RSA signature scheme. For 105 : : * example an rsae cert can be used for both rsa_pss_rsae_sha256 106 : : * and rsa_pss_rsae_sha384 */ 107 : 3406 : return S2N_SUCCESS; 108 [ + - ]: 3406 : } else if (cert_type == S2N_PKEY_TYPE_ECDSA) { 109 : : /* TLS 1.3 ECDSA signatures schemes e.g. ecdsa_secp384r1_sha384 also specify 110 : : * a curve. We must make sure that the certificate has the correct curve */ 111 [ - + ][ # # ]: 1724 : POSIX_ENSURE_REF(cert->private_key); 112 [ # # ][ - + ]: 1724 : POSIX_ENSURE_REF(cert->cert_chain); 113 [ # # ][ - + ]: 1724 : POSIX_ENSURE_REF(cert->cert_chain->head); 114 [ - + ][ # # ]: 1724 : POSIX_ENSURE_EQ(cert->cert_chain->head->pkey_type, S2N_PKEY_TYPE_ECDSA); 115 [ + + ][ + - ]: 1724 : POSIX_ENSURE_EQ(cert->cert_chain->head->info.public_key_nid, sig_scheme->signature_curve->libcrypto_nid); 116 [ # # ]: 1724 : } else if (cert_type == S2N_PKEY_TYPE_MLDSA) { 117 : : /* ML-DSA signatures e.g. mldsa65 include a parameter set (65) which must 118 : : * match the cert */ 119 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(cert->private_key); 120 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(cert->cert_chain); 121 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(cert->cert_chain->head); 122 [ # # ][ # # ]: 0 : POSIX_ENSURE_EQ(cert->cert_chain->head->pkey_type, S2N_PKEY_TYPE_MLDSA); 123 [ # # ][ # # ]: 0 : POSIX_ENSURE_EQ(cert->cert_chain->head->info.signature_nid, sig_scheme->libcrypto_nid); 124 : 0 : } else { 125 : : /* We expect any future signature schemes to also have these restrictions 126 : : * so we concretely fail here until they are properly handled */ 127 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); 128 : 0 : } 129 : 5130 : } 130 : : 131 : 3661 : return S2N_SUCCESS; 132 : 7870 : } 133 : : 134 : : static int s2n_certs_exist_for_auth_method(struct s2n_connection *conn, s2n_authentication_method auth_method) 135 : 9579 : { 136 [ + + ]: 9579 : if (auth_method == S2N_AUTHENTICATION_METHOD_SENTINEL) { 137 : 5331 : return S2N_SUCCESS; 138 : 5331 : } 139 : : 140 : 4248 : s2n_authentication_method auth_method_for_cert_type; 141 [ + - ]: 9660 : for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { 142 [ + + ]: 9660 : POSIX_GUARD(s2n_get_auth_method_for_cert_type(i, &auth_method_for_cert_type)); 143 : : 144 [ + + ]: 7976 : if (auth_method != auth_method_for_cert_type) { 145 : 3047 : continue; 146 : 3047 : } 147 : : 148 [ + + ]: 4929 : if (s2n_get_compatible_cert_chain_and_key(conn, i) != NULL) { 149 : 2564 : return S2N_SUCCESS; 150 : 2564 : } 151 : 4929 : } 152 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); 153 : 0 : } 154 : : 155 : : /* TLS1.3 ciphers are always valid, as they don't include an auth method. 156 : : * 157 : : * A pre-TLS1.3 cipher suite is valid if: 158 : : * - At least one compatible cert is configured 159 : : * 160 : : * This method is called by the server when choosing a cipher suite. 161 : : */ 162 : : int s2n_is_cipher_suite_valid_for_auth(struct s2n_connection *conn, struct s2n_cipher_suite *cipher_suite) 163 : 9579 : { 164 [ - + ][ # # ]: 9579 : POSIX_ENSURE_REF(cipher_suite); 165 : : 166 [ + + ]: 9579 : POSIX_GUARD(s2n_certs_exist_for_auth_method(conn, cipher_suite->auth_method)); 167 : : 168 : 7895 : return S2N_SUCCESS; 169 : 9579 : } 170 : : 171 : : /* A signature algorithm is valid if: 172 : : * - At least one compatible cert is configured. 173 : : * - The signature algorithm is allowed by the cipher suite's auth method 174 : : * (if running as a pre-TLS1.3 server). 175 : : * 176 : : * This method is called by the both server and client when choosing a signature algorithm. 177 : : */ 178 : : int s2n_is_sig_scheme_valid_for_auth(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) 179 : 32554 : { 180 [ - + ][ # # ]: 32554 : POSIX_ENSURE_REF(conn); 181 [ # # ][ - + ]: 32554 : POSIX_ENSURE_REF(conn->secure); 182 [ - + ][ # # ]: 32554 : POSIX_ENSURE_REF(sig_scheme); 183 : : 184 : 32554 : struct s2n_cipher_suite *cipher_suite = conn->secure->cipher_suite; 185 [ - + ][ # # ]: 32554 : POSIX_ENSURE_REF(cipher_suite); 186 : : 187 [ + + ]: 32554 : POSIX_GUARD(s2n_certs_exist_for_sig_scheme(conn, sig_scheme)); 188 : : 189 : : /* For the client side, signature algorithm does not need to match the cipher suite. */ 190 [ + + ]: 7067 : if (conn->mode == S2N_SERVER) { 191 [ + + ]: 6878 : POSIX_GUARD(s2n_is_sig_alg_valid_for_cipher_suite(sig_scheme->sig_alg, cipher_suite)); 192 : 6878 : } 193 : 6521 : return S2N_SUCCESS; 194 : 7067 : } 195 : : 196 : : /* A cert is valid if: 197 : : * - The configured cipher suite's auth method (if present) supports the cert. 198 : : * 199 : : * We could also verify that at least one of our supported sig algs 200 : : * supports the cert, but that seems unnecessary. If we don't have a valid 201 : : * sig alg, we'll fail on CertVerify. 202 : : * 203 : : * This method is called by the client when receiving the server's cert. 204 : : */ 205 : : int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type cert_type) 206 : 4712 : { 207 [ - + ][ # # ]: 4712 : POSIX_ENSURE_REF(conn); 208 [ - + ][ # # ]: 4712 : POSIX_ENSURE_REF(conn->secure); 209 [ - + ][ # # ]: 4712 : POSIX_ENSURE_REF(conn->secure->cipher_suite); 210 : 4712 : s2n_authentication_method conn_auth_method = conn->secure->cipher_suite->auth_method; 211 : : 212 : : /* TLS1.3 cipher suites do not specify an auth type */ 213 [ + + ]: 4712 : if (conn_auth_method == S2N_AUTHENTICATION_METHOD_SENTINEL) { 214 : 2411 : return S2N_SUCCESS; 215 : 2411 : } 216 : : 217 : 2301 : s2n_authentication_method cert_auth_method = 0; 218 [ + + ]: 2301 : POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type, &cert_auth_method)); 219 [ + + ][ + - ]: 2299 : POSIX_ENSURE(cert_auth_method == conn_auth_method, S2N_ERR_CERT_TYPE_UNSUPPORTED); 220 : 2296 : return S2N_SUCCESS; 221 : 2299 : } 222 : : 223 : : /* Choose the cert associated with our configured signature algorithm. 224 : : * 225 : : * This method is called by the server after configuring its cipher suite and sig algs. 226 : : */ 227 : : int s2n_select_certs_for_server_auth(struct s2n_connection *conn, struct s2n_cert_chain_and_key **chosen_certs) 228 : 6707 : { 229 [ - + ][ # # ]: 6707 : POSIX_ENSURE_REF(conn); 230 : 6707 : const struct s2n_signature_scheme *sig_scheme = conn->handshake_params.server_cert_sig_scheme; 231 [ - + ][ # # ]: 6707 : POSIX_ENSURE_REF(sig_scheme); 232 : 6707 : s2n_signature_algorithm sig_alg = sig_scheme->sig_alg; 233 : : 234 : 6707 : s2n_pkey_type cert_type = S2N_PKEY_TYPE_UNKNOWN; 235 [ + + ]: 6707 : if (sig_scheme == &s2n_null_sig_scheme) { 236 : : /* Only RSA auth (+ RSA kex) supports no signature scheme */ 237 : 336 : cert_type = S2N_PKEY_TYPE_RSA; 238 : 6371 : } else { 239 [ - + ]: 6371 : POSIX_GUARD_RESULT(s2n_signature_algorithm_get_pkey_type(sig_alg, &cert_type)); 240 : 6371 : } 241 : : 242 : 6707 : *chosen_certs = s2n_get_compatible_cert_chain_and_key(conn, cert_type); 243 [ + + ][ + - ]: 6707 : S2N_ERROR_IF(*chosen_certs == NULL, S2N_ERR_CERT_TYPE_UNSUPPORTED); 244 : : 245 : 6701 : return S2N_SUCCESS; 246 : 6707 : }