diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/restricted/aws/s2n/tls/s2n_auth_selection.c | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/tls/s2n_auth_selection.c')
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_auth_selection.c | 456 |
1 files changed, 228 insertions, 228 deletions
diff --git a/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c b/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c index 2d5070e32e..87c6b69277 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c +++ b/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c @@ -1,228 +1,228 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include "crypto/s2n_certificate.h" -#include "crypto/s2n_ecdsa.h" -#include "crypto/s2n_signature.h" - -#include "tls/s2n_cipher_suites.h" -#include "tls/s2n_kex.h" -#include "tls/s2n_auth_selection.h" - -#include "utils/s2n_safety.h" - -/* This module should contain any logic related to choosing a valid combination of - * signature algorithm, authentication method, and certificate to use for authentication. - * - * We choose our auth methods by: - * 1. Finding a cipher suite with an auth method that we have valid certs for. In TLS1.3, - * this is a no-op -- cipher suites do not specify an auth method. - * 2. Choosing a signature algorithm that matches both the auth method (if set) and the - * available certs. - * 3. Selecting the cert that matches the chosen signature algorithm. - * - * This is a break from the original s2n pre-TLS1.3 flow, when we could choose certs and - * ciphers at the same time. Our cipher suites differentiate between "RSA" and "ECDSA", - * but not between "RSA" and "RSA-PSS". To make that decision, we need to wait until - * we've chosen a signature algorithm. This allows us to use RSA-PSS with existing - * TLS1.2 cipher suites. - */ - -static int s2n_get_auth_method_for_cert_type(s2n_pkey_type cert_type, s2n_authentication_method *auth_method) -{ - switch(cert_type) { - case S2N_PKEY_TYPE_RSA: - case S2N_PKEY_TYPE_RSA_PSS: - *auth_method = S2N_AUTHENTICATION_RSA; - return S2N_SUCCESS; - case S2N_PKEY_TYPE_ECDSA: - *auth_method = S2N_AUTHENTICATION_ECDSA; - return S2N_SUCCESS; - case S2N_PKEY_TYPE_UNKNOWN: - case S2N_PKEY_TYPE_SENTINEL: - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); - } - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); -} - -static int s2n_get_cert_type_for_sig_alg(s2n_signature_algorithm sig_alg, s2n_pkey_type *cert_type) -{ - switch(sig_alg) { - case S2N_SIGNATURE_RSA_PSS_RSAE: - case S2N_SIGNATURE_RSA: - *cert_type = S2N_PKEY_TYPE_RSA; - return S2N_SUCCESS; - case S2N_SIGNATURE_ECDSA: - *cert_type = S2N_PKEY_TYPE_ECDSA; - return S2N_SUCCESS; - case S2N_SIGNATURE_RSA_PSS_PSS: - *cert_type = S2N_PKEY_TYPE_RSA_PSS; - return S2N_SUCCESS; - case S2N_SIGNATURE_ANONYMOUS: - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); - } - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); -} - -static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg, struct s2n_cipher_suite *cipher_suite) -{ - notnull_check(cipher_suite); - - s2n_pkey_type cert_type_for_sig_alg; - GUARD(s2n_get_cert_type_for_sig_alg(sig_alg, &cert_type_for_sig_alg)); - - /* Non-ephemeral key exchange methods require encryption, and RSA-PSS certificates - * do not support encryption. - * - * Therefore, if a cipher suite uses a non-ephemeral kex, then any signature - * algorithm that requires RSA-PSS certificates is not valid. - */ - if (cipher_suite->key_exchange_alg != NULL && !cipher_suite->key_exchange_alg->is_ephemeral) { - ne_check(cert_type_for_sig_alg, S2N_PKEY_TYPE_RSA_PSS); - } - - /* If a cipher suite includes an auth method, then the signature algorithm - * must match that auth method. - */ - if (cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { - s2n_authentication_method auth_method_for_sig_alg; - GUARD(s2n_get_auth_method_for_cert_type(cert_type_for_sig_alg, &auth_method_for_sig_alg)); - eq_check(cipher_suite->auth_method, auth_method_for_sig_alg); - } - - return S2N_SUCCESS; -} - -static int s2n_certs_exist_for_sig_scheme(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) -{ - notnull_check(sig_scheme); - - s2n_pkey_type cert_type; - GUARD(s2n_get_cert_type_for_sig_alg(sig_scheme->sig_alg, &cert_type)); - - /* A valid cert must exist for the authentication method. */ - struct s2n_cert_chain_and_key *cert = s2n_get_compatible_cert_chain_and_key(conn, cert_type); - notnull_check(cert); - - /* For sig_algs that include a curve, the group must also match. */ - if (sig_scheme->signature_curve != NULL) { - notnull_check(cert->private_key); - notnull_check(cert->cert_chain); - notnull_check(cert->cert_chain->head); - eq_check(cert->cert_chain->head->pkey_type, S2N_PKEY_TYPE_ECDSA); - GUARD(s2n_ecdsa_pkey_matches_curve(&cert->private_key->key.ecdsa_key, sig_scheme->signature_curve)); - } - - return S2N_SUCCESS; -} - -static int s2n_certs_exist_for_auth_method(struct s2n_connection *conn, s2n_authentication_method auth_method) -{ - s2n_authentication_method auth_method_for_cert_type; - for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { - GUARD(s2n_get_auth_method_for_cert_type(i, &auth_method_for_cert_type)); - - if (auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL && auth_method != auth_method_for_cert_type) { - continue; - } - - if (s2n_get_compatible_cert_chain_and_key(conn, i) != NULL) { - return S2N_SUCCESS; - } - } - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); -} - -/* A cipher suite is valid if: - * - At least one compatible cert is configured - * - * TLS1.3 ciphers are valid if ANY certs are configured, as authentication - * method is not tied to cipher suites in TLS1.3. - * - * This method is called by the server when choosing a cipher suite. - */ -int s2n_is_cipher_suite_valid_for_auth(struct s2n_connection *conn, struct s2n_cipher_suite *cipher_suite) -{ - notnull_check(cipher_suite); - - GUARD(s2n_certs_exist_for_auth_method(conn, cipher_suite->auth_method)); - - return S2N_SUCCESS; -} - -/* A signature algorithm is valid if: - * - At least one compatible cert is configured. - * - The signature algorithm is allowed by the cipher suite's auth method - * (if running as a pre-TLS1.3 server). - * - * This method is called by the both server and client when choosing a signature algorithm. - */ -int s2n_is_sig_scheme_valid_for_auth(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) -{ - notnull_check(conn); - notnull_check(sig_scheme); - - struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite; - notnull_check(cipher_suite); - - GUARD(s2n_certs_exist_for_sig_scheme(conn, sig_scheme)); - - /* For the client side, signature algorithm does not need to match the cipher suite. */ - if (conn->mode == S2N_SERVER) { - GUARD(s2n_is_sig_alg_valid_for_cipher_suite(sig_scheme->sig_alg, cipher_suite)); - } - return S2N_SUCCESS; -} - -/* A cert is valid if: - * - The configured cipher suite's auth method (if present) supports the cert. - * - * We could also verify that at least one of our supported sig algs - * supports the cert, but that seems unnecessary. If we don't have a valid - * sig alg, we'll fail on CertVerify. - * - * This method is called by the client when receiving the server's cert. - */ -int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type cert_type) -{ - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); - - s2n_authentication_method auth_method; - GUARD(s2n_get_auth_method_for_cert_type(cert_type, &auth_method)); - - if (conn->secure.cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { - S2N_ERROR_IF(auth_method != conn->secure.cipher_suite->auth_method, S2N_ERR_CERT_TYPE_UNSUPPORTED); - } - - return S2N_SUCCESS; -} - -/* Choose the cert associated with our configured signature algorithm. - * - * This method is called by the server after configuring its cipher suite and sig algs. - */ -int s2n_select_certs_for_server_auth(struct s2n_connection *conn, struct s2n_cert_chain_and_key **chosen_certs) -{ - notnull_check(conn); - - s2n_pkey_type cert_type; - GUARD(s2n_get_cert_type_for_sig_alg(conn->secure.conn_sig_scheme.sig_alg, &cert_type)); - - *chosen_certs = s2n_get_compatible_cert_chain_and_key(conn, cert_type); - S2N_ERROR_IF(*chosen_certs == NULL, S2N_ERR_CERT_TYPE_UNSUPPORTED); - - return S2N_SUCCESS; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "crypto/s2n_certificate.h" +#include "crypto/s2n_ecdsa.h" +#include "crypto/s2n_signature.h" + +#include "tls/s2n_cipher_suites.h" +#include "tls/s2n_kex.h" +#include "tls/s2n_auth_selection.h" + +#include "utils/s2n_safety.h" + +/* This module should contain any logic related to choosing a valid combination of + * signature algorithm, authentication method, and certificate to use for authentication. + * + * We choose our auth methods by: + * 1. Finding a cipher suite with an auth method that we have valid certs for. In TLS1.3, + * this is a no-op -- cipher suites do not specify an auth method. + * 2. Choosing a signature algorithm that matches both the auth method (if set) and the + * available certs. + * 3. Selecting the cert that matches the chosen signature algorithm. + * + * This is a break from the original s2n pre-TLS1.3 flow, when we could choose certs and + * ciphers at the same time. Our cipher suites differentiate between "RSA" and "ECDSA", + * but not between "RSA" and "RSA-PSS". To make that decision, we need to wait until + * we've chosen a signature algorithm. This allows us to use RSA-PSS with existing + * TLS1.2 cipher suites. + */ + +static int s2n_get_auth_method_for_cert_type(s2n_pkey_type cert_type, s2n_authentication_method *auth_method) +{ + switch(cert_type) { + case S2N_PKEY_TYPE_RSA: + case S2N_PKEY_TYPE_RSA_PSS: + *auth_method = S2N_AUTHENTICATION_RSA; + return S2N_SUCCESS; + case S2N_PKEY_TYPE_ECDSA: + *auth_method = S2N_AUTHENTICATION_ECDSA; + return S2N_SUCCESS; + case S2N_PKEY_TYPE_UNKNOWN: + case S2N_PKEY_TYPE_SENTINEL: + S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); + } + S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); +} + +static int s2n_get_cert_type_for_sig_alg(s2n_signature_algorithm sig_alg, s2n_pkey_type *cert_type) +{ + switch(sig_alg) { + case S2N_SIGNATURE_RSA_PSS_RSAE: + case S2N_SIGNATURE_RSA: + *cert_type = S2N_PKEY_TYPE_RSA; + return S2N_SUCCESS; + case S2N_SIGNATURE_ECDSA: + *cert_type = S2N_PKEY_TYPE_ECDSA; + return S2N_SUCCESS; + case S2N_SIGNATURE_RSA_PSS_PSS: + *cert_type = S2N_PKEY_TYPE_RSA_PSS; + return S2N_SUCCESS; + case S2N_SIGNATURE_ANONYMOUS: + S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + } + S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); +} + +static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg, struct s2n_cipher_suite *cipher_suite) +{ + notnull_check(cipher_suite); + + s2n_pkey_type cert_type_for_sig_alg; + GUARD(s2n_get_cert_type_for_sig_alg(sig_alg, &cert_type_for_sig_alg)); + + /* Non-ephemeral key exchange methods require encryption, and RSA-PSS certificates + * do not support encryption. + * + * Therefore, if a cipher suite uses a non-ephemeral kex, then any signature + * algorithm that requires RSA-PSS certificates is not valid. + */ + if (cipher_suite->key_exchange_alg != NULL && !cipher_suite->key_exchange_alg->is_ephemeral) { + ne_check(cert_type_for_sig_alg, S2N_PKEY_TYPE_RSA_PSS); + } + + /* If a cipher suite includes an auth method, then the signature algorithm + * must match that auth method. + */ + if (cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { + s2n_authentication_method auth_method_for_sig_alg; + GUARD(s2n_get_auth_method_for_cert_type(cert_type_for_sig_alg, &auth_method_for_sig_alg)); + eq_check(cipher_suite->auth_method, auth_method_for_sig_alg); + } + + return S2N_SUCCESS; +} + +static int s2n_certs_exist_for_sig_scheme(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) +{ + notnull_check(sig_scheme); + + s2n_pkey_type cert_type; + GUARD(s2n_get_cert_type_for_sig_alg(sig_scheme->sig_alg, &cert_type)); + + /* A valid cert must exist for the authentication method. */ + struct s2n_cert_chain_and_key *cert = s2n_get_compatible_cert_chain_and_key(conn, cert_type); + notnull_check(cert); + + /* For sig_algs that include a curve, the group must also match. */ + if (sig_scheme->signature_curve != NULL) { + notnull_check(cert->private_key); + notnull_check(cert->cert_chain); + notnull_check(cert->cert_chain->head); + eq_check(cert->cert_chain->head->pkey_type, S2N_PKEY_TYPE_ECDSA); + GUARD(s2n_ecdsa_pkey_matches_curve(&cert->private_key->key.ecdsa_key, sig_scheme->signature_curve)); + } + + return S2N_SUCCESS; +} + +static int s2n_certs_exist_for_auth_method(struct s2n_connection *conn, s2n_authentication_method auth_method) +{ + s2n_authentication_method auth_method_for_cert_type; + for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { + GUARD(s2n_get_auth_method_for_cert_type(i, &auth_method_for_cert_type)); + + if (auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL && auth_method != auth_method_for_cert_type) { + continue; + } + + if (s2n_get_compatible_cert_chain_and_key(conn, i) != NULL) { + return S2N_SUCCESS; + } + } + S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); +} + +/* A cipher suite is valid if: + * - At least one compatible cert is configured + * + * TLS1.3 ciphers are valid if ANY certs are configured, as authentication + * method is not tied to cipher suites in TLS1.3. + * + * This method is called by the server when choosing a cipher suite. + */ +int s2n_is_cipher_suite_valid_for_auth(struct s2n_connection *conn, struct s2n_cipher_suite *cipher_suite) +{ + notnull_check(cipher_suite); + + GUARD(s2n_certs_exist_for_auth_method(conn, cipher_suite->auth_method)); + + return S2N_SUCCESS; +} + +/* A signature algorithm is valid if: + * - At least one compatible cert is configured. + * - The signature algorithm is allowed by the cipher suite's auth method + * (if running as a pre-TLS1.3 server). + * + * This method is called by the both server and client when choosing a signature algorithm. + */ +int s2n_is_sig_scheme_valid_for_auth(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) +{ + notnull_check(conn); + notnull_check(sig_scheme); + + struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite; + notnull_check(cipher_suite); + + GUARD(s2n_certs_exist_for_sig_scheme(conn, sig_scheme)); + + /* For the client side, signature algorithm does not need to match the cipher suite. */ + if (conn->mode == S2N_SERVER) { + GUARD(s2n_is_sig_alg_valid_for_cipher_suite(sig_scheme->sig_alg, cipher_suite)); + } + return S2N_SUCCESS; +} + +/* A cert is valid if: + * - The configured cipher suite's auth method (if present) supports the cert. + * + * We could also verify that at least one of our supported sig algs + * supports the cert, but that seems unnecessary. If we don't have a valid + * sig alg, we'll fail on CertVerify. + * + * This method is called by the client when receiving the server's cert. + */ +int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type cert_type) +{ + notnull_check(conn); + notnull_check(conn->secure.cipher_suite); + + s2n_authentication_method auth_method; + GUARD(s2n_get_auth_method_for_cert_type(cert_type, &auth_method)); + + if (conn->secure.cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { + S2N_ERROR_IF(auth_method != conn->secure.cipher_suite->auth_method, S2N_ERR_CERT_TYPE_UNSUPPORTED); + } + + return S2N_SUCCESS; +} + +/* Choose the cert associated with our configured signature algorithm. + * + * This method is called by the server after configuring its cipher suite and sig algs. + */ +int s2n_select_certs_for_server_auth(struct s2n_connection *conn, struct s2n_cert_chain_and_key **chosen_certs) +{ + notnull_check(conn); + + s2n_pkey_type cert_type; + GUARD(s2n_get_cert_type_for_sig_alg(conn->secure.conn_sig_scheme.sig_alg, &cert_type)); + + *chosen_certs = s2n_get_compatible_cert_chain_and_key(conn, cert_type); + S2N_ERROR_IF(*chosen_certs == NULL, S2N_ERR_CERT_TYPE_UNSUPPORTED); + + return S2N_SUCCESS; +} |