diff --git a/api/s2n.h b/api/s2n.h index c454ec880a3..37f1480137d 100644 --- a/api/s2n.h +++ b/api/s2n.h @@ -141,6 +141,7 @@ extern int s2n_config_set_max_cert_chain_depth(struct s2n_config *config, uint16 extern int s2n_config_add_dhparams(struct s2n_config *config, const char *dhparams_pem); extern int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *version); extern int s2n_config_set_signature_preferences(struct s2n_config *config, const char *version); +extern int s2n_config_set_ecc_preferences(struct s2n_config *config, const char *version); extern int s2n_config_set_protocol_preferences(struct s2n_config *config, const char * const *protocols, int protocol_count); typedef enum { S2N_STATUS_REQUEST_NONE = 0, S2N_STATUS_REQUEST_OCSP = 1 } s2n_status_request_type; extern int s2n_config_set_status_request_type(struct s2n_config *config, s2n_status_request_type type); diff --git a/bin/s2nc.c b/bin/s2nc.c index 5e325b6dd62..d2c18ea84a4 100755 --- a/bin/s2nc.c +++ b/bin/s2nc.c @@ -48,6 +48,9 @@ void usage() fprintf(stderr, " -c [version_string]\n"); fprintf(stderr, " --ciphers [version_string]\n"); fprintf(stderr, " Set the cipher preference version string. Defaults to \"default\". See USAGE-GUIDE.md\n"); + fprintf(stderr, " -u [version_string]\n"); + fprintf(stderr, " --curves [version_string]\n"); + fprintf(stderr, " Set the ecc preference version string. Defaults to \"default\". See USAGE-GUIDE.md\n"); fprintf(stderr, " -e\n"); fprintf(stderr, " --echo\n"); fprintf(stderr, " Listen to stdin after TLS Connection is established and echo it to the Server\n"); @@ -105,7 +108,7 @@ extern void print_s2n_error(const char *app_error); extern int echo(struct s2n_connection *conn, int sockfd); extern int negotiate(struct s2n_connection *conn); -static void setup_s2n_config(struct s2n_config *config, const char *cipher_prefs, s2n_status_request_type type, +static void setup_s2n_config(struct s2n_config *config, const char *cipher_prefs, const char *ecc_prefs, s2n_status_request_type type, struct verify_data *unsafe_verify_data, const char *host, const char *alpn_protocols, uint16_t mfl_value) { if (config == NULL) { @@ -115,6 +118,8 @@ static void setup_s2n_config(struct s2n_config *config, const char *cipher_prefs GUARD_EXIT(s2n_config_set_cipher_preferences(config, cipher_prefs), "Error setting cipher prefs"); + GUARD_EXIT(s2n_config_set_ecc_preferences(config, ecc_prefs), "Error setting ecc prefs"); + GUARD_EXIT(s2n_config_set_status_request_type(config, type), "OCSP validation is not supported by the linked libCrypto implementation. It cannot be set."); if (s2n_config_set_verify_host_callback(config, unsafe_verify_host, unsafe_verify_data) < 0) { @@ -232,6 +237,7 @@ int main(int argc, char *const *argv) uint8_t dyn_rec_timeout = 0; /* required args */ const char *cipher_prefs = "default"; + const char *ecc_prefs = "default"; const char *host = NULL; struct verify_data unsafe_verify_data; const char *port = "443"; @@ -256,11 +262,12 @@ int main(int argc, char *const *argv) {"timeout", required_argument, 0, 't'}, {"corked-io", no_argument, 0, 'C'}, {"tls13", no_argument, 0, '3'}, + {"curves", required_argument, NULL, 'u'}, }; while (1) { int option_index = 0; - int c = getopt_long(argc, argv, "a:c:ehn:sf:d:D:t:irTC", long_options, &option_index); + int c = getopt_long(argc, argv, "a:c:ehn:sf:d:D:t:irTCu:", long_options, &option_index); if (c == -1) { break; } @@ -317,6 +324,9 @@ int main(int argc, char *const *argv) case '3': use_tls13 = 1; break; + case 'u': + ecc_prefs = optarg; + break; case '?': default: usage(); @@ -381,7 +391,7 @@ int main(int argc, char *const *argv) } struct s2n_config *config = s2n_config_new(); - setup_s2n_config(config, cipher_prefs, type, &unsafe_verify_data, host, alpn_protocols, mfl_value); + setup_s2n_config(config, cipher_prefs, ecc_prefs, type, &unsafe_verify_data, host, alpn_protocols, mfl_value); if (ca_file || ca_dir) { if (s2n_config_set_verification_ca_location(config, ca_file, ca_dir) < 0) { diff --git a/bin/s2nd.c b/bin/s2nd.c index 3b449de99aa..cf4bb693d78 100755 --- a/bin/s2nd.c +++ b/bin/s2nd.c @@ -289,6 +289,9 @@ void usage() fprintf(stderr, " -c [version_string]\n"); fprintf(stderr, " --ciphers [version_string]\n"); fprintf(stderr, " Set the cipher preference version string. Defaults to \"default\". See USAGE-GUIDE.md\n"); + fprintf(stderr, " -u [version_string]\n"); + fprintf(stderr, " --curves [version_string]\n"); + fprintf(stderr, " Set the ecc preference version string. Defaults to \"default\". See USAGE-GUIDE.md\n"); fprintf(stderr, " --enter-fips-mode\n"); fprintf(stderr, " Enter libcrypto's FIPS mode. The linked version of OpenSSL must be built with the FIPS module.\n"); fprintf(stderr, " --cert\n"); @@ -431,6 +434,7 @@ int main(int argc, char *const *argv) const char *ocsp_response_file_path = NULL; const char *session_ticket_key_file_path = NULL; const char *cipher_prefs = "default"; + const char *ecc_prefs = "default"; /* The certificates provided by the user. If there are none provided, we will use the hardcoded default cert. * The associated private key for each cert will be at the same index in private_keys. If the user mixes up the @@ -469,12 +473,13 @@ int main(int argc, char *const *argv) {"no-session-ticket", no_argument, 0, 'T'}, {"corked-io", no_argument, 0, 'C'}, {"tls13", no_argument, 0, '3'}, + {"curves", required_argument, NULL, 'u'}, /* Per getopt(3) the last element of the array has to be filled with all zeros */ { 0 }, }; while (1) { int option_index = 0; - int c = getopt_long(argc, argv, "c:hmnst:d:iTC", long_options, &option_index); + int c = getopt_long(argc, argv, "c:hmnst:d:iTCu:", long_options, &option_index); if (c == -1) { break; } @@ -550,6 +555,9 @@ int main(int argc, char *const *argv) case '3': use_tls13 = 1; break; + case 'u': + ecc_prefs = optarg; + break; case '?': default: fprintf(stdout, "getopt_long returned: %d", c); @@ -698,6 +706,8 @@ int main(int argc, char *const *argv) GUARD_EXIT(s2n_config_set_cipher_preferences(config, cipher_prefs),"Error setting cipher prefs"); + GUARD_EXIT(s2n_config_set_ecc_preferences(config, ecc_prefs), "Error setting ecc prefs"); + GUARD_EXIT(s2n_config_set_cache_store_callback(config, cache_store_callback, session_cache), "Error setting cache store callback"); GUARD_EXIT(s2n_config_set_cache_retrieve_callback(config, cache_retrieve_callback, session_cache), "Error setting cache retrieve callback"); diff --git a/crypto/s2n_ecc_evp.c b/crypto/s2n_ecc_evp.c index 6179c9fea09..e126ce4e0fa 100644 --- a/crypto/s2n_ecc_evp.c +++ b/crypto/s2n_ecc_evp.c @@ -29,7 +29,7 @@ DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free); DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY_CTX *, EVP_PKEY_CTX_free); DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free); -#if !MODERN_EC_SUPPORTED +#if !EVP_APIS_SUPPORTED DEFINE_POINTER_CLEANUP_FUNC(EC_POINT *, EC_POINT_free); #endif @@ -53,23 +53,37 @@ const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1 = .share_size = ( 48 * 2 ) + 1 }; -#if MODERN_EC_SUPPORTED +#if EVP_APIS_SUPPORTED const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = { .iana_id = TLS_EC_CURVE_ECDH_X25519, .libcrypto_nid = NID_X25519, .name = "x25519", .share_size = 32 }; +#else +const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = {0}; #endif -const struct s2n_ecc_named_curve *const s2n_ecc_evp_supported_curves_list[] = { +/* All curves that s2n supports. New curves MUST be added here. + * This list is a super set of all the curves present in s2n_ecc_preferences list. + */ +const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[] = { &s2n_ecc_curve_secp256r1, &s2n_ecc_curve_secp384r1, +#if EVP_APIS_SUPPORTED + &s2n_ecc_curve_x25519, +#endif }; -const size_t s2n_ecc_evp_supported_curves_list_len = s2n_array_len(s2n_ecc_evp_supported_curves_list); +const size_t s2n_all_supported_curves_list_len = s2n_array_len(s2n_all_supported_curves_list); + + +int s2n_is_evp_apis_supported() +{ + return EVP_APIS_SUPPORTED; +} -#if MODERN_EC_SUPPORTED +#if EVP_APIS_SUPPORTED static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); #else static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out); @@ -78,9 +92,9 @@ static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY * #endif static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); -static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, struct s2n_blob *shared_secret); +static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret); -#if MODERN_EC_SUPPORTED +#if EVP_APIS_SUPPORTED static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(named_curve->libcrypto_nid, NULL), @@ -118,7 +132,7 @@ static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve } static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { -#if MODERN_EC_SUPPORTED +#if EVP_APIS_SUPPORTED if (named_curve->libcrypto_nid == NID_X25519) { return s2n_ecc_evp_generate_key_x25519(named_curve, evp_pkey); } @@ -129,14 +143,19 @@ static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_ S2N_ERROR(S2N_ERR_ECDHE_GEN_KEY); } -static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, struct s2n_blob *shared_secret) { +static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret) { notnull_check(peer_public); notnull_check(own_key); - /* Peers MUST validate each other’s public key */ - DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer); - S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_SHARED_SECRET); + /* From RFC 8446 Section 4.2.8.2: For the curves secp256r1 and secp384r1 peers MUST validate each other's + * public value Q by ensuring that the point is a valid point on the elliptic curve. + * For the curve x25519 the peer public-key validation check doesn't apply. + */ + if (iana_id == TLS_EC_CURVE_SECP_256_R1 || iana_id == TLS_EC_CURVE_SECP_384_R1) { + DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer); + S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_SHARED_SECRET); + } size_t shared_secret_size; @@ -175,7 +194,7 @@ int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *pri S2N_ERROR_IF(private_ecc_evp_params->negotiated_curve->iana_id != public_ecc_evp_params->negotiated_curve->iana_id, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); GUARD(s2n_ecc_evp_compute_shared_secret(private_ecc_evp_params->evp_pkey, public_ecc_evp_params->evp_pkey, - shared_key)); + private_ecc_evp_params->negotiated_curve->iana_id, shared_key)); return 0; } @@ -195,7 +214,7 @@ int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_e client_public_blob.data = s2n_stuffer_raw_read(Yc_in, client_public_blob.size); notnull_check(client_public_blob.data); -#if MODERN_EC_SUPPORTED +#if EVP_APIS_SUPPORTED if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) { GUARD(EVP_PKEY_set_type(peer_key, ecc_evp_params->negotiated_curve->libcrypto_nid)); } else { @@ -203,7 +222,7 @@ int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_e S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING); GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING); GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING); - GUARD(EVP_PKEY_paramgen(pctx, &peer_key)); + GUARD_OSSL(EVP_PKEY_paramgen(pctx, &peer_key), S2N_ERR_ECDHE_SERIALIZING); } GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(peer_key, client_public_blob.data, client_public_blob.size), S2N_ERR_ECDHE_SERIALIZING); @@ -220,7 +239,8 @@ int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_e S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE); #endif - return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key, shared_key); + return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key, + ecc_evp_params->negotiated_curve->iana_id, shared_key); } @@ -234,7 +254,8 @@ int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_e GUARD(s2n_ecc_evp_generate_own_key(client_params.negotiated_curve, &client_params.evp_pkey)); S2N_ERROR_IF(client_params.evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); - if (s2n_ecc_evp_compute_shared_secret(client_params.evp_pkey, ecc_evp_params->evp_pkey, shared_key) != 0) { + if (s2n_ecc_evp_compute_shared_secret(client_params.evp_pkey, ecc_evp_params->evp_pkey, + ecc_evp_params->negotiated_curve->iana_id, shared_key) != S2N_SUCCESS) { S2N_ERROR(S2N_ERR_ECDHE_SHARED_SECRET); } @@ -247,7 +268,7 @@ int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_e } -#if (!MODERN_EC_SUPPORTED) +#if (!EVP_APIS_SUPPORTED) static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length) { size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); S2N_ERROR_IF(ret == 0, S2N_ERR_ECDHE_SERIALIZING); @@ -323,7 +344,7 @@ int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, st notnull_check(ecc_evp_params->evp_pkey); notnull_check(out); -#if MODERN_EC_SUPPORTED +#if EVP_APIS_SUPPORTED struct s2n_blob point_blob = {0}; uint8_t *encoded_point = NULL; @@ -390,7 +411,7 @@ int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_e notnull_check(ecc_evp_params->negotiated_curve); S2N_ERROR_IF(point_blob->size != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING); -#if MODERN_EC_SUPPORTED +#if EVP_APIS_SUPPORTED if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) { if (ecc_evp_params->evp_pkey == NULL) { ecc_evp_params->evp_pkey = EVP_PKEY_new(); @@ -403,7 +424,7 @@ int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_e S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING); GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING); GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING); - GUARD(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey)); + GUARD_OSSL(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey), S2N_ERR_ECDHE_SERIALIZING); } GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(ecc_evp_params->evp_pkey, point_blob->data, point_blob->size), S2N_ERR_ECDHE_SERIALIZING); @@ -446,8 +467,8 @@ int s2n_ecc_evp_find_supported_curve(struct s2n_blob *iana_ids, const struct s2n GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids)); GUARD(s2n_stuffer_write(&iana_ids_in, iana_ids)); - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - const struct s2n_ecc_named_curve *supported_curve = s2n_ecc_evp_supported_curves_list[i]; + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { + const struct s2n_ecc_named_curve *supported_curve = s2n_all_supported_curves_list[i]; for (int j = 0; j < iana_ids->size / 2; j++) { uint16_t iana_id; GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id)); diff --git a/crypto/s2n_ecc_evp.h b/crypto/s2n_ecc_evp.h index 33739e9e77d..1783efe3631 100644 --- a/crypto/s2n_ecc_evp.h +++ b/crypto/s2n_ecc_evp.h @@ -34,21 +34,21 @@ struct s2n_ecc_named_curve { extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1; extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1; - -#define S2N_ECC_EVP_SUPPORTED_CURVES_COUNT 2 +extern const struct s2n_ecc_named_curve s2n_ecc_curve_x25519; /* BoringSSL only supports using EVP_PKEY_X25519 with "modern" EC EVP APIs. BoringSSL has a note to possibly add this in * the future. See https://github.com/google/boringssl/blob/master/crypto/evp/p_x25519_asn1.c#L233 */ #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) -#define MODERN_EC_SUPPORTED 1 -extern const struct s2n_ecc_named_curve s2n_ecc_curve_x25519; + #define EVP_APIS_SUPPORTED 1 + #define S2N_ECC_EVP_SUPPORTED_CURVES_COUNT 3 #else -#define MODERN_EC_SUPPORTED 0 + #define EVP_APIS_SUPPORTED 0 + #define S2N_ECC_EVP_SUPPORTED_CURVES_COUNT 2 #endif -extern const struct s2n_ecc_named_curve *const s2n_ecc_evp_supported_curves_list[]; -extern const size_t s2n_ecc_evp_supported_curves_list_len; +extern const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[]; +extern const size_t s2n_all_supported_curves_list_len; struct s2n_ecc_evp_params { const struct s2n_ecc_named_curve *negotiated_curve; @@ -77,3 +77,4 @@ int s2n_ecc_evp_parse_params(struct s2n_ecdhe_raw_server_params *raw_server_ecc_ struct s2n_ecc_evp_params *ecc_evp_params); int s2n_ecc_evp_find_supported_curve(struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found); int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params); +int s2n_is_evp_apis_supported(); diff --git a/docs/USAGE-GUIDE.md b/docs/USAGE-GUIDE.md index 701f000f121..f16f3d617ef 100644 --- a/docs/USAGE-GUIDE.md +++ b/docs/USAGE-GUIDE.md @@ -544,7 +544,7 @@ int s2n_config_set_signature_preferences(struct s2n_config *config, **s2n_config_set_signature_preferences** sets the list of acceptable signature schemes (signature + hash algorithms). -The "default" version behaves as in **s2n_config_set_signature_preferences**. Numbered versions are fixed and will never change. The currently supported versions are: +The "default" version behaves as in **s2n_config_set_cipher_preferences**. Numbered versions are fixed and will never change. The currently supported versions are: | version | definition | |----------|----------- @@ -552,6 +552,23 @@ The "default" version behaves as in **s2n_config_set_signature_preferences**. Nu |"20200207" | RSA-PSS, RSA-RSAE, RSA-PKCS1, and ECDSA. SHA1 allowed, but only as a fallback. |"20140601" | RSA-PKCS1 and ECDSA. SHA1 allowed, but only as a fallback. +### s2n\_config\_set\_ecc\_preferences + +```c +int s2n_config_set_ecc_preferences(struct s2n_config *config, + const char *version); +``` + +**s2n_config_set_ecc_preferences** sets the list of acceptable ecc curves in descending order of preference. + +The "default" version behaves as in **s2n_config_set_cipher_preferences**. Numbered versions are fixed and will never change. The currently supported versions are: + +| version | definition | +|----------|----------- +|"default" | Currently "20140601". +|"20200310" | Curves x25519, secp256r1, and secp384r1. +|"20140601" | Curves secp256r1 and secp384r1. + ### s2n\_config\_add\_cert\_chain\_and\_key ```c diff --git a/error/s2n_errno.c b/error/s2n_errno.c index 37abe1f47cd..fe8e82961a0 100755 --- a/error/s2n_errno.c +++ b/error/s2n_errno.c @@ -205,7 +205,8 @@ static const char *no_such_error = "Internal s2n error"; ERR_ENTRY(S2N_ERR_PQ_KEMS_DISALLOWED_IN_FIPS, "PQ KEMs are disallowed while in FIPS mode") \ ERR_ENTRY(S2N_RSA_PSS_NOT_SUPPORTED, "RSA-PSS signing not supported by underlying libcrypto implementation") \ ERR_ENTRY(S2N_ERR_MAX_INNER_PLAINTEXT_SIZE, "inner plaintext size exceeds limit") \ - + ERR_ENTRY(S2N_ERR_INVALID_ECC_PREFERENCES, "Invalid ecc curves preferences version") \ + #define ERR_STR_CASE(ERR, str) case ERR: return str; #define ERR_NAME_CASE(ERR, str) case ERR: return #ERR; diff --git a/error/s2n_errno.h b/error/s2n_errno.h index 243207055f9..fbcff1c9ebc 100755 --- a/error/s2n_errno.h +++ b/error/s2n_errno.h @@ -231,6 +231,7 @@ typedef enum { S2N_ERR_OCSP_NOT_SUPPORTED, S2N_ERR_INVALID_SIGNATURE_ALGORITHMS_PREFERENCES, S2N_RSA_PSS_NOT_SUPPORTED, + S2N_ERR_INVALID_ECC_PREFERENCES, S2N_ERR_T_USAGE_END, } s2n_error; diff --git a/tests/fuzz/s2n_client_key_recv_fuzz_test.c b/tests/fuzz/s2n_client_key_recv_fuzz_test.c index e3e61640db1..d8deffa0124 100644 --- a/tests/fuzz/s2n_client_key_recv_fuzz_test.c +++ b/tests/fuzz/s2n_client_key_recv_fuzz_test.c @@ -26,6 +26,7 @@ #include "tls/s2n_kem.h" #include "tls/s2n_client_key_exchange.h" #include "tls/s2n_kex.h" +#include "tls/s2n_ecc_preferences.h" #include "api/s2n.h" #include "stuffer/s2n_stuffer.h" @@ -195,9 +196,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) } server_conn->handshake_params.our_chain_and_key = cert; - + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_preferences = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_preferences); + if (server_conn->secure.cipher_suite->key_exchange_alg->client_key_recv == s2n_ecdhe_client_key_recv || server_conn->secure.cipher_suite->key_exchange_alg->client_key_recv == s2n_hybrid_client_key_recv) { - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + server_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0]; s2n_ecc_evp_generate_ephemeral_key(&server_conn->secure.server_ecc_evp_params); } diff --git a/tests/fuzz/s2n_extensions_server_key_share_recv_test.c b/tests/fuzz/s2n_extensions_server_key_share_recv_test.c index 09ac271c380..a74051f8dfd 100644 --- a/tests/fuzz/s2n_extensions_server_key_share_recv_test.c +++ b/tests/fuzz/s2n_extensions_server_key_share_recv_test.c @@ -21,6 +21,7 @@ #include #include "tls/extensions/s2n_server_key_share.h" +#include "tls/s2n_ecc_preferences.h" #include "api/s2n.h" #include "stuffer/s2n_stuffer.h" @@ -63,16 +64,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) GUARD(s2n_stuffer_write_bytes(&fuzz_stuffer, buf, len)); struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT); - notnull_check(client_conn); + EXPECT_NOT_NULL(client_conn); /* Pull a byte off the libfuzzer input and use it to set parameters */ uint8_t randval = 0; GUARD(s2n_stuffer_read_uint8(&fuzz_stuffer, &randval)); client_conn->actual_protocol_version = TLS_VERSIONS[randval % s2n_array_len(TLS_VERSIONS)]; + EXPECT_NOT_NULL(client_conn->config); + const struct s2n_ecc_preferences *ecc_preferences = client_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_preferences); + /* Generate ephemeral keys for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - client_conn->secure.client_ecc_evp_params[i].negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + for (int i = 0; i < ecc_preferences->count; i++) { + client_conn->secure.client_ecc_evp_params[i].negotiated_curve = ecc_preferences->ecc_curves[i]; GUARD(s2n_ecc_evp_generate_ephemeral_key(&client_conn->secure.client_ecc_evp_params[i])); } diff --git a/tests/fuzz/s2n_hybrid_ecdhe_bike_r1_fuzz_test.c b/tests/fuzz/s2n_hybrid_ecdhe_bike_r1_fuzz_test.c index adf3445ea76..3f930d5925f 100644 --- a/tests/fuzz/s2n_hybrid_ecdhe_bike_r1_fuzz_test.c +++ b/tests/fuzz/s2n_hybrid_ecdhe_bike_r1_fuzz_test.c @@ -33,6 +33,7 @@ #include "utils/s2n_safety.h" #include "utils/s2n_safety.h" #include "tls/s2n_cipher_suites.h" +#include "tls/s2n_ecc_preferences.h" static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_bike1_l1_r1}; @@ -44,7 +45,8 @@ static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_bike1_l1 static int setup_connection(struct s2n_connection *server_conn) { server_conn->actual_protocol_version = S2N_TLS12; - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + const struct s2n_ecc_preferences *ecc_preferences = server_conn->config->ecc_preferences; + server_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0]; server_conn->secure.server_ecc_evp_params.evp_pkey = NULL; server_conn->secure.s2n_kem_keys.negotiated_kem = &s2n_bike1_l1_r1; server_conn->secure.cipher_suite = &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384; diff --git a/tests/fuzz/s2n_hybrid_ecdhe_bike_r2_fuzz_test.c b/tests/fuzz/s2n_hybrid_ecdhe_bike_r2_fuzz_test.c index da627850655..90cdf08da71 100644 --- a/tests/fuzz/s2n_hybrid_ecdhe_bike_r2_fuzz_test.c +++ b/tests/fuzz/s2n_hybrid_ecdhe_bike_r2_fuzz_test.c @@ -32,6 +32,7 @@ #include "utils/s2n_safety.h" #include "utils/s2n_safety.h" #include "tls/s2n_cipher_suites.h" +#include "tls/s2n_ecc_preferences.h" #include "pq-crypto/bike_r2/bike_r2_kem.h" static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_bike1_l1_r2}; @@ -44,7 +45,8 @@ static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_bike1_l1 static int setup_connection(struct s2n_connection *server_conn) { server_conn->actual_protocol_version = S2N_TLS12; - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + const struct s2n_ecc_preferences *ecc_preferences = server_conn->config->ecc_preferences; + server_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0]; server_conn->secure.server_ecc_evp_params.evp_pkey = NULL; server_conn->secure.s2n_kem_keys.negotiated_kem = &s2n_bike1_l1_r2; server_conn->secure.cipher_suite = &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384; diff --git a/tests/fuzz/s2n_hybrid_ecdhe_sike_r1_fuzz_test.c b/tests/fuzz/s2n_hybrid_ecdhe_sike_r1_fuzz_test.c index 8411c81681a..8491e3dfd5c 100644 --- a/tests/fuzz/s2n_hybrid_ecdhe_sike_r1_fuzz_test.c +++ b/tests/fuzz/s2n_hybrid_ecdhe_sike_r1_fuzz_test.c @@ -33,6 +33,7 @@ #include "utils/s2n_safety.h" #include "utils/s2n_safety.h" #include "tls/s2n_cipher_suites.h" +#include "tls/s2n_ecc_preferences.h" static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_sike_p503_r1}; @@ -44,7 +45,8 @@ static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_sike_p50 static int setup_connection(struct s2n_connection *server_conn) { server_conn->actual_protocol_version = S2N_TLS12; - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + const struct s2n_ecc_preferences *ecc_preferences = server_conn->config->ecc_preferences; + server_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0]; server_conn->secure.server_ecc_evp_params.evp_pkey = NULL; server_conn->secure.s2n_kem_keys.negotiated_kem = &s2n_sike_p503_r1; server_conn->secure.cipher_suite = &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384; diff --git a/tests/fuzz/s2n_hybrid_ecdhe_sike_r2_fuzz_test.c b/tests/fuzz/s2n_hybrid_ecdhe_sike_r2_fuzz_test.c index e36f2111fc5..18b28ac996a 100644 --- a/tests/fuzz/s2n_hybrid_ecdhe_sike_r2_fuzz_test.c +++ b/tests/fuzz/s2n_hybrid_ecdhe_sike_r2_fuzz_test.c @@ -33,6 +33,7 @@ #include "utils/s2n_safety.h" #include "utils/s2n_safety.h" #include "tls/s2n_cipher_suites.h" +#include "tls/s2n_ecc_preferences.h" static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_sike_p434_r2}; @@ -44,7 +45,8 @@ static struct s2n_kem_keypair server_kem_keys = {.negotiated_kem = &s2n_sike_p43 static int setup_connection(struct s2n_connection *server_conn) { server_conn->actual_protocol_version = S2N_TLS12; - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + const struct s2n_ecc_preferences *ecc_preferences = server_conn->config->ecc_preferences; + server_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0]; server_conn->secure.server_ecc_evp_params.evp_pkey = NULL; server_conn->secure.s2n_kem_keys.negotiated_kem = &s2n_sike_p434_r2; server_conn->secure.cipher_suite = &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384; diff --git a/tests/integration/common/s2n_test_common.py b/tests/integration/common/s2n_test_common.py index e96a5545d47..f280afe92df 100644 --- a/tests/integration/common/s2n_test_common.py +++ b/tests/integration/common/s2n_test_common.py @@ -20,7 +20,7 @@ import subprocess import uuid -from common.s2n_test_scenario import Mode, Version, run_scenarios +from common.s2n_test_scenario import Mode, Version, run_scenarios, get_libcrypto from common.s2n_test_reporting import Result @@ -148,6 +148,8 @@ def get_s2n_cmd(scenario): if scenario.version is Version.TLS13: s2n_cmd.append("--tls13") + if get_libcrypto() == "openssl-1.1.1": + s2n_cmd.extend(["--curves", "default_tls13"]) s2n_cmd.extend(scenario.s2n_flags) s2n_cmd.extend([str(scenario.host), str(scenario.port)]) diff --git a/tests/integration/common/s2n_test_openssl.py b/tests/integration/common/s2n_test_openssl.py index 18669e9539e..09090b5a047 100644 --- a/tests/integration/common/s2n_test_openssl.py +++ b/tests/integration/common/s2n_test_openssl.py @@ -54,7 +54,7 @@ def get_openssl_cmd(scenario): if scenario.cipher: if scenario.version is Version.TLS13: openssl_cmd.extend(["-ciphersuites", str(scenario.cipher)]) - openssl_cmd.extend(["-curves", scenario.curve]) + openssl_cmd.extend(["-curves", str(scenario.curve)]) else: openssl_cmd.extend(["cipher", str(scenario.cipher)]) diff --git a/tests/integration/common/s2n_test_scenario.py b/tests/integration/common/s2n_test_scenario.py index b642358fc16..170f45d076c 100644 --- a/tests/integration/common/s2n_test_scenario.py +++ b/tests/integration/common/s2n_test_scenario.py @@ -117,8 +117,44 @@ def get_libcrypto(): "boringssl" : LEGACY_COMPATIBLE_CIPHERS, } +class Curve(): + def __init__(self, name, min_version): + self.name = name + self.min_version = min_version + + def valid_for(self, version): + if not version: + version = Version.default() + + if version.value < self.min_version.value: + return False + + return True -ALL_CURVES = ["P-256", "P-384"] + def __str__(self): + return self.name + + @classmethod + def all(cls): + return ALL_CURVES_PER_LIBCRYPTO_VERSION[get_libcrypto()] + +ALL_CURVES = [ + Curve("X25519", Version.TLS13), + Curve("P-256", Version.SSLv3), + Curve("P-384", Version.SSLv3) +] + +# Older versions of Openssl, do not support X25519. Current versions of LibreSSL and BoringSSL use a different API +# that is unsupported by s2n. +LEGACY_COMPATIBLE_CURVES = list(filter(lambda x: "X25519" not in x.name, ALL_CURVES)) + +ALL_CURVES_PER_LIBCRYPTO_VERSION = { + "openssl-1.1.1" : ALL_CURVES, + "openssl-1.0.2" : LEGACY_COMPATIBLE_CURVES, + "openssl-1.0.2-fips" : LEGACY_COMPATIBLE_CURVES, + "libressl" : LEGACY_COMPATIBLE_CURVES, + "boringssl" : LEGACY_COMPATIBLE_CURVES, +} class Scenario: @@ -195,7 +231,7 @@ def run_scenarios(test_func, scenarios): def get_scenarios(host, start_port, s2n_modes=Mode.all(), versions=[None], ciphers=[None], - curves=ALL_CURVES, certs=ALL_CERTS, s2n_flags=[], peer_flags=[]): + curves=Curve.all(), certs=ALL_CERTS, s2n_flags=[], peer_flags=[]): port = start_port scenarios = [] @@ -204,6 +240,9 @@ def get_scenarios(host, start_port, s2n_modes=Mode.all(), versions=[None], ciphe if cipher and not cipher.valid_for(version): continue + if curve and not curve.valid_for(version): + continue + for s2n_mode in s2n_modes: scenarios.append(Scenario( s2n_mode=s2n_mode, diff --git a/tests/integration/s2n_handshake_test_s_client.py b/tests/integration/s2n_handshake_test_s_client.py index fa779c860ea..5f43240805c 100644 --- a/tests/integration/s2n_handshake_test_s_client.py +++ b/tests/integration/s2n_handshake_test_s_client.py @@ -80,18 +80,6 @@ def s_client_validate(s_client_out): use_corked_io=False -def get_supported_curves_list_by_version(libcrypto_version): - if libcrypto_version == "openssl-1.1.1": - return ["P-256", "P-384"] - else: - return ["P-256", "P-384"] - -def get_supported_curves_str_by_version(libcrypto_version): - if libcrypto_version == "openssl-1.1.1": - return "P-256:P-384" - else: - return "P-256:P-384" - def cleanup_processes(*processes): for p in processes: p.kill() @@ -603,7 +591,7 @@ def elliptic_curve_test(host, port, libcrypto_version, fips_mode): Acceptance test for supported elliptic curves. Tests all possible supported curves with unsupported curves mixed in for noise. """ - supported_curves = get_supported_curves_list_by_version(libcrypto_version) + supported_curves = ["P-256", "P-384"] unsupported_curves = ["B-163", "K-409"] print("\n\tRunning elliptic curve tests:") print("\tExpected supported: " + str(supported_curves)) @@ -689,7 +677,7 @@ def cert_type_cipher_match_test(host, port, libcrypto_version): failed = False cipher = "ALL" - supported_curves = get_supported_curves_str_by_version(libcrypto_version) + supported_curves = "P-256:P-384" # Handshake with RSA cert + ECDSApriority server cipher pref (must skip ecdsa ciphers) rsa_ret = try_handshake(host, port, cipher, None, curves=supported_curves, @@ -720,7 +708,7 @@ def multiple_cert_type_test(host, port, libcrypto_version): # Basic handshake with ECDSA cert + RSA cert for cipher in ["ECDHE-ECDSA-AES128-SHA", "ECDHE-RSA-AES128-GCM-SHA256"]: - supported_curves = get_supported_curves_str_by_version(libcrypto_version) + supported_curves = "P-256:P-384" server_prefs = "test_all" ret = try_handshake(host, port, cipher, None, curves=supported_curves, server_cert_key_list=[(TEST_RSA_CERT, TEST_RSA_KEY),(TEST_ECDSA_CERT, TEST_ECDSA_KEY)], @@ -732,7 +720,7 @@ def multiple_cert_type_test(host, port, libcrypto_version): # Handshake with ECDSA + RSA cert but no ecdsa ciphers configured on the server for cipher in ["ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-GCM-SHA256", "AES128-SHA"]: - supported_curves = get_supported_curves_str_by_version(libcrypto_version) + supported_curves = "P-256:P-384" server_prefs = "20170210" ret = try_handshake(host, port, cipher, None, curves=supported_curves, server_cert_key_list=[(TEST_RSA_CERT, TEST_RSA_KEY),(TEST_ECDSA_CERT, TEST_ECDSA_KEY)], @@ -744,7 +732,7 @@ def multiple_cert_type_test(host, port, libcrypto_version): # Handshake with ECDSA + RSA cert but no rsa ciphers configured on the server for cipher in ["ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-ECDSA-AES256-SHA"]: - supported_curves = get_supported_curves_str_by_version(libcrypto_version) + supported_curves = "P-256:P-384" server_prefs = "test_all_ecdsa" ret = try_handshake(host, port, cipher, None, curves=supported_curves, server_cert_key_list=[(TEST_RSA_CERT, TEST_RSA_KEY),(TEST_ECDSA_CERT, TEST_ECDSA_KEY)], diff --git a/tests/integration/s2n_handshake_test_s_server.py b/tests/integration/s2n_handshake_test_s_server.py index 5b4f133c0c7..c755244a4a8 100644 --- a/tests/integration/s2n_handshake_test_s_server.py +++ b/tests/integration/s2n_handshake_test_s_server.py @@ -36,13 +36,6 @@ use_corked_io=False - -def get_supported_curves_list_by_version(libcrypto_version): - if libcrypto_version == "openssl-1.1.1": - return ["P-256", "P-384"] - else: - return ["P-256", "P-384"] - def cleanup_processes(*processes): for p in processes: p.kill() @@ -303,7 +296,7 @@ def elliptic_curve_test(host, port, libcrypto_version): Acceptance test for supported elliptic curves. Tests all possible supported curves with unsupported curves mixed in for noise. """ - supported_curves = get_supported_curves_list_by_version(libcrypto_version) + supported_curves = ["P-256", "P-384"] unsupported_curves = ["B-163", "K-409"] print("\n\tRunning s2n Client elliptic curve tests:") print("\tExpected supported: " + str(supported_curves)) diff --git a/tests/testlib/s2n_hybrid_kem_tests.c b/tests/testlib/s2n_hybrid_kem_tests.c index 53ce2c48ad8..cace3f20333 100644 --- a/tests/testlib/s2n_hybrid_kem_tests.c +++ b/tests/testlib/s2n_hybrid_kem_tests.c @@ -27,6 +27,7 @@ #include "tls/s2n_tls.h" #include "tls/s2n_cipher_suites.h" #include "tls/s2n_cipher_preferences.h" +#include "tls/s2n_ecc_preferences.h" /* If the configured lib crypto supports a custom random number generator this test is run with a AES 256 DRBG with no * prediction resistance RNG. Running in that mode all the server and client key exchange messages and final master @@ -45,7 +46,8 @@ int setup_connection(struct s2n_connection *conn, const struct s2n_kem *kem, str const char *cipher_pref_version) { S2N_ERROR_IF(s2n_is_in_fips_mode(), S2N_ERR_PQ_KEMS_DISALLOWED_IN_FIPS); conn->actual_protocol_version = S2N_TLS12; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + const struct s2n_ecc_preferences *ecc_preferences = conn->config->ecc_preferences; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0]; conn->secure.s2n_kem_keys.negotiated_kem = kem; conn->secure.cipher_suite = cipher_suite; conn->secure.conn_sig_scheme = s2n_rsa_pkcs1_sha384; diff --git a/tests/unit/s2n_choose_supported_group_test.c b/tests/unit/s2n_choose_supported_group_test.c index fa27d896694..0b624aa6332 100644 --- a/tests/unit/s2n_choose_supported_group_test.c +++ b/tests/unit/s2n_choose_supported_group_test.c @@ -17,6 +17,7 @@ #include "tls/s2n_tls.h" #include "tls/s2n_tls13.h" #include "tls/extensions/s2n_client_supported_groups.h" +#include "tls/s2n_ecc_preferences.h" int main(int argc, char **argv) { @@ -30,12 +31,15 @@ int main(int argc, char **argv) /* If the list of mutually supported groups is empty, chosen curve should be set to null */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); - for (int i = 0; i < S2N_ECC_EVP_SUPPORTED_CURVES_COUNT; i++) { + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + for (int i = 0; i < ecc_pref->count; i++) { EXPECT_NULL(server_conn->secure.mutually_supported_groups[i]); } - uint16_t supported_groups_size = s2n_array_len(server_conn->secure.mutually_supported_groups); - EXPECT_FAILURE_WITH_ERRNO(s2n_choose_supported_group(server_conn->secure.mutually_supported_groups, - supported_groups_size, &server_conn->secure.server_ecc_evp_params), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + + EXPECT_FAILURE_WITH_ERRNO(s2n_choose_supported_group(server_conn, server_conn->secure.mutually_supported_groups, + &server_conn->secure.server_ecc_evp_params), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); EXPECT_SUCCESS(s2n_connection_free(server_conn)); @@ -46,14 +50,16 @@ int main(int argc, char **argv) * match. */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); - server_conn->secure.mutually_supported_groups[1] = s2n_ecc_evp_supported_curves_list[1]; + server_conn->secure.mutually_supported_groups[1] = ecc_pref->ecc_curves[1]; - uint16_t supported_groups_size = s2n_array_len(server_conn->secure.mutually_supported_groups); - EXPECT_SUCCESS(s2n_choose_supported_group(server_conn->secure.mutually_supported_groups, supported_groups_size, + EXPECT_SUCCESS(s2n_choose_supported_group(server_conn, server_conn->secure.mutually_supported_groups, &server_conn->secure.server_ecc_evp_params)); - EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[1]); + EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[1]); EXPECT_SUCCESS(s2n_connection_free(server_conn)); } @@ -64,14 +70,17 @@ int main(int argc, char **argv) */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); - for (int i = 0; i < S2N_ECC_EVP_SUPPORTED_CURVES_COUNT; i++) { - server_conn->secure.mutually_supported_groups[i] = s2n_ecc_evp_supported_curves_list[i]; + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + for (int i = 0; i < ecc_pref->count; i++) { + server_conn->secure.mutually_supported_groups[i] = ecc_pref->ecc_curves[i]; } - uint16_t supported_groups_size = s2n_array_len(server_conn->secure.mutually_supported_groups); - EXPECT_SUCCESS(s2n_choose_supported_group(server_conn->secure.mutually_supported_groups, supported_groups_size, + + EXPECT_SUCCESS(s2n_choose_supported_group(server_conn, server_conn->secure.mutually_supported_groups, &server_conn->secure.server_ecc_evp_params)); - EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[0]); + EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[0]); EXPECT_SUCCESS(s2n_connection_free(server_conn)); } diff --git a/tests/unit/s2n_cipher_suite_match_test.c b/tests/unit/s2n_cipher_suite_match_test.c index a8d98b8a4dd..704a9f3a52f 100644 --- a/tests/unit/s2n_cipher_suite_match_test.c +++ b/tests/unit/s2n_cipher_suite_match_test.c @@ -23,6 +23,7 @@ #include "tls/s2n_cipher_suites.h" #include "tls/s2n_connection.h" #include "tls/s2n_cipher_preferences.h" +#include "tls/s2n_ecc_preferences.h" int main(int argc, char **argv) { @@ -221,10 +222,13 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_connection_wipe(conn)); /* TEST RSA cipher chosen when ECDSA cipher is at top */ - s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"); + EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority")); + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(conn->config, "default")); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); /* Assume default for negotiated curve. */ /* Shouldn't be necessary unless the test fails, but we want the failure to be obvious. */ - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; const uint8_t expected_rsa_wire_choice[] = { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA }; EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -245,7 +249,7 @@ int main(int argc, char **argv) int client_extensions_len = sizeof(client_extensions_data); s2n_connection_set_cipher_preferences(conn, "KMS-PQ-TLS-1-0-2019-06"); conn->client_protocol_version = S2N_TLS12; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; conn->secure.client_pq_kem_extension.data = client_extensions_data; conn->secure.client_pq_kem_extension.size = client_extensions_len; EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers, cipher_count)); @@ -259,7 +263,7 @@ int main(int argc, char **argv) const uint8_t expected_classic_wire_choice[] = {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}; s2n_connection_set_cipher_preferences(conn, "KMS-PQ-TLS-1-0-2019-06"); conn->client_protocol_version = i; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; conn->secure.client_pq_kem_extension.data = client_extensions_data; conn->secure.client_pq_kem_extension.size = client_extensions_len; EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers, cipher_count)); @@ -277,11 +281,13 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, ecdsa_cert)); EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); + ecc_pref = conn->config->ecc_preferences; + /* TEST ECDSA */ s2n_connection_set_cipher_preferences(conn, "test_all_ecdsa"); const uint8_t expected_ecdsa_wire_choice[] = { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 }; /* Assume default for negotiated curve. */ - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); EXPECT_EQUAL(conn->secure.cipher_suite, s2n_cipher_suite_from_wire(expected_ecdsa_wire_choice)); @@ -290,7 +296,7 @@ int main(int argc, char **argv) /* TEST ECDSA cipher chosen when RSA cipher is at top */ s2n_connection_set_cipher_preferences(conn, "test_all"); /* Assume default for negotiated curve. */ - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); EXPECT_EQUAL(conn->secure.cipher_suite, s2n_cipher_suite_from_wire(expected_ecdsa_wire_choice)); @@ -308,7 +314,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 }; s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -320,7 +326,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA }; s2n_connection_set_cipher_preferences(conn, "test_all"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -335,7 +341,7 @@ int main(int argc, char **argv) const uint8_t expected_wire_choice[] = { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA }; /* 20170328 only supports RSA ciphers */ s2n_connection_set_cipher_preferences(conn, "20170328"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -349,7 +355,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 }; s2n_connection_set_cipher_preferences(conn, "test_all_ecdsa"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -363,7 +369,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_RSA_WITH_RC4_128_MD5 }; s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers, cipher_count)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -377,7 +383,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA }; s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_only_ecdsa, cipher_count_only_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -410,13 +416,14 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, ecdsa_cert)); /* Override auto-chosen defaults with only RSA cert default. ECDSA still loaded, but not default. */ EXPECT_SUCCESS(s2n_config_set_cert_chain_and_key_defaults(server_config, &rsa_cert, 1)); + ecc_pref = server_config->ecc_preferences; /* Client sends RSA and ECDSA ciphers, server prioritizes ECDSA, ECDSA + RSA cert is configured, * only RSA is default. Expect default RSA used instead of previous test that expects ECDSA for this case. */ { const uint8_t expected_wire_choice[] = { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA }; s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -432,7 +439,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 }; s2n_connection_set_cipher_preferences(conn, "test_all"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -448,7 +455,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 }; s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -471,7 +478,7 @@ int main(int argc, char **argv) { const uint8_t expected_wire_choice[] = { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA }; s2n_connection_set_cipher_preferences(conn, "test_all"); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config)); EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa)); EXPECT_EQUAL(conn->secure_renegotiation, 0); @@ -558,7 +565,7 @@ int main(int argc, char **argv) conn->server_protocol_version = S2N_TLS12; /* server configured with TLS 1.2 */ conn->actual_protocol_version = S2N_TLS12; conn->client_protocol_version = S2N_TLS13; /* a TLS 1.3 client */ - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0]; EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, count)); EXPECT_EQUAL(conn->secure.cipher_suite, &s2n_ecdhe_rsa_with_aes_128_gcm_sha256); diff --git a/tests/unit/s2n_client_key_share_extension_test.c b/tests/unit/s2n_client_key_share_extension_test.c index 52d40a744ac..f8da5ff2dcc 100644 --- a/tests/unit/s2n_client_key_share_extension_test.c +++ b/tests/unit/s2n_client_key_share_extension_test.c @@ -24,6 +24,7 @@ #include "tls/s2n_tls.h" #include "tls/extensions/s2n_client_key_share.h" #include "tls/extensions/s2n_key_share.h" +#include "tls/s2n_ecc_preferences.h" #include "testlib/s2n_testlib.h" #include "stuffer/s2n_stuffer.h" @@ -68,20 +69,23 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_connection_free(conn)); } - /* Test s2n_extensions_key_share_send */ + /* Test s2n_extensions_client_key_share_send */ { - /* Test that s2n_extensions_key_share_send initializes the client key share list */ + /* Test that s2n_extensions_client_key_share_send initializes the client key share list */ { struct s2n_stuffer key_share_extension; struct s2n_connection *conn; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_CLIENT)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); EXPECT_SUCCESS(s2n_extensions_client_key_share_send(conn, &key_share_extension)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_preferences = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_preferences); - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < ecc_preferences->count; i++) { struct s2n_ecc_evp_params *ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; - EXPECT_EQUAL(ecc_evp_params->negotiated_curve, s2n_ecc_evp_supported_curves_list[i]); + EXPECT_EQUAL(ecc_evp_params->negotiated_curve, ecc_preferences->ecc_curves[i]); EXPECT_NOT_NULL(ecc_evp_params->evp_pkey); } @@ -89,13 +93,12 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_connection_free(conn)); } - /* Test that s2n_extensions_key_share_send writes a well-formed list of key shares */ + /* Test that s2n_extensions_client_key_share_send writes a well-formed list of key shares */ { struct s2n_stuffer key_share_extension; struct s2n_connection *conn; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_CLIENT)); - + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); EXPECT_SUCCESS(s2n_extensions_client_key_share_send(conn, &key_share_extension)); /* should start with correct extension type */ @@ -115,13 +118,17 @@ int main(int argc, char **argv) uint16_t actual_key_shares_size = s2n_stuffer_data_available(&key_share_extension); EXPECT_EQUAL(key_shares_size, actual_key_shares_size); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_preferences = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_preferences); + /* should contain every supported curve, in order, with their sizes */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < ecc_preferences->count; i++) { uint16_t iana_value, share_size; EXPECT_SUCCESS(s2n_stuffer_read_uint16(&key_share_extension, &iana_value)); - EXPECT_EQUAL(iana_value, s2n_ecc_evp_supported_curves_list[i]->iana_id); + EXPECT_EQUAL(iana_value, ecc_preferences->ecc_curves[i]->iana_id); EXPECT_SUCCESS(s2n_stuffer_read_uint16(&key_share_extension, &share_size)); - EXPECT_EQUAL(share_size, s2n_ecc_evp_supported_curves_list[i]->share_size); + EXPECT_EQUAL(share_size, ecc_preferences->ecc_curves[i]->share_size); EXPECT_SUCCESS(s2n_stuffer_skip_read(&key_share_extension, share_size)); } @@ -129,6 +136,34 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_free(&key_share_extension)); EXPECT_SUCCESS(s2n_connection_free(conn)); } + + /* Test s2n_extensions_client_key_share_send for a supported curve present in s2n_all_supported_curves_list, + * but not present in the ecc_preferences list selected */ + if (s2n_is_evp_apis_supported()) { + struct s2n_stuffer key_share_extension; + struct s2n_connection *conn; + EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_CLIENT)); + EXPECT_NOT_NULL(conn->config); + /* Explicitly set the ecc_preferences list to contain the curves p-256 and p-384 */ + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(conn->config, "20140601")); + const struct s2n_ecc_preferences *ecc_preferences = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_preferences); + + /* x25519 is present in s2n_all_supported_curves_list but not in the "default" list */ + const struct s2n_ecc_named_curve *test_curve = &s2n_ecc_curve_x25519; + + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + + EXPECT_SUCCESS(s2n_extensions_client_key_share_send(conn, &key_share_extension)); + + for (int i = 0; i < ecc_preferences->count ; i++) { + struct s2n_ecc_evp_params *ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; + EXPECT_NOT_EQUAL(ecc_evp_params->negotiated_curve, test_curve); + } + + EXPECT_SUCCESS(s2n_stuffer_free(&key_share_extension)); + EXPECT_SUCCESS(s2n_connection_free(conn)); + } } /* Test s2n_extensions_client_key_share_recv */ @@ -138,23 +173,27 @@ int main(int argc, char **argv) { struct s2n_connection *client_conn, *server_conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT)); EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(client_conn))); EXPECT_SUCCESS(s2n_extensions_client_key_share_send(client_conn, &key_share_extension)); EXPECT_SUCCESS(s2n_stuffer_skip_read(&key_share_extension, 4)); EXPECT_SUCCESS(s2n_extensions_client_key_share_recv(server_conn, &key_share_extension)); + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + /* should read all data */ EXPECT_EQUAL(s2n_stuffer_data_available(&key_share_extension), 0); /* should set internal state the same as the client */ struct s2n_ecc_evp_params *server_ecc_evp_params; struct s2n_ecc_evp_params *client_ecc_evp_params; - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < ecc_pref->count; i++) { server_ecc_evp_params = &server_conn->secure.client_ecc_evp_params[i]; client_ecc_evp_params = &client_conn->secure.client_ecc_evp_params[i]; @@ -173,11 +212,13 @@ int main(int argc, char **argv) { struct s2n_connection *conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); - - EXPECT_SUCCESS(s2n_stuffer_write_uint16(&key_share_extension, s2n_ecc_evp_supported_curves_list[0]->share_size * 10)); - EXPECT_SUCCESS(s2n_write_named_curve(&key_share_extension, s2n_ecc_evp_supported_curves_list[0])); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + EXPECT_SUCCESS(s2n_stuffer_write_uint16(&key_share_extension, ecc_pref->ecc_curves[0]->share_size * 10)); + EXPECT_SUCCESS(s2n_write_named_curve(&key_share_extension, ecc_pref->ecc_curves[0])); EXPECT_FAILURE(s2n_extensions_client_key_share_recv(conn, &key_share_extension)); @@ -189,13 +230,16 @@ int main(int argc, char **argv) { struct s2n_connection *conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); /* Write curve with huge length */ S2N_PREPARE_DATA_LENGTH(&key_share_extension); EXPECT_SUCCESS(s2n_write_key_share(&key_share_extension, - s2n_ecc_evp_supported_curves_list[0]->iana_id, s2n_ecc_evp_supported_curves_list[0]->share_size * 10, s2n_ecc_evp_supported_curves_list[0])); + ecc_pref->ecc_curves[0]->iana_id, ecc_pref->ecc_curves[0]->share_size * 10, ecc_pref->ecc_curves[0])); S2N_WRITE_DATA_LENGTH(&key_share_extension); EXPECT_FAILURE(s2n_extensions_client_key_share_recv(conn, &key_share_extension)); @@ -208,12 +252,14 @@ int main(int argc, char **argv) { struct s2n_connection *conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); - + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); /* Write only first curve */ S2N_PREPARE_DATA_LENGTH(&key_share_extension); - EXPECT_SUCCESS(s2n_write_named_curve(&key_share_extension, s2n_ecc_evp_supported_curves_list[0])); + EXPECT_SUCCESS(s2n_write_named_curve(&key_share_extension, ecc_pref->ecc_curves[0])); S2N_WRITE_DATA_LENGTH(&key_share_extension); EXPECT_SUCCESS(s2n_extensions_client_key_share_recv(conn, &key_share_extension)); @@ -225,10 +271,10 @@ int main(int argc, char **argv) struct s2n_ecc_evp_params *ecc_evp_params = &conn->secure.client_ecc_evp_params[0]; EXPECT_NOT_NULL(ecc_evp_params->negotiated_curve); EXPECT_NOT_NULL(ecc_evp_params->evp_pkey); - EXPECT_EQUAL(ecc_evp_params->negotiated_curve, s2n_ecc_evp_supported_curves_list[0]); + EXPECT_EQUAL(ecc_evp_params->negotiated_curve, ecc_pref->ecc_curves[0]); /* should not have initialized any other curves */ - for (int i = 1; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 1; i < ecc_pref->count; i++) { ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; EXPECT_NULL(ecc_evp_params->negotiated_curve); EXPECT_NULL(ecc_evp_params->evp_pkey); @@ -242,15 +288,18 @@ int main(int argc, char **argv) { struct s2n_connection *server_conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(server_conn))); + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); EXPECT_SUCCESS(s2n_stuffer_write_uint16(&key_share_extension, 0)); EXPECT_SUCCESS(s2n_extensions_client_key_share_recv(server_conn, &key_share_extension)); /* should not have initialized any other curves */ - for (int i = 1; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 1; i < ecc_pref->count; i++) { struct s2n_ecc_evp_params *ecc_evp_params = &server_conn->secure.client_ecc_evp_params[i]; EXPECT_NULL(ecc_evp_params->negotiated_curve); EXPECT_NULL(ecc_evp_params->evp_pkey); @@ -264,18 +313,21 @@ int main(int argc, char **argv) { struct s2n_connection *conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); S2N_PREPARE_DATA_LENGTH(&key_share_extension); /* Write unsupported curves */ /* 0 -> unallocated_RESERVED */ EXPECT_SUCCESS(s2n_write_key_share(&key_share_extension, - 0, s2n_ecc_evp_supported_curves_list[0]->share_size, s2n_ecc_evp_supported_curves_list[0])); + 0, ecc_pref->ecc_curves[0]->share_size, ecc_pref->ecc_curves[0])); /* 0xFF01 -> obsolete_RESERVED */ EXPECT_SUCCESS(s2n_write_key_share(&key_share_extension, - 65281, s2n_ecc_evp_supported_curves_list[0]->share_size, s2n_ecc_evp_supported_curves_list[0])); + 65281, ecc_pref->ecc_curves[0]->share_size, ecc_pref->ecc_curves[0])); S2N_WRITE_DATA_LENGTH(&key_share_extension); @@ -285,7 +337,7 @@ int main(int argc, char **argv) EXPECT_EQUAL(s2n_stuffer_data_available(&key_share_extension), 0); /* should not have initialized any curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < ecc_pref->count; i++) { struct s2n_ecc_evp_params *ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; EXPECT_NULL(ecc_evp_params->negotiated_curve); EXPECT_NULL(ecc_evp_params->evp_pkey); @@ -299,13 +351,16 @@ int main(int argc, char **argv) { struct s2n_connection *conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); /* Write supported curve, but with a different curve's size */ S2N_PREPARE_DATA_LENGTH(&key_share_extension); EXPECT_SUCCESS(s2n_write_key_share(&key_share_extension, - s2n_ecc_evp_supported_curves_list[0]->iana_id, s2n_ecc_evp_supported_curves_list[1]->share_size, s2n_ecc_evp_supported_curves_list[1])); + ecc_pref->ecc_curves[0]->iana_id, ecc_pref->ecc_curves[1]->share_size, ecc_pref->ecc_curves[1])); S2N_WRITE_DATA_LENGTH(&key_share_extension); EXPECT_SUCCESS(s2n_extensions_client_key_share_recv(conn, &key_share_extension)); @@ -314,7 +369,7 @@ int main(int argc, char **argv) EXPECT_EQUAL(s2n_stuffer_data_available(&key_share_extension), 0); /* should not have initialized any curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < ecc_pref->count; i++) { struct s2n_ecc_evp_params *ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; EXPECT_NULL(ecc_evp_params->negotiated_curve); EXPECT_NULL(ecc_evp_params->evp_pkey); @@ -330,18 +385,21 @@ int main(int argc, char **argv) struct s2n_stuffer key_share_extension; struct s2n_ecc_evp_params first_params, second_params; int supported_curve_index = 0; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(server_conn))); + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); S2N_PREPARE_DATA_LENGTH(&key_share_extension); /* Write first curve once */ - first_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[supported_curve_index]; + first_params.negotiated_curve = ecc_pref->ecc_curves[supported_curve_index]; first_params.evp_pkey = NULL; EXPECT_SUCCESS(s2n_ecdhe_parameters_send(&first_params, &key_share_extension)); /* Write first curve again */ - second_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[supported_curve_index]; + second_params.negotiated_curve = ecc_pref->ecc_curves[supported_curve_index]; second_params.evp_pkey = NULL; EXPECT_SUCCESS(s2n_ecdhe_parameters_send(&second_params, &key_share_extension)); @@ -354,7 +412,7 @@ int main(int argc, char **argv) /* should have only copied the first set of params */ EXPECT_TRUE(s2n_public_ecc_keys_are_equal( - &server_conn->secure.client_ecc_evp_params[supported_curve_index], &first_params)); + &server_conn->secure.client_ecc_evp_params[supported_curve_index], &first_params)); EXPECT_SUCCESS(s2n_stuffer_free(&key_share_extension)); EXPECT_SUCCESS(s2n_connection_free(server_conn)); @@ -366,12 +424,15 @@ int main(int argc, char **argv) { struct s2n_connection *conn; struct s2n_stuffer key_share_extension; - EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(NULL))); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); /* Write first curve */ S2N_PREPARE_DATA_LENGTH(&key_share_extension); - EXPECT_SUCCESS(s2n_write_named_curve(&key_share_extension, s2n_ecc_evp_supported_curves_list[0])); + EXPECT_SUCCESS(s2n_write_named_curve(&key_share_extension, ecc_pref->ecc_curves[0])); S2N_WRITE_DATA_LENGTH(&key_share_extension); /* Mess up point by erasing most of it */ @@ -385,7 +446,7 @@ int main(int argc, char **argv) EXPECT_EQUAL(s2n_stuffer_data_available(&key_share_extension), 0); /* should not have initialized any curves */ - for (int i = 1; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 1; i < ecc_pref->count; i++) { struct s2n_ecc_evp_params *ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; EXPECT_NULL(ecc_evp_params->negotiated_curve); EXPECT_NULL(ecc_evp_params->evp_pkey); @@ -394,6 +455,48 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_free(&key_share_extension)); EXPECT_SUCCESS(s2n_connection_free(conn)); } + + /* Test that s2n_extensions_client_key_share_recv ignores a supported curve present in + * s2n_all_supported_curves_list but not in s2n_ecc_preferences list selected + */ + { + if (s2n_is_evp_apis_supported()) { + struct s2n_connection *conn; + struct s2n_stuffer key_share_extension; + EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&key_share_extension, s2n_extensions_client_key_share_size(conn))); + EXPECT_NOT_NULL(conn->config); + /* Explicitly set the ecc_preferences list to contain the curves p-256 and p-384 */ + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(conn->config, "20140601")); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + + /* x25519 is present in s2n_all_supported_curves_list but not in the "default" list */ + const struct s2n_ecc_named_curve *test_curve = &s2n_ecc_curve_x25519; + + S2N_PREPARE_DATA_LENGTH(&key_share_extension); + + EXPECT_SUCCESS(s2n_write_key_share(&key_share_extension, + test_curve->iana_id, test_curve->share_size, test_curve)); + + S2N_WRITE_DATA_LENGTH(&key_share_extension); + + EXPECT_SUCCESS(s2n_extensions_client_key_share_recv(conn, &key_share_extension)); + + /* should read all data */ + EXPECT_EQUAL(s2n_stuffer_data_available(&key_share_extension), 0); + + /* should not have initialized any curves */ + for (int i = 0; i < ecc_pref->count; i++) { + struct s2n_ecc_evp_params *ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; + EXPECT_NULL(ecc_evp_params->negotiated_curve); + EXPECT_NULL(ecc_evp_params->evp_pkey); + } + + EXPECT_SUCCESS(s2n_stuffer_free(&key_share_extension)); + EXPECT_SUCCESS(s2n_connection_free(conn)); + } + } } END_TEST(); diff --git a/tests/unit/s2n_ecc_evp_test.c b/tests/unit/s2n_ecc_evp_test.c index edb09e3074d..6a99669081d 100644 --- a/tests/unit/s2n_ecc_evp_test.c +++ b/tests/unit/s2n_ecc_evp_test.c @@ -28,17 +28,17 @@ int main(int argc, char **argv) { BEGIN_TEST(); { /* Test generate ephemeral keys for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params evp_params = {0}; /* Server generates a key */ - evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + evp_params.negotiated_curve = s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&evp_params)); EXPECT_SUCCESS(s2n_ecc_evp_params_free(&evp_params)); } } { /* Test failure case for generate ephemeral key when the negotiated curve is not set */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params evp_params = {0}; /* Server generates a key */ evp_params.negotiated_curve = NULL; @@ -48,18 +48,18 @@ int main(int argc, char **argv) { } { /* Test generate ephemeral key and compute shared key for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params server_params = {0}; struct s2n_ecc_evp_params client_params = {0}; struct s2n_blob server_shared = {0}; struct s2n_blob client_shared = {0}; /* Server generates a key */ - server_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + server_params.negotiated_curve = s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_params)); /* Client generates a key */ - client_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + client_params.negotiated_curve = s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_params)); /* Compute shared secret for server */ @@ -85,8 +85,8 @@ int main(int argc, char **argv) { { /* Test failure case for computing shared key for all supported curves when the server and client curves donot match */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - for (int j = 0; j < s2n_ecc_evp_supported_curves_list_len; j++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { + for (int j = 0; j < s2n_all_supported_curves_list_len; j++) { struct s2n_ecc_evp_params server_params = {0}; struct s2n_ecc_evp_params client_params = {0}; struct s2n_blob server_shared = {0}; @@ -96,12 +96,12 @@ int main(int argc, char **argv) { } /* Server generates a key */ - server_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[j]; + server_params.negotiated_curve = s2n_all_supported_curves_list[j]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_params)); /* Client generates a key */ - client_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + client_params.negotiated_curve = s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_params)); /* Compute shared secret for server */ @@ -120,7 +120,7 @@ int main(int argc, char **argv) { } { /* Test s2n_ecc_evp_write_params_point for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params test_params = {0}; struct s2n_stuffer wire; uint8_t legacy_form; @@ -128,18 +128,18 @@ int main(int argc, char **argv) { EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&wire, 0)); /* Server generates a key for a given curve */ - test_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + test_params.negotiated_curve = s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&test_params)); EXPECT_SUCCESS(s2n_ecc_evp_write_params_point(&test_params, &wire)); /* Verify output is of the right length */ uint32_t avail = s2n_stuffer_data_available(&wire); - EXPECT_EQUAL(avail, s2n_ecc_evp_supported_curves_list[i]->share_size); + EXPECT_EQUAL(avail, s2n_all_supported_curves_list[i]->share_size); /* Verify output starts with the known legacy form for curves secp256r1 * and secp384r1*/ - if (s2n_ecc_evp_supported_curves_list[i]->iana_id == TLS_EC_CURVE_SECP_256_R1 || - s2n_ecc_evp_supported_curves_list[i]->iana_id == TLS_EC_CURVE_SECP_384_R1) { + if (s2n_all_supported_curves_list[i]->iana_id == TLS_EC_CURVE_SECP_256_R1 || + s2n_all_supported_curves_list[i]->iana_id == TLS_EC_CURVE_SECP_384_R1) { EXPECT_SUCCESS(s2n_stuffer_read_uint8(&wire, &legacy_form)); EXPECT_EQUAL(legacy_form, ECDHE_PARAMS_LEGACY_FORM); } @@ -151,7 +151,7 @@ int main(int argc, char **argv) { } { /* TEST s2n_ecc_evp_read_params_point for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params write_params = {0}; struct s2n_blob point_blob; struct s2n_stuffer wire; @@ -159,16 +159,16 @@ int main(int argc, char **argv) { EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&wire, 0)); /* Server generates a key for a given curve */ - write_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + write_params.negotiated_curve = s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&write_params)); EXPECT_SUCCESS(s2n_ecc_evp_write_params_point(&write_params, &wire)); /* Read point back in */ EXPECT_SUCCESS( - s2n_ecc_evp_read_params_point(&wire, s2n_ecc_evp_supported_curves_list[i]->share_size, &point_blob)); + s2n_ecc_evp_read_params_point(&wire, s2n_all_supported_curves_list[i]->share_size, &point_blob)); /* Check that the blob looks generally correct. */ - EXPECT_EQUAL(point_blob.size, s2n_ecc_evp_supported_curves_list[i]->share_size); + EXPECT_EQUAL(point_blob.size, s2n_all_supported_curves_list[i]->share_size); EXPECT_NOT_NULL(point_blob.data); EXPECT_SUCCESS(s2n_ecc_evp_params_free(&write_params)); @@ -177,7 +177,7 @@ int main(int argc, char **argv) { } { /* TEST s2n_ecc_evp_parse_params_point for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params write_params = {0}; struct s2n_ecc_evp_params read_params = {0}; struct s2n_blob point_blob; @@ -185,8 +185,8 @@ int main(int argc, char **argv) { EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&wire, 0)); - write_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; - read_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + write_params.negotiated_curve = s2n_all_supported_curves_list[i]; + read_params.negotiated_curve = s2n_all_supported_curves_list[i]; /* Server generates a key for a given curve */ EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&write_params)); @@ -194,7 +194,7 @@ int main(int argc, char **argv) { /* Read point back in */ EXPECT_SUCCESS( - s2n_ecc_evp_read_params_point(&wire, s2n_ecc_evp_supported_curves_list[i]->share_size, &point_blob)); + s2n_ecc_evp_read_params_point(&wire, s2n_all_supported_curves_list[i]->share_size, &point_blob)); EXPECT_SUCCESS(s2n_ecc_evp_parse_params_point(&point_blob, &read_params)); /* Check that the point we read is the same we wrote */ EXPECT_TRUE(EVP_PKEY_cmp(write_params.evp_pkey, read_params.evp_pkey)); @@ -207,7 +207,7 @@ int main(int argc, char **argv) { } { /* Test read/write/parse params for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params write_params = {0}; struct s2n_ecc_evp_params read_params = {0}; struct s2n_stuffer wire; @@ -215,8 +215,8 @@ int main(int argc, char **argv) { EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&wire, 1024)); - write_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; - read_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + write_params.negotiated_curve = s2n_all_supported_curves_list[i]; + read_params.negotiated_curve = s2n_all_supported_curves_list[i]; /* Server generates a key for a given curve */ EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&write_params)); @@ -240,7 +240,7 @@ int main(int argc, char **argv) { } { /* Test generate/read/write/parse and compute shared secrets for all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params server_params = {0}; struct s2n_ecc_evp_params read_params = {0}; struct s2n_ecc_evp_params client_params = {0}; @@ -250,8 +250,8 @@ int main(int argc, char **argv) { EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&wire, 1024)); - server_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; - read_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + server_params.negotiated_curve = s2n_all_supported_curves_list[i]; + read_params.negotiated_curve = s2n_all_supported_curves_list[i]; /* Server generates a key for a given curve */ EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_params)); @@ -268,7 +268,7 @@ int main(int argc, char **argv) { EXPECT_TRUE(EVP_PKEY_cmp(server_params.evp_pkey, read_params.evp_pkey)); /* Client generates its key for the given curve */ - client_params.negotiated_curve =s2n_ecc_evp_supported_curves_list[i]; + client_params.negotiated_curve =s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_params)); /* Compute shared secret for the server */ @@ -294,7 +294,7 @@ int main(int argc, char **argv) { } { /* Test generate->write->read->compute_shared with all supported curves */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { struct s2n_ecc_evp_params server_params = {0}, client_params = {0}; struct s2n_stuffer wire; struct s2n_blob server_shared, client_shared, ecdh_params_sent, ecdh_params_received; @@ -302,7 +302,7 @@ int main(int argc, char **argv) { EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&wire, 1024)); /* Server generates a key for a given curve */ - server_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + server_params.negotiated_curve = s2n_all_supported_curves_list[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_params)); /* Server sends the public */ EXPECT_SUCCESS(s2n_ecc_evp_write_params(&server_params, &wire, &ecdh_params_sent)); diff --git a/tests/unit/s2n_ecc_preferences_test.c b/tests/unit/s2n_ecc_preferences_test.c new file mode 100644 index 00000000000..ddf59430626 --- /dev/null +++ b/tests/unit/s2n_ecc_preferences_test.c @@ -0,0 +1,72 @@ +/* + * 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 + +#include "s2n_test.h" + +#include "tls/s2n_config.h" +#include "tls/s2n_ecc_preferences.h" + +int main(int argc, char **argv) +{ + BEGIN_TEST(); + + /* s2n_config_set_ecc_preferences */ + { + struct s2n_config *config = s2n_config_new(); + + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(config, "default")); + EXPECT_EQUAL(config->ecc_preferences, &s2n_ecc_preferences_20140601); + + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(config, "dEfAUlT")); + EXPECT_EQUAL(config->ecc_preferences, &s2n_ecc_preferences_20140601); + + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(config, "20200310")); + EXPECT_EQUAL(config->ecc_preferences, &s2n_ecc_preferences_20200310); + + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(config, "20140601")); + EXPECT_EQUAL(config->ecc_preferences, &s2n_ecc_preferences_20140601); + + EXPECT_FAILURE_WITH_ERRNO(s2n_config_set_ecc_preferences(config, "notathing"), + S2N_ERR_INVALID_ECC_PREFERENCES); + + s2n_config_free(config); + } + + /* Failure case when s2n_ecc_preference lists contains a curve not present in s2n_all_supported_curves_list */ + { + const struct s2n_ecc_named_curve test_curve = { + .iana_id = 12345, + .libcrypto_nid = 0, + .name = "test_curve", + .share_size = 0 + }; + + const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_test[] = { + &test_curve, + }; + + const struct s2n_ecc_preferences s2n_ecc_preferences_new_list = { + .count = s2n_array_len(s2n_ecc_pref_list_test), + .ecc_curves = s2n_ecc_pref_list_test, + }; + + EXPECT_FAILURE(s2n_check_ecc_preferences_curves_list(&s2n_ecc_preferences_new_list)); + } + + END_TEST(); + return 0; +} diff --git a/tests/unit/s2n_extensions_server_key_share_select_test.c b/tests/unit/s2n_extensions_server_key_share_select_test.c index 1e3b9f033bd..658bffc43e7 100644 --- a/tests/unit/s2n_extensions_server_key_share_select_test.c +++ b/tests/unit/s2n_extensions_server_key_share_select_test.c @@ -18,6 +18,7 @@ #include "tls/s2n_tls.h" #include "tls/s2n_tls13.h" #include "tls/extensions/s2n_server_key_share.h" +#include "tls/s2n_ecc_preferences.h" int main(int argc, char **argv) { @@ -35,7 +36,10 @@ int main(int argc, char **argv) */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); - for (int i = 0; i < S2N_ECC_EVP_SUPPORTED_CURVES_COUNT; i++) { + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + for (int i = 0; i < ecc_pref->count; i++) { EXPECT_NULL(server_conn->secure.client_ecc_evp_params[i].evp_pkey); EXPECT_NULL(server_conn->secure.client_ecc_evp_params[i].negotiated_curve); EXPECT_NULL(server_conn->secure.mutually_supported_groups[i]); @@ -56,7 +60,10 @@ int main(int argc, char **argv) */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); - server_conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + server_conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_conn->secure.client_ecc_evp_params[0])); EXPECT_FAILURE_WITH_ERRNO(s2n_extensions_server_key_share_select(server_conn), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); @@ -72,9 +79,12 @@ int main(int argc, char **argv) * send Hello Retry Request. */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; - server_conn->secure.mutually_supported_groups[0] = s2n_ecc_evp_supported_curves_list[0]; - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + server_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + server_conn->secure.mutually_supported_groups[0] = ecc_pref->ecc_curves[0]; + for (int i = 0; i < ecc_pref->count; i++) { EXPECT_NULL(server_conn->secure.client_ecc_evp_params[i].evp_pkey); EXPECT_NULL(server_conn->secure.client_ecc_evp_params[i].negotiated_curve); } @@ -82,7 +92,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_extensions_server_key_share_select(server_conn)); */ EXPECT_FAILURE_WITH_ERRNO(s2n_extensions_server_key_share_select(server_conn), S2N_ERR_BAD_KEY_SHARE); - EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[0]); + EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[0]); /* Commented out until hello retry is implemented in issue #1607. EXPECT_TRUE(s2n_server_requires_retry(server_conn)); */ EXPECT_SUCCESS(s2n_connection_free(server_conn)); @@ -94,17 +104,20 @@ int main(int argc, char **argv) */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); - server_conn->secure.mutually_supported_groups[0] = s2n_ecc_evp_supported_curves_list[0]; - server_conn->secure.mutually_supported_groups[1] = s2n_ecc_evp_supported_curves_list[1]; + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + server_conn->secure.mutually_supported_groups[0] = ecc_pref->ecc_curves[0]; + server_conn->secure.mutually_supported_groups[1] = ecc_pref->ecc_curves[1]; EXPECT_NULL(server_conn->secure.client_ecc_evp_params[0].evp_pkey); EXPECT_NULL(server_conn->secure.client_ecc_evp_params[0].negotiated_curve); - server_conn->secure.client_ecc_evp_params[1].negotiated_curve = s2n_ecc_evp_supported_curves_list[1]; + server_conn->secure.client_ecc_evp_params[1].negotiated_curve = ecc_pref->ecc_curves[1]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_conn->secure.client_ecc_evp_params[1])); EXPECT_SUCCESS(s2n_extensions_server_key_share_select(server_conn)); - EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[1]); + EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[1]); /* Commented out until hello retry is implemented in issue #1607. EXPECT_FALSE(s2n_server_requires_retry(server_conn)); */ EXPECT_SUCCESS(s2n_connection_free(server_conn)); @@ -116,13 +129,16 @@ int main(int argc, char **argv) */ EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); - server_conn->secure.mutually_supported_groups[0] = s2n_ecc_evp_supported_curves_list[0]; - server_conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + server_conn->secure.mutually_supported_groups[0] = ecc_pref->ecc_curves[0]; + server_conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_conn->secure.client_ecc_evp_params[0])); EXPECT_SUCCESS(s2n_extensions_server_key_share_select(server_conn)); - EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[0]); + EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[0]); /* Commented out until hello retry is implemented in issue #1607. EXPECT_FALSE(s2n_server_requires_retry(server_conn)); */ EXPECT_SUCCESS(s2n_connection_free(server_conn)); diff --git a/tests/unit/s2n_key_share_extension_test.c b/tests/unit/s2n_key_share_extension_test.c index ed2a2a20785..6fc76dc8cc5 100644 --- a/tests/unit/s2n_key_share_extension_test.c +++ b/tests/unit/s2n_key_share_extension_test.c @@ -19,6 +19,7 @@ #include "tls/s2n_tls.h" #include "tls/extensions/s2n_key_share.h" +#include "crypto/s2n_ecc_evp.h" #include "testlib/s2n_testlib.h" #include "stuffer/s2n_stuffer.h" @@ -27,21 +28,21 @@ int main(int argc, char **argv) { BEGIN_TEST(); + const struct s2n_ecc_named_curve *test_curve = s2n_all_supported_curves_list[0]; /* Test s2n_ecdhe_parameters_send write with valid ecc params */ { struct s2n_stuffer out; struct s2n_ecc_evp_params ecc_evp_params; - const struct s2n_ecc_named_curve *curve = s2n_ecc_evp_supported_curves_list[0]; - ecc_evp_params.negotiated_curve = curve; + ecc_evp_params.negotiated_curve = test_curve; ecc_evp_params.evp_pkey = NULL; - EXPECT_SUCCESS(s2n_stuffer_alloc(&out, curve->share_size + 4)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&out, test_curve->share_size + 4)); EXPECT_SUCCESS(s2n_ecdhe_parameters_send(&ecc_evp_params, &out)); - S2N_STUFFER_READ_EXPECT_EQUAL(&out, curve->iana_id, uint16); - S2N_STUFFER_READ_EXPECT_EQUAL(&out, curve->share_size, uint16); - EXPECT_EQUAL(s2n_stuffer_data_available(&out), curve->share_size); + S2N_STUFFER_READ_EXPECT_EQUAL(&out, test_curve->iana_id, uint16); + S2N_STUFFER_READ_EXPECT_EQUAL(&out, test_curve->share_size, uint16); + EXPECT_EQUAL(s2n_stuffer_data_available(&out), test_curve->share_size); EXPECT_SUCCESS(s2n_ecc_evp_params_free(&ecc_evp_params)); EXPECT_SUCCESS(s2n_stuffer_free(&out)); @@ -52,18 +53,17 @@ int main(int argc, char **argv) struct s2n_stuffer out; struct s2n_ecc_evp_params ecc_evp_params; - const struct s2n_ecc_named_curve *good_curve = s2n_ecc_evp_supported_curves_list[0]; - const struct s2n_ecc_named_curve curve = { + const struct s2n_ecc_named_curve bad_curve = { .iana_id = 12345, .libcrypto_nid = 0, - .name = good_curve->name, - .share_size = good_curve->share_size + .name = test_curve->name, + .share_size = test_curve->share_size }; - ecc_evp_params.negotiated_curve = &curve; + ecc_evp_params.negotiated_curve = &bad_curve; ecc_evp_params.evp_pkey = NULL; - EXPECT_SUCCESS(s2n_stuffer_alloc(&out, curve.share_size + 4)); + EXPECT_SUCCESS(s2n_stuffer_alloc(&out, bad_curve.share_size + 4)); /* generating an ECDHE key should fail */ EXPECT_FAILURE(s2n_ecdhe_parameters_send(&ecc_evp_params, &out)); diff --git a/tests/unit/s2n_parse_client_supported_groups_list_test.c b/tests/unit/s2n_parse_client_supported_groups_list_test.c index 3ddd499edc9..ca0ca9ad9b5 100644 --- a/tests/unit/s2n_parse_client_supported_groups_list_test.c +++ b/tests/unit/s2n_parse_client_supported_groups_list_test.c @@ -19,6 +19,7 @@ #include "tls/s2n_tls13.h" #include "utils/s2n_blob.h" #include "tls/extensions/s2n_client_supported_groups.h" +#include "tls/s2n_ecc_preferences.h" int main(int argc, char **argv) { @@ -35,18 +36,23 @@ int main(int argc, char **argv) /* If the client sent a supported group that the server also supports, mutually_supported_groups * should contain the sent group. */ + EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + uint8_t data[2] = {0}; EXPECT_SUCCESS(s2n_blob_init(&iana_ids, data, sizeof(data))); EXPECT_SUCCESS(s2n_stuffer_init(&out, &iana_ids)); - EXPECT_SUCCESS(s2n_stuffer_write_uint16(&out, s2n_ecc_evp_supported_curves_list[0]->iana_id)); - EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); - for (int i = 0; i < S2N_ECC_EVP_SUPPORTED_CURVES_COUNT; i++) { + EXPECT_SUCCESS(s2n_stuffer_write_uint16(&out, ecc_pref->ecc_curves[0]->iana_id)); + + for (int i = 0; i < ecc_pref->count; i++) { EXPECT_NULL(server_conn->secure.mutually_supported_groups[i]); } - EXPECT_SUCCESS(s2n_parse_client_supported_groups_list(&iana_ids, server_conn->secure.mutually_supported_groups)); + EXPECT_SUCCESS(s2n_parse_client_supported_groups_list(server_conn, &iana_ids, server_conn->secure.mutually_supported_groups)); - EXPECT_EQUAL(server_conn->secure.mutually_supported_groups[0], s2n_ecc_evp_supported_curves_list[0]); + EXPECT_EQUAL(server_conn->secure.mutually_supported_groups[0], ecc_pref->ecc_curves[0]); EXPECT_NULL(server_conn->secure.mutually_supported_groups[1]); EXPECT_SUCCESS(s2n_connection_free(server_conn)); @@ -59,10 +65,13 @@ int main(int argc, char **argv) uint8_t data[2] = {0}; EXPECT_SUCCESS(s2n_blob_init(&iana_ids, data, sizeof(data))); EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); - EXPECT_SUCCESS(s2n_parse_client_supported_groups_list(&iana_ids, server_conn->secure.mutually_supported_groups)); + EXPECT_SUCCESS(s2n_parse_client_supported_groups_list(server_conn, &iana_ids, server_conn->secure.mutually_supported_groups)); - for (int i = 0; i < S2N_ECC_EVP_SUPPORTED_CURVES_COUNT; i++) { + for (int i = 0; i < ecc_pref->count; i++) { EXPECT_NULL(server_conn->secure.mutually_supported_groups[i]); } EXPECT_SUCCESS(s2n_connection_free(server_conn)); @@ -72,6 +81,10 @@ int main(int argc, char **argv) /* If the client has sent one mutually supported group and several groups the server does not support, * mutually_supported_groups should contain only the group that the server supports. */ + EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(server_conn->config); + const struct s2n_ecc_preferences *ecc_pref = server_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); uint8_t data[6] = {0}; EXPECT_SUCCESS(s2n_blob_init(&iana_ids, data, sizeof(data))); @@ -79,14 +92,12 @@ int main(int argc, char **argv) /* 17 and 18 are unsupported ids */ EXPECT_SUCCESS(s2n_stuffer_write_uint16(&out, 17)); EXPECT_SUCCESS(s2n_stuffer_write_uint16(&out, 18)); - EXPECT_SUCCESS(s2n_stuffer_write_uint16(&out, s2n_ecc_evp_supported_curves_list[1]->iana_id)); - - EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_SUCCESS(s2n_stuffer_write_uint16(&out, ecc_pref->ecc_curves[1]->iana_id)); - EXPECT_SUCCESS(s2n_parse_client_supported_groups_list(&iana_ids, server_conn->secure.mutually_supported_groups)); + EXPECT_SUCCESS(s2n_parse_client_supported_groups_list(server_conn, &iana_ids, server_conn->secure.mutually_supported_groups)); EXPECT_NULL(server_conn->secure.mutually_supported_groups[0]); - EXPECT_EQUAL(server_conn->secure.mutually_supported_groups[1], s2n_ecc_evp_supported_curves_list[1]); + EXPECT_EQUAL(server_conn->secure.mutually_supported_groups[1], ecc_pref->ecc_curves[1]); EXPECT_SUCCESS(s2n_connection_free(server_conn)); } diff --git a/tests/unit/s2n_server_extensions_test.c b/tests/unit/s2n_server_extensions_test.c index 3858b74b630..9f2f87e989d 100644 --- a/tests/unit/s2n_server_extensions_test.c +++ b/tests/unit/s2n_server_extensions_test.c @@ -24,6 +24,7 @@ #include "tls/extensions/s2n_server_supported_versions.h" #include "tls/extensions/s2n_server_key_share.h" #include "tls/s2n_cipher_preferences.h" +#include "tls/s2n_ecc_preferences.h" #include "utils/s2n_safety.h" @@ -40,8 +41,9 @@ const uint8_t MIN_TLS13_EXTENSION_SIZE = ( 32 * 2 ) + 1 + 8 + 6; /* expanded fro static int configure_tls13_connection(struct s2n_connection *conn) { conn->actual_protocol_version = S2N_TLS13; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[0])); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->handshake.io)); @@ -272,14 +274,17 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); struct s2n_stuffer *hello_stuffer = &conn->handshake.io; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; /* Test that s2n_server_extensions_send() only works when protocol version is TLS13 */ conn->actual_protocol_version = S2N_TLS13; /* key_share_send() requires a negotiated_curve */ - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; const uint8_t size = P256_KEYSHARE_SIZE + SUPPORTED_VERSION_SIZE; @@ -314,15 +319,18 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); struct s2n_stuffer *hello_stuffer = &conn->handshake.io; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; /* secure renegotiation is requested */ conn->secure_renegotiation = 1; /* Test that s2n_server_extensions_send() only works when protocol version is TLS13 */ conn->actual_protocol_version = S2N_TLS13; /* key_share_send() requires a negotiated_curve */ - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; /* secure_renegotiation extension not send >=TLS13*/ uint8_t size = s2n_extensions_server_key_share_send_size(conn) + s2n_extensions_server_supported_versions_size(conn); @@ -355,8 +363,11 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); struct s2n_stuffer *hello_stuffer = &conn->handshake.io; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; /* New Session Ticket Requested*/ conn->config->use_tickets = 1; @@ -366,7 +377,7 @@ int main(int argc, char **argv) conn->actual_protocol_version = S2N_TLS13; /* key_share_send() requires a negotiated_curve */ - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; /* nst extension not send >=TLS13*/ uint8_t size = s2n_extensions_server_key_share_send_size(conn) @@ -411,8 +422,11 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); struct s2n_stuffer *hello_stuffer = &conn->handshake.io; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; s2n_connection_set_cipher_preferences(conn, "test_all_tls13"); /* Test that s2n_server_extensions_send() only works when protocol version is TLS13 */ @@ -421,7 +435,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_tls13, cipher_count_tls13)); /* key_share_send() requires a negotiated_curve */ - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; uint8_t size = s2n_extensions_server_key_share_send_size(conn) + s2n_extensions_server_supported_versions_size(conn); diff --git a/tests/unit/s2n_server_hello_test.c b/tests/unit/s2n_server_hello_test.c index 96936b9df51..bda0da4a87e 100644 --- a/tests/unit/s2n_server_hello_test.c +++ b/tests/unit/s2n_server_hello_test.c @@ -22,6 +22,7 @@ #include "tls/s2n_cipher_suites.h" #include "tls/s2n_tls.h" #include "tls/s2n_tls13.h" +#include "tls/s2n_ecc_preferences.h" #include "utils/s2n_safety.h" @@ -84,11 +85,13 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); - + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_preferences = config->ecc_preferences; + EXPECT_NOT_NULL(ecc_preferences); /* configure these parameters so server hello can be sent */ conn->actual_protocol_version = S2N_TLS13; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_preferences->ecc_curves[0]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[0])); struct s2n_stuffer *hello_stuffer = &conn->handshake.io; diff --git a/tests/unit/s2n_server_key_share_extension_test.c b/tests/unit/s2n_server_key_share_extension_test.c index d32f36eff4d..fb614daea0a 100644 --- a/tests/unit/s2n_server_key_share_extension_test.c +++ b/tests/unit/s2n_server_key_share_extension_test.c @@ -20,6 +20,7 @@ #include "tls/extensions/s2n_server_key_share.h" #include "tls/extensions/s2n_client_key_share.h" +#include "tls/s2n_ecc_preferences.h" #include "tls/s2n_tls13.h" #include "testlib/s2n_testlib.h" @@ -41,12 +42,16 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + EXPECT_FAILURE(s2n_extensions_server_key_share_send_check(conn)); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_FAILURE(s2n_extensions_server_key_share_send_check(conn)); - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_FAILURE(s2n_extensions_server_key_share_send_check(conn)); EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[0])); @@ -60,12 +65,15 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_EQUAL(0, s2n_extensions_server_key_share_send_size(conn)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; - EXPECT_EQUAL(s2n_ecc_evp_supported_curves_list[0]->share_size + 8, s2n_extensions_server_key_share_send_size(conn)); + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + EXPECT_EQUAL(ecc_pref->ecc_curves[0]->share_size + 8, s2n_extensions_server_key_share_send_size(conn)); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[1]; - EXPECT_EQUAL(s2n_ecc_evp_supported_curves_list[1]->share_size + 8, s2n_extensions_server_key_share_send_size(conn)); + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[1]; + EXPECT_EQUAL(ecc_pref->ecc_curves[1]->share_size + 8, s2n_extensions_server_key_share_send_size(conn)); conn->secure.server_ecc_evp_params.negotiated_curve = NULL; EXPECT_EQUAL(0, s2n_extensions_server_key_share_send_size(conn)); @@ -78,6 +86,9 @@ int main(int argc, char **argv) struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); struct s2n_stuffer* extension_stuffer = &conn->handshake.io; /* Error if no curve have been selected */ @@ -85,44 +96,46 @@ int main(int argc, char **argv) S2N_STUFFER_READ_SKIP_TILL_END(extension_stuffer); - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; - conn->secure.client_ecc_evp_params[i].negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + for (int i = 0; i < ecc_pref->count; i++) { + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[i]; + conn->secure.client_ecc_evp_params[i].negotiated_curve = ecc_pref->ecc_curves[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[i])); EXPECT_SUCCESS(s2n_extensions_server_key_share_send(conn, extension_stuffer)); S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, TLS_EXTENSION_KEY_SHARE, uint16); - S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, s2n_ecc_evp_supported_curves_list[i]->share_size + 4, uint16); /* 4 = iana_id + share_size */ - S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, s2n_ecc_evp_supported_curves_list[i]->iana_id, uint16); - S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, s2n_ecc_evp_supported_curves_list[i]->share_size, uint16); - S2N_STUFFER_LENGTH_WRITTEN_EXPECT_EQUAL(extension_stuffer, s2n_ecc_evp_supported_curves_list[i]->share_size); + S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, ecc_pref->ecc_curves[i]->share_size + 4, uint16); /* 4 = iana_id + share_size */ + S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, ecc_pref->ecc_curves[i]->iana_id, uint16); + S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, ecc_pref->ecc_curves[i]->share_size, uint16); + S2N_STUFFER_LENGTH_WRITTEN_EXPECT_EQUAL(extension_stuffer, ecc_pref->ecc_curves[i]->share_size); - EXPECT_EQUAL(conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[i]); + EXPECT_EQUAL(conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[i]); EXPECT_SUCCESS(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); } EXPECT_SUCCESS(s2n_connection_free(conn)); } - /* Test s2n_extensions_server_key_share_send_check for failures */ + /* Test s2n_extensions_server_key_share_send for failures */ { struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); struct s2n_stuffer* extension_stuffer = &conn->handshake.io; - + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); EXPECT_FAILURE(s2n_extensions_server_key_share_send(conn, extension_stuffer)); - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_FAILURE(s2n_extensions_server_key_share_send(conn, extension_stuffer)); - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_FAILURE(s2n_extensions_server_key_share_send(conn, extension_stuffer)); EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[0])); EXPECT_SUCCESS(s2n_extensions_server_key_share_send(conn, extension_stuffer)); - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[1]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[1]; EXPECT_FAILURE(s2n_extensions_server_key_share_send(conn, extension_stuffer)); EXPECT_SUCCESS(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); @@ -131,24 +144,28 @@ int main(int argc, char **argv) /* Test s2n_extensions_server_key_share_recv with supported curves */ { - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + const struct s2n_ecc_preferences *ecc_pref = NULL; + + int i = 0; + do { struct s2n_connection *server_send_conn; struct s2n_connection *client_recv_conn; - EXPECT_NOT_NULL(server_send_conn = s2n_connection_new(S2N_SERVER)); EXPECT_NOT_NULL(client_recv_conn = s2n_connection_new(S2N_CLIENT)); - + EXPECT_NOT_NULL(server_send_conn->config); + EXPECT_NOT_NULL(ecc_pref = server_send_conn->config->ecc_preferences); + struct s2n_stuffer* extension_stuffer = &server_send_conn->handshake.io; - server_send_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; - server_send_conn->secure.client_ecc_evp_params[i].negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + server_send_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[i]; + server_send_conn->secure.client_ecc_evp_params[i].negotiated_curve = ecc_pref->ecc_curves[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_send_conn->secure.client_ecc_evp_params[i])); EXPECT_SUCCESS(s2n_extensions_server_key_share_send(server_send_conn, extension_stuffer)); S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, TLS_EXTENSION_KEY_SHARE, uint16); S2N_STUFFER_READ_EXPECT_EQUAL(extension_stuffer, s2n_extensions_server_key_share_send_size(server_send_conn) - 4, uint16); /* 4 = S2N_SIZE_OF_EXTENSION_TYPE + S2N_SIZE_OF_EXTENSION_DATA_SIZE */ - client_recv_conn->secure.client_ecc_evp_params[i].negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + client_recv_conn->secure.client_ecc_evp_params[i].negotiated_curve = ecc_pref->ecc_curves[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_recv_conn->secure.client_ecc_evp_params[i])); /* Parse key share */ @@ -156,39 +173,48 @@ int main(int argc, char **argv) EXPECT_EQUAL(s2n_stuffer_data_available(extension_stuffer), 0); EXPECT_EQUAL(server_send_conn->secure.server_ecc_evp_params.negotiated_curve->iana_id, client_recv_conn->secure.server_ecc_evp_params.negotiated_curve->iana_id); - EXPECT_EQUAL(server_send_conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[i]); + EXPECT_EQUAL(server_send_conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[i]); EXPECT_SUCCESS(s2n_connection_free(server_send_conn)); EXPECT_SUCCESS(s2n_connection_free(client_recv_conn)); - } + + i += 1; + } while (icount); } /* Test s2n_extensions_server_key_share_recv with various sample payloads */ { /* valid extension payloads */ + if (s2n_is_evp_apis_supported()) { - const char *key_share_payloads[2] = { + /* Payload values were generated by connecting to openssl */ + const char *key_share_payloads[] = { + /* x25519 */ + "001d00206b24ffd795c496899cd14b7742a5ffbdc453c23085a7f82f0ed1e0296adb9e0e", /* p256 */ "001700410474cfd75c0ab7b57247761a277e1c92b5810dacb251bb758f43e9d15aaf292c4a2be43e886425ba55653ebb7a4f32fe368bacce3df00c618645cf1eb646f22552", /* p384 */ "00180061040a27264201368540483e97d324a3093e11a5862b0a1be0cf5d8510bc47ec285f5304e9ec3ba01a0c375c3b6fa4bd0ad44aae041bb776aebc7ee92462ad481fe86f8b6e3858d5c41d0f83b0404f711832a4119aec3da2eac86266f424b50aa212" }; - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 3; i++) { struct s2n_stuffer extension_stuffer; struct s2n_connection *client_conn; EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT)); + EXPECT_NOT_NULL(client_conn->config); + const struct s2n_ecc_preferences *ecc_pref = client_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); const char *payload = key_share_payloads[i]; EXPECT_NULL(client_conn->secure.server_ecc_evp_params.negotiated_curve); EXPECT_SUCCESS(s2n_stuffer_alloc_ro_from_hex_string(&extension_stuffer, payload)); - client_conn->secure.client_ecc_evp_params[i].negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + client_conn->secure.client_ecc_evp_params[i].negotiated_curve = ecc_pref->ecc_curves[i]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_conn->secure.client_ecc_evp_params[i])); EXPECT_SUCCESS(s2n_extensions_server_key_share_recv(client_conn, &extension_stuffer)); - EXPECT_EQUAL(client_conn->secure.server_ecc_evp_params.negotiated_curve, s2n_ecc_evp_supported_curves_list[i]); + EXPECT_EQUAL(client_conn->secure.server_ecc_evp_params.negotiated_curve, ecc_pref->ecc_curves[i]); EXPECT_EQUAL(s2n_stuffer_data_available(&extension_stuffer), 0); EXPECT_SUCCESS(s2n_stuffer_free(&extension_stuffer)); @@ -196,23 +222,6 @@ int main(int argc, char **argv) } } - /* Test s2n_extensions_server_key_share_recv with unsupported curve (x25519) */ - { - struct s2n_stuffer extension_stuffer; - struct s2n_connection *client_conn; - - EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT)); - const char *x25519 = "001d00206b24ffd795c496899cd14b7742a5ffbdc453c23085a7f82f0ed1e0296adb9e0e"; - - EXPECT_NULL(client_conn->secure.server_ecc_evp_params.negotiated_curve); - EXPECT_SUCCESS(s2n_stuffer_alloc_ro_from_hex_string(&extension_stuffer, x25519)); - - EXPECT_FAILURE_WITH_ERRNO(s2n_extensions_server_key_share_recv(client_conn, &extension_stuffer), S2N_ERR_BAD_KEY_SHARE); - - EXPECT_SUCCESS(s2n_stuffer_free(&extension_stuffer)); - EXPECT_SUCCESS(s2n_connection_free(client_conn)); - } - /* Test error handling parsing broken/trancated p256 key share */ { struct s2n_stuffer extension_stuffer; @@ -236,13 +245,20 @@ int main(int argc, char **argv) struct s2n_connection *client_conn; EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT)); + EXPECT_NOT_NULL(client_conn->config); + const struct s2n_ecc_preferences *ecc_pref = client_conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + const char *p256 = "001700410474cfd75c0ab7b57247761a277e1c92b5810dacb251bb758f43e9d15aaf292c4a2be43e886425ba55653ebb7a4f32fe368bacce3df00c618645cf1eb646f22552"; EXPECT_NULL(client_conn->secure.server_ecc_evp_params.negotiated_curve); EXPECT_SUCCESS(s2n_stuffer_alloc_ro_from_hex_string(&extension_stuffer, p256)); - client_conn->secure.client_ecc_evp_params[1].negotiated_curve = s2n_ecc_evp_supported_curves_list[1]; - EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_conn->secure.client_ecc_evp_params[1])); + /* If s2n_is_evp_apis_supported is not supported, the ecc_prefs->ecc_curves contains only p-256, p-384 curves. */ + int p_384_index = s2n_is_evp_apis_supported() ? 2 : 1; + + client_conn->secure.client_ecc_evp_params[p_384_index].negotiated_curve = ecc_pref->ecc_curves[p_384_index]; + EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_conn->secure.client_ecc_evp_params[p_384_index])); EXPECT_FAILURE_WITH_ERRNO(s2n_extensions_server_key_share_recv(client_conn, &extension_stuffer), S2N_ERR_BAD_KEY_SHARE); @@ -253,9 +269,15 @@ int main(int argc, char **argv) /* Test Shared Key Generation */ { - int shared_secret_size[3] = { 32, 48, 32 }; - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) - { + const struct s2n_ecc_preferences *ecc_pref = NULL; + /* Shared Secret Size: x25519 (32), p-256 (32), p-384 (48) */ + int shared_secret_size[3] = { 32, 32, 48 }; + if (!s2n_is_evp_apis_supported()) { + /* Shared Secret Size: p-256 (32), p-384 (48) */ + shared_secret_size[1] = 48; + } + int i = 0; + do { struct s2n_connection *client_conn; struct s2n_connection *server_conn; struct s2n_stuffer client_hello_key_share; @@ -263,6 +285,10 @@ int main(int argc, char **argv) EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT)); EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(server_conn->config); + EXPECT_NOT_NULL(ecc_pref = server_conn->config->ecc_preferences); + + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&client_hello_key_share, 1024)); EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&server_hello_key_share, 1024)); @@ -278,9 +304,9 @@ int main(int argc, char **argv) EXPECT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); /* Server configures the "negotiated_curve" */ - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[i]; + server_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[i]; - for (int j = 0; j < s2n_ecc_evp_supported_curves_list_len; j++) { + for (int j = 0; j < ecc_pref->count; j++) { if (j != i) { server_conn->secure.client_ecc_evp_params[j].negotiated_curve = NULL; } @@ -288,7 +314,7 @@ int main(int argc, char **argv) EXPECT_NOT_NULL(server_conn->secure.server_ecc_evp_params.negotiated_curve); server_conn->secure.server_ecc_evp_params.evp_pkey = NULL; - EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve->iana_id, s2n_ecc_evp_supported_curves_list[i]->iana_id); + EXPECT_EQUAL(server_conn->secure.server_ecc_evp_params.negotiated_curve->iana_id, ecc_pref->ecc_curves[i]->iana_id); /* Server sends ServerHello key_share */ EXPECT_SUCCESS(s2n_extensions_server_key_share_send(server_conn, &server_hello_key_share)); @@ -332,7 +358,69 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_free(&server_hello_key_share)); EXPECT_SUCCESS(s2n_connection_free(client_conn)); EXPECT_SUCCESS(s2n_connection_free(server_conn)); - } + i += 1; + } while (i < ecc_pref->count); + } + + /* Test s2n_extensions_server_key_share_send with supported curve not in s2n_ecc_preferences list selected */ + if (s2n_is_evp_apis_supported()) { + struct s2n_connection *conn; + + EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(conn->config); + /* Explicitly set the ecc_preferences list to contain the curves p-256 and p-384 */ + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(conn->config, "20140601")); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); + + /* x25519 is present in s2n_all_supported_curves_list but not in the "default" list */ + const struct s2n_ecc_named_curve *test_curve = &s2n_ecc_curve_x25519; + + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; + + EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[0])); + + struct s2n_stuffer *extension_stuffer = &conn->handshake.io; + EXPECT_SUCCESS(s2n_extensions_server_key_share_send(conn, extension_stuffer)); + + conn->secure.client_ecc_evp_params[0].negotiated_curve = test_curve; + EXPECT_FAILURE(s2n_extensions_server_key_share_send(conn, extension_stuffer)); + + EXPECT_SUCCESS(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); + EXPECT_SUCCESS(s2n_connection_free(conn)); + } + + /* Test s2n_extensions_server_key_share_recv with supported curve not in s2n_ecc_preferences list selected */ + if (s2n_is_evp_apis_supported()) { + const struct s2n_ecc_preferences *ecc_pref = NULL; + struct s2n_connection *server_send_conn; + struct s2n_connection *client_recv_conn; + + EXPECT_NOT_NULL(server_send_conn = s2n_connection_new(S2N_SERVER)); + EXPECT_NOT_NULL(client_recv_conn = s2n_connection_new(S2N_CLIENT)); + EXPECT_NOT_NULL(server_send_conn->config); + /* Explicitly set the ecc_preferences list to contain the curves p-256 and p-384 */ + EXPECT_SUCCESS(s2n_config_set_ecc_preferences(server_send_conn->config, "20140601")); + EXPECT_NOT_NULL(ecc_pref = server_send_conn->config->ecc_preferences); + + /* x25519 is present in s2n_all_supported_curves_list but not in the "default" list */ + const struct s2n_ecc_named_curve *test_curve = &s2n_ecc_curve_x25519; + + server_send_conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + server_send_conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; + + EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&server_send_conn->secure.client_ecc_evp_params[0])); + + struct s2n_stuffer *extension_stuffer = &server_send_conn->handshake.io; + EXPECT_SUCCESS(s2n_extensions_server_key_share_send(server_send_conn, extension_stuffer)); + client_recv_conn->secure.client_ecc_evp_params[0].negotiated_curve = test_curve; + EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&client_recv_conn->secure.client_ecc_evp_params[0])); + + EXPECT_FAILURE(s2n_extensions_server_key_share_recv(client_recv_conn, extension_stuffer)); + + EXPECT_SUCCESS(s2n_connection_free(server_send_conn)); + EXPECT_SUCCESS(s2n_connection_free(client_recv_conn)); } END_TEST(); diff --git a/tests/unit/s2n_tls13_handshake_test.c b/tests/unit/s2n_tls13_handshake_test.c index a3739044ea5..f62e51ad6ac 100644 --- a/tests/unit/s2n_tls13_handshake_test.c +++ b/tests/unit/s2n_tls13_handshake_test.c @@ -31,6 +31,7 @@ #include "tls/s2n_tls13_handshake.h" #include "tls/extensions/s2n_server_key_share.h" #include "tls/extensions/s2n_client_key_share.h" +#include "tls/s2n_ecc_preferences.h" #include "utils/s2n_safety.h" /* Just to get access to the static functions / variables we need to test */ @@ -51,6 +52,8 @@ int main(int argc, char **argv) client_conn->actual_protocol_version = S2N_TLS13; server_conn->actual_protocol_version = S2N_TLS13; + + const struct s2n_ecc_preferences *server_ecc_preferences = server_conn->config->ecc_preferences; struct s2n_stuffer client_hello_key_share; struct s2n_stuffer server_hello_key_share; @@ -66,7 +69,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_extensions_client_key_share_recv(server_conn, &client_hello_key_share)); /* Server configures the "negotiated_curve" */ - server_conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + server_conn->secure.server_ecc_evp_params.negotiated_curve = server_ecc_preferences->ecc_curves[0]; /* Server sends ServerHello key_share */ EXPECT_SUCCESS(s2n_extensions_server_key_share_send(server_conn, &server_hello_key_share)); @@ -279,6 +282,9 @@ int main(int argc, char **argv) for (int i = 0; i < S2N_MAX_HANDSHAKE_LENGTH; i++) { struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(modes[m])); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); conn->actual_protocol_version = S2N_TLS13; conn->secure.cipher_suite = &s2n_tls13_aes_128_gcm_sha256; @@ -290,8 +296,8 @@ int main(int argc, char **argv) conn->handshake.handshake_type = NEGOTIATED | FULL_HANDSHAKE; conn->handshake.message_number = i; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.server_ecc_evp_params)); EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[0])); @@ -326,6 +332,9 @@ int main(int argc, char **argv) for (int i = 0; i < S2N_MAX_HANDSHAKE_LENGTH; i++) { struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(modes[m])); + EXPECT_NOT_NULL(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + EXPECT_NOT_NULL(ecc_pref); conn->actual_protocol_version = S2N_TLS12; conn->secure.cipher_suite = &s2n_tls13_aes_128_gcm_sha256; @@ -337,8 +346,8 @@ int main(int argc, char **argv) conn->handshake.handshake_type = NEGOTIATED | FULL_HANDSHAKE; conn->handshake.message_number = i; - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; - conn->secure.client_ecc_evp_params[0].negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + conn->secure.client_ecc_evp_params[0].negotiated_curve = ecc_pref->ecc_curves[0]; EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.server_ecc_evp_params)); EXPECT_SUCCESS(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.client_ecc_evp_params[0])); diff --git a/tls/extensions/s2n_client_key_share.c b/tls/extensions/s2n_client_key_share.c index 7148dc4dd1a..8f02704ef88 100644 --- a/tls/extensions/s2n_client_key_share.c +++ b/tls/extensions/s2n_client_key_share.c @@ -15,8 +15,8 @@ #include "tls/extensions/s2n_client_key_share.h" #include "tls/extensions/s2n_key_share.h" +#include "tls/s2n_ecc_preferences.h" -#include "crypto/s2n_ecc_evp.h" #include "error/s2n_errno.h" #include "stuffer/s2n_stuffer.h" #include "utils/s2n_safety.h" @@ -44,28 +44,16 @@ * - Key shares for named groups not in the client's supported_groups extension. **/ -uint32_t s2n_client_key_share_extension_size; - static int s2n_ecdhe_supported_curves_send(struct s2n_connection *conn, struct s2n_stuffer *out); -int s2n_client_key_share_init() -{ - s2n_client_key_share_extension_size = S2N_SIZE_OF_EXTENSION_TYPE - + S2N_SIZE_OF_EXTENSION_DATA_SIZE - + S2N_SIZE_OF_CLIENT_SHARES_SIZE; - - for (uint32_t i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - s2n_client_key_share_extension_size += S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_SIZE_OF_NAMED_GROUP; - s2n_client_key_share_extension_size += s2n_ecc_evp_supported_curves_list[i]->share_size; - } - - return 0; -} - int s2n_extensions_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { notnull_check(conn); notnull_check(extension); + notnull_check(conn->config); + + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); uint16_t key_shares_size; GUARD(s2n_stuffer_read_uint16(extension, &key_shares_size)); @@ -87,10 +75,10 @@ int s2n_extensions_client_key_share_recv(struct s2n_connection *conn, struct s2n bytes_processed += share_size + S2N_SIZE_OF_NAMED_GROUP + S2N_SIZE_OF_KEY_SHARE_SIZE; supported_curve = NULL; - for (uint32_t i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - if (named_group == s2n_ecc_evp_supported_curves_list[i]->iana_id) { + for (uint32_t i = 0; i < ecc_pref->count; i++) { + if (named_group == ecc_pref->ecc_curves[i]->iana_id) { supported_curve_index = i; - supported_curve = s2n_ecc_evp_supported_curves_list[i]; + supported_curve = ecc_pref->ecc_curves[i]; break; } } @@ -128,16 +116,31 @@ int s2n_extensions_client_key_share_recv(struct s2n_connection *conn, struct s2n uint32_t s2n_extensions_client_key_share_size(struct s2n_connection *conn) { + notnull_check(conn); + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); + + uint32_t s2n_client_key_share_extension_size = S2N_SIZE_OF_EXTENSION_TYPE + + S2N_SIZE_OF_EXTENSION_DATA_SIZE + + S2N_SIZE_OF_CLIENT_SHARES_SIZE; + + for (uint32_t i = 0; i < ecc_pref->count ; i++) { + s2n_client_key_share_extension_size += S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_SIZE_OF_NAMED_GROUP; + s2n_client_key_share_extension_size += ecc_pref->ecc_curves[i]->share_size; + } + return s2n_client_key_share_extension_size; } int s2n_extensions_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out) { notnull_check(out); - + notnull_check(conn); + const uint16_t extension_type = TLS_EXTENSION_KEY_SHARE; const uint16_t extension_data_size = - s2n_client_key_share_extension_size - S2N_SIZE_OF_EXTENSION_TYPE - S2N_SIZE_OF_EXTENSION_DATA_SIZE; + s2n_extensions_client_key_share_size(conn) - S2N_SIZE_OF_EXTENSION_TYPE - S2N_SIZE_OF_EXTENSION_DATA_SIZE; const uint16_t client_shares_size = extension_data_size - S2N_SIZE_OF_CLIENT_SHARES_SIZE; @@ -153,13 +156,16 @@ int s2n_extensions_client_key_share_send(struct s2n_connection *conn, struct s2n static int s2n_ecdhe_supported_curves_send(struct s2n_connection *conn, struct s2n_stuffer *out) { notnull_check(conn); + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); const struct s2n_ecc_named_curve *named_curve = NULL; struct s2n_ecc_evp_params *ecc_evp_params = NULL; - for (uint32_t i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (uint32_t i = 0; i < ecc_pref->count; i++) { ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; - named_curve = s2n_ecc_evp_supported_curves_list[i]; + named_curve = ecc_pref->ecc_curves[i]; ecc_evp_params->negotiated_curve = named_curve; ecc_evp_params->evp_pkey = NULL; diff --git a/tls/extensions/s2n_client_key_share.h b/tls/extensions/s2n_client_key_share.h index 7401148026d..0356647ac18 100644 --- a/tls/extensions/s2n_client_key_share.h +++ b/tls/extensions/s2n_client_key_share.h @@ -18,7 +18,6 @@ #include "tls/s2n_connection.h" #include "stuffer/s2n_stuffer.h" -extern int s2n_client_key_share_init(); extern int s2n_extensions_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); extern uint32_t s2n_extensions_client_key_share_size(struct s2n_connection *conn); extern int s2n_extensions_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out); diff --git a/tls/extensions/s2n_client_supported_groups.c b/tls/extensions/s2n_client_supported_groups.c index 9d3f005209d..f9f24d1c81e 100644 --- a/tls/extensions/s2n_client_supported_groups.c +++ b/tls/extensions/s2n_client_supported_groups.c @@ -19,18 +19,24 @@ #include "tls/extensions/s2n_client_supported_groups.h" #include "tls/s2n_tls.h" #include "tls/s2n_tls_parameters.h" +#include "tls/s2n_ecc_preferences.h" #include "utils/s2n_safety.h" int s2n_extensions_client_supported_groups_send(struct s2n_connection *conn, struct s2n_stuffer *out) { + notnull_check(conn); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); + GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_SUPPORTED_GROUPS)); - GUARD(s2n_stuffer_write_uint16(out, 2 + s2n_ecc_evp_supported_curves_list_len * 2)); + /* size of extension, 2 byte iana ids */ + GUARD(s2n_stuffer_write_uint16(out, 2 + ecc_pref->count * 2)); /* Curve list len */ - GUARD(s2n_stuffer_write_uint16(out, s2n_ecc_evp_supported_curves_list_len * 2)); + GUARD(s2n_stuffer_write_uint16(out, ecc_pref->count * 2)); /* Curve list */ - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - GUARD(s2n_stuffer_write_uint16(out, s2n_ecc_evp_supported_curves_list[i]->iana_id)); + for (int i = 0; i < ecc_pref->count; i++) { + GUARD(s2n_stuffer_write_uint16(out, ecc_pref->ecc_curves[i]->iana_id)); } GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_EC_POINT_FORMATS)); @@ -58,17 +64,20 @@ int s2n_recv_client_supported_groups(struct s2n_connection *conn, struct s2n_stu proposed_curves.data = s2n_stuffer_raw_read(extension, proposed_curves.size); notnull_check(proposed_curves.data); - GUARD(s2n_parse_client_supported_groups_list(&proposed_curves, conn->secure.mutually_supported_groups)); - uint16_t supported_groups_size = s2n_array_len(conn->secure.mutually_supported_groups); - if (s2n_choose_supported_group(conn->secure.mutually_supported_groups, supported_groups_size, - &conn->secure.server_ecc_evp_params) != 0) { + GUARD(s2n_parse_client_supported_groups_list(conn, &proposed_curves, conn->secure.mutually_supported_groups)); + if (s2n_choose_supported_group(conn, conn->secure.mutually_supported_groups, + &conn->secure.server_ecc_evp_params) != S2N_SUCCESS) { /* Can't agree on a curve, ECC is not allowed. Return success to proceed with the handshake. */ conn->secure.server_ecc_evp_params.negotiated_curve = NULL; } return 0; } -int s2n_parse_client_supported_groups_list(struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **supported_groups) { +int s2n_parse_client_supported_groups_list(struct s2n_connection *conn, struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **supported_groups) { + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); + struct s2n_stuffer iana_ids_in = {0}; GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids)); @@ -77,8 +86,8 @@ int s2n_parse_client_supported_groups_list(struct s2n_blob *iana_ids, const stru for (int i = 0; i < iana_ids->size / 2; i++) { uint16_t iana_id; GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id)); - for (int j = 0; j < s2n_ecc_evp_supported_curves_list_len; j++) { - const struct s2n_ecc_named_curve *supported_curve = s2n_ecc_evp_supported_curves_list[j]; + for (int j = 0; j < ecc_pref->count; j++) { + const struct s2n_ecc_named_curve *supported_curve = ecc_pref->ecc_curves[j]; if (supported_curve->iana_id == iana_id) { supported_groups[j] = supported_curve; } @@ -87,12 +96,13 @@ int s2n_parse_client_supported_groups_list(struct s2n_blob *iana_ids, const stru return 0; } -int s2n_choose_supported_group(const struct s2n_ecc_named_curve **group_options, uint16_t group_options_length, - struct s2n_ecc_evp_params *chosen_group) +int s2n_choose_supported_group(struct s2n_connection *conn, const struct s2n_ecc_named_curve **group_options, struct s2n_ecc_evp_params *chosen_group) { - eq_check(s2n_ecc_evp_supported_curves_list_len, group_options_length); + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < ecc_pref->count; i++) { if (group_options[i]) { chosen_group->negotiated_curve = group_options[i]; return 0; diff --git a/tls/extensions/s2n_client_supported_groups.h b/tls/extensions/s2n_client_supported_groups.h index 7e7d71eedf9..3261c268d05 100644 --- a/tls/extensions/s2n_client_supported_groups.h +++ b/tls/extensions/s2n_client_supported_groups.h @@ -20,5 +20,5 @@ extern int s2n_extensions_client_supported_groups_send(struct s2n_connection *conn, struct s2n_stuffer *out); extern int s2n_recv_client_supported_groups(struct s2n_connection *conn, struct s2n_stuffer *extension); -int s2n_parse_client_supported_groups_list(struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **supported_groups); -int s2n_choose_supported_group(const struct s2n_ecc_named_curve **group_options, uint16_t group_options_length, struct s2n_ecc_evp_params *chosen_group); +int s2n_parse_client_supported_groups_list(struct s2n_connection *conn, struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **supported_groups); +int s2n_choose_supported_group(struct s2n_connection *conn, const struct s2n_ecc_named_curve **group_options, struct s2n_ecc_evp_params *chosen_group); diff --git a/tls/extensions/s2n_server_key_share.c b/tls/extensions/s2n_server_key_share.c index d0d82895cdf..36589e06730 100644 --- a/tls/extensions/s2n_server_key_share.c +++ b/tls/extensions/s2n_server_key_share.c @@ -16,6 +16,8 @@ #include "tls/extensions/s2n_server_key_share.h" #include "tls/s2n_client_extensions.h" +#include "tls/s2n_ecc_preferences.h" + #include "utils/s2n_safety.h" #include "tls/s2n_tls.h" @@ -24,13 +26,17 @@ */ int s2n_extensions_server_key_share_send_check(struct s2n_connection *conn) { + notnull_check(conn); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); + const struct s2n_ecc_named_curve *server_curve, *client_curve; server_curve = conn->secure.server_ecc_evp_params.negotiated_curve; notnull_check(server_curve); int curve_index = -1; - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - if (server_curve == s2n_ecc_evp_supported_curves_list[i]) { + for (int i = 0; i < ecc_pref->count; i++) { + if (server_curve == ecc_pref->ecc_curves[i]) { curve_index = i; break; } @@ -51,7 +57,10 @@ int s2n_extensions_server_key_share_send_check(struct s2n_connection *conn) */ int s2n_extensions_server_key_share_select(struct s2n_connection *conn) { - for (uint32_t i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); + for (uint32_t i = 0; i < ecc_pref->count; i++) { /* Checks supported group and keyshare have both been sent */ if (conn->secure.client_ecc_evp_params[i].negotiated_curve && conn->secure.mutually_supported_groups[i]) { @@ -123,6 +132,9 @@ int s2n_extensions_server_key_share_recv(struct s2n_connection *conn, struct s2n { notnull_check(conn); notnull_check(extension); + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); uint16_t named_group, share_size; @@ -137,10 +149,10 @@ int s2n_extensions_server_key_share_recv(struct s2n_connection *conn, struct s2n int supported_curve_index = -1; const struct s2n_ecc_named_curve *supported_curve = NULL; - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - if (named_group == s2n_ecc_evp_supported_curves_list[i]->iana_id) { + for (int i = 0; i < ecc_pref->count; i++) { + if (named_group == ecc_pref->ecc_curves[i]->iana_id) { supported_curve_index = i; - supported_curve = s2n_ecc_evp_supported_curves_list[i]; + supported_curve = ecc_pref->ecc_curves[i]; break; } } diff --git a/tls/s2n_client_extensions.c b/tls/s2n_client_extensions.c index 040ea87f3e7..9157aefc17c 100644 --- a/tls/s2n_client_extensions.c +++ b/tls/s2n_client_extensions.c @@ -26,6 +26,7 @@ #include "tls/s2n_connection.h" #include "tls/s2n_client_extensions.h" #include "tls/s2n_resume.h" +#include "tls/s2n_ecc_preferences.h" #include "extensions/s2n_client_supported_versions.h" #include "extensions/s2n_client_signature_algorithms.h" @@ -87,10 +88,14 @@ int s2n_client_extensions_send(struct s2n_connection *conn, struct s2n_stuffer * const struct s2n_cipher_preferences *cipher_preferences; GUARD(s2n_connection_get_cipher_preferences(conn, &cipher_preferences)); + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); + const uint8_t ecc_extension_required = s2n_ecc_extension_required(cipher_preferences); if (ecc_extension_required) { /* Write ECC extensions: Supported Curves and Supported Point Formats */ - total_size += 12 + s2n_ecc_evp_supported_curves_list_len * 2; + total_size += (5 * sizeof(uint16_t) + 2 * sizeof(uint8_t)) + ecc_pref->count * 2; } const uint8_t pq_kem_extension_required = s2n_pq_kem_extension_required(cipher_preferences); diff --git a/tls/s2n_client_hello.c b/tls/s2n_client_hello.c index fda3a6e0a58..8c739dd68f8 100644 --- a/tls/s2n_client_hello.c +++ b/tls/s2n_client_hello.c @@ -35,6 +35,7 @@ #include "tls/s2n_client_extensions.h" #include "tls/s2n_tls_digest_preferences.h" #include "tls/extensions/s2n_server_key_share.h" +#include "tls/s2n_ecc_preferences.h" #include "stuffer/s2n_stuffer.h" @@ -202,8 +203,12 @@ static int s2n_parse_client_hello(struct s2n_connection *conn) GUARD(s2n_stuffer_read_uint8(in, &num_compression_methods)); GUARD(s2n_stuffer_skip_read(in, num_compression_methods)); + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_pref = conn->config->ecc_preferences; + notnull_check(ecc_pref); + /* This is going to be our default if the client has no preference. */ - conn->secure.server_ecc_evp_params.negotiated_curve = s2n_ecc_evp_supported_curves_list[0]; + conn->secure.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; uint16_t extensions_length = 0; if (s2n_stuffer_data_available(in) >= 2) { diff --git a/tls/s2n_config.c b/tls/s2n_config.c index 36d8b115eb7..9e7a2d11746 100755 --- a/tls/s2n_config.c +++ b/tls/s2n_config.c @@ -22,6 +22,7 @@ #include "crypto/s2n_fips.h" #include "tls/s2n_cipher_preferences.h" +#include "tls/s2n_ecc_preferences.h" #include "tls/s2n_tls13.h" #include "utils/s2n_safety.h" #include "crypto/s2n_hkdf.h" @@ -68,6 +69,7 @@ static int s2n_config_setup_default(struct s2n_config *config) { GUARD(s2n_config_set_cipher_preferences(config, "default")); GUARD(s2n_config_set_signature_preferences(config, "default")); + GUARD(s2n_config_set_ecc_preferences(config, "default")); return S2N_SUCCESS; } @@ -75,6 +77,7 @@ static int s2n_config_setup_tls13(struct s2n_config *config) { GUARD(s2n_config_set_cipher_preferences(config, "default_tls13")); GUARD(s2n_config_set_signature_preferences(config, "default_tls13")); + GUARD(s2n_config_set_ecc_preferences(config, "default_tls13")); return S2N_SUCCESS; } diff --git a/tls/s2n_config.h b/tls/s2n_config.h index 18ec7ada687..e76a4d537f8 100644 --- a/tls/s2n_config.h +++ b/tls/s2n_config.h @@ -54,6 +54,7 @@ struct s2n_config { const struct s2n_cipher_preferences *cipher_preferences; const struct s2n_signature_preferences *signature_preferences; + const struct s2n_ecc_preferences *ecc_preferences; void *sys_clock_ctx; void *monotonic_clock_ctx; diff --git a/tls/s2n_connection.c b/tls/s2n_connection.c index 99d711376ff..a841f7ecc91 100755 --- a/tls/s2n_connection.c +++ b/tls/s2n_connection.c @@ -40,6 +40,7 @@ #include "tls/s2n_prf.h" #include "tls/s2n_resume.h" #include "tls/s2n_kem.h" +#include "tls/s2n_ecc_preferences.h" #include "crypto/s2n_certificate.h" #include "crypto/s2n_cipher.h" @@ -291,7 +292,7 @@ static int s2n_connection_wipe_keys(struct s2n_connection *conn) s2n_x509_validator_wipe(&conn->x509_validator); GUARD(s2n_dh_params_free(&conn->secure.server_dh_params)); GUARD(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); - for (int i=0; i< s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i=0; i < S2N_ECC_EVP_SUPPORTED_CURVES_COUNT; i++) { GUARD(s2n_ecc_evp_params_free(&conn->secure.client_ecc_evp_params[i])); } GUARD(s2n_kem_free(&conn->secure.s2n_kem_keys)); diff --git a/tls/s2n_ecc_preferences.c b/tls/s2n_ecc_preferences.c new file mode 100644 index 00000000000..bf64caa3a87 --- /dev/null +++ b/tls/s2n_ecc_preferences.c @@ -0,0 +1,107 @@ +/* + * 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 + +#include "tls/s2n_ecc_preferences.h" +#include "tls/s2n_connection.h" +#include "crypto/s2n_ecc_evp.h" +#include "utils/s2n_safety.h" + +const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_20140601[] = { + &s2n_ecc_curve_secp256r1, + &s2n_ecc_curve_secp384r1, +}; + +const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_20200310[] = { +#if EVP_APIS_SUPPORTED + &s2n_ecc_curve_x25519, +#endif + &s2n_ecc_curve_secp256r1, + &s2n_ecc_curve_secp384r1, +}; + +const struct s2n_ecc_preferences s2n_ecc_preferences_20140601 = { + .count = s2n_array_len(s2n_ecc_pref_list_20140601), + .ecc_curves = s2n_ecc_pref_list_20140601, +}; + +const struct s2n_ecc_preferences s2n_ecc_preferences_20200310 = { + .count = s2n_array_len(s2n_ecc_pref_list_20200310), + .ecc_curves = s2n_ecc_pref_list_20200310, +}; + +static struct { + const char *version; + const struct s2n_ecc_preferences *preferences; +} selection[] = { + {.version = "default", .preferences = &s2n_ecc_preferences_20140601 }, + {.version = "default_tls13", .preferences = &s2n_ecc_preferences_20200310 }, + {.version = "20200310", .preferences = &s2n_ecc_preferences_20200310 }, + {.version = "20140601", .preferences = &s2n_ecc_preferences_20140601 }, + {.version = NULL, .preferences = NULL }, /* Sentinel */ +}; + +/* Checks if the ecc_curves present in s2n_ecc_preferences list is a subset of s2n_all_supported_curves_list + * maintained in s2n_ecc_evp.c */ +int s2n_check_ecc_preferences_curves_list(const struct s2n_ecc_preferences *ecc_preferences) { + int check = 1; + for (int i = 0; i < ecc_preferences->count; i++) { + const struct s2n_ecc_named_curve *named_curve = ecc_preferences->ecc_curves[i]; + int curve_found = 0; + for (int j = 0; j < s2n_all_supported_curves_list_len; j++) { + if (named_curve->iana_id == s2n_all_supported_curves_list[j]->iana_id) { + curve_found = 1; + break; + } + } + check *= curve_found; + if (check == 0) { + S2N_ERROR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + } + } + return S2N_SUCCESS; +} + +int s2n_ecc_preferences_init() +{ + for (int i = 0; selection[i].version != NULL; i++) { + const struct s2n_ecc_preferences *preferences = selection[i].preferences; + GUARD(s2n_check_ecc_preferences_curves_list(preferences)); + } + + return S2N_SUCCESS; +} + +static int s2n_find_ecc_pref_from_version(const char *version, const struct s2n_ecc_preferences **ecc_preferences) +{ + notnull_check(version); + notnull_check(ecc_preferences); + + for (int i = 0; selection[i].version != NULL; i++) { + if (!strcasecmp(version, selection[i].version)) { + *ecc_preferences = selection[i].preferences; + return S2N_SUCCESS; + } + } + + S2N_ERROR(S2N_ERR_INVALID_ECC_PREFERENCES); +} + +int s2n_config_set_ecc_preferences(struct s2n_config *config, const char *version) +{ + GUARD(s2n_find_ecc_pref_from_version(version, &config->ecc_preferences)); + return S2N_SUCCESS; +} diff --git a/tls/s2n_ecc_preferences.h b/tls/s2n_ecc_preferences.h new file mode 100644 index 00000000000..77cda2a912e --- /dev/null +++ b/tls/s2n_ecc_preferences.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include "crypto/s2n_ecc_evp.h" + +struct s2n_ecc_preferences { + uint8_t count; + const struct s2n_ecc_named_curve *const *ecc_curves; +}; +extern const struct s2n_ecc_preferences s2n_ecc_preferences_20140601; +extern const struct s2n_ecc_preferences s2n_ecc_preferences_20200310; + +int s2n_ecc_preferences_init(); +int s2n_config_set_ecc_preferences(struct s2n_config *config, const char *version); +int s2n_check_ecc_preferences_curves_list(const struct s2n_ecc_preferences *ecc_preferences); diff --git a/tls/s2n_tls13_handshake.c b/tls/s2n_tls13_handshake.c index f066c988257..1d16f7673bb 100644 --- a/tls/s2n_tls13_handshake.c +++ b/tls/s2n_tls13_handshake.c @@ -15,6 +15,7 @@ #include "tls/s2n_tls13_handshake.h" #include "tls/s2n_cipher_suites.h" +#include "tls/s2n_ecc_preferences.h" int s2n_tls13_mac_verify(struct s2n_tls13_keys *keys, struct s2n_blob *finished_verify, struct s2n_blob *wire_verify) { @@ -52,14 +53,17 @@ int s2n_tls13_keys_from_conn(struct s2n_tls13_keys *keys, struct s2n_connection int s2n_tls13_compute_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) { + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_preferences = conn->config->ecc_preferences; + notnull_check(ecc_preferences); struct s2n_ecc_evp_params *server_key = &conn->secure.server_ecc_evp_params; notnull_check(server_key); /* for now we do this tedious loop to find the matching client key selection. * this can be simplified if we get an index or a pointer to a specific key */ int selection = -1; - for (int i = 0; i < s2n_ecc_evp_supported_curves_list_len; i++) { - if (server_key->negotiated_curve->iana_id == s2n_ecc_evp_supported_curves_list[i]->iana_id) { + for (int i = 0; i < ecc_preferences->count; i++) { + if (server_key->negotiated_curve->iana_id == ecc_preferences->ecc_curves[i]->iana_id) { selection = i; break; } @@ -86,6 +90,10 @@ int s2n_tls13_compute_shared_secret(struct s2n_connection *conn, struct s2n_blob */ int s2n_tls13_handle_handshake_secrets(struct s2n_connection *conn) { + notnull_check(conn->config); + const struct s2n_ecc_preferences *ecc_preferences = conn->config->ecc_preferences; + notnull_check(ecc_preferences); + /* get tls13 key context */ s2n_tls13_connection_keys(secrets, conn); @@ -127,7 +135,7 @@ int s2n_tls13_handle_handshake_secrets(struct s2n_connection *conn) /* since shared secret has been computed, clean up keys */ GUARD(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); - for (int i = 0; i< s2n_ecc_evp_supported_curves_list_len; i++) { + for (int i = 0; i < ecc_preferences->count; i++) { GUARD(s2n_ecc_evp_params_free(&conn->secure.client_ecc_evp_params[i])); } diff --git a/utils/s2n_init.c b/utils/s2n_init.c index c9dd7865cfd..f45dd0cc716 100644 --- a/utils/s2n_init.c +++ b/utils/s2n_init.c @@ -17,6 +17,7 @@ #include "error/s2n_errno.h" #include "tls/s2n_cipher_preferences.h" +#include "tls/s2n_ecc_preferences.h" #include "tls/s2n_cipher_suites.h" #include "tls/s2n_client_extensions.h" #include "tls/extensions/s2n_client_key_share.h" @@ -41,9 +42,9 @@ int s2n_init(void) GUARD(s2n_rand_init()); GUARD(s2n_cipher_suites_init()); GUARD(s2n_cipher_preferences_init()); - GUARD(s2n_client_key_share_init()); + GUARD(s2n_ecc_preferences_init()); GUARD(s2n_config_defaults_init()); - + S2N_ERROR_IF(atexit(s2n_cleanup_atexit) != 0, S2N_ERR_ATEXIT); /* Set the supported extension mask bits for each of the recognized