diff --git a/bindings/rust/s2n-tls-sys/build.rs b/bindings/rust/s2n-tls-sys/build.rs index 03a9698cc8b..1925cfd72c3 100644 --- a/bindings/rust/s2n-tls-sys/build.rs +++ b/bindings/rust/s2n-tls-sys/build.rs @@ -39,8 +39,8 @@ struct FeatureDetector<'a> { } impl<'a> FeatureDetector<'a> { - pub fn new(out_dir: &'a Path) -> Self { - let builder = builder(); + pub fn new(out_dir: &'a Path, libcrypto: &Libcrypto) -> Self { + let builder = builder(libcrypto); Self { builder, out_dir } } @@ -89,7 +89,9 @@ impl<'a> FeatureDetector<'a> { } fn build_vendored() { - let mut build = builder(); + let libcrypto = Libcrypto::default(); + + let mut build = builder(&libcrypto); let pq = option_env("CARGO_FEATURE_PQ").is_some(); @@ -129,7 +131,7 @@ fn build_vendored() { let out_dir = PathBuf::from(env("OUT_DIR")); - let features = FeatureDetector::new(&out_dir); + let features = FeatureDetector::new(&out_dir, &libcrypto); let mut feature_names = std::fs::read_dir("lib/tests/features") .expect("missing features directory") @@ -171,7 +173,7 @@ fn build_vendored() { build.compile("s2n-tls"); // tell rust we're linking with libcrypto - println!("cargo:rustc-link-lib=crypto"); + println!("cargo:rustc-link-lib={}", libcrypto.link); // let consumers know where to find our header files let include_dir = out_dir.join("include"); @@ -180,12 +182,11 @@ fn build_vendored() { println!("cargo:include={}", include_dir.display()); } -fn builder() -> cc::Build { +fn builder(libcrypto: &Libcrypto) -> cc::Build { let mut build = cc::Build::new(); build - // pull the include path from the openssl-sys dependency - .include(env("DEP_OPENSSL_INCLUDE")) + .include(&libcrypto.include) .include("lib") .include("lib/api") .flag("-std=c11") @@ -205,16 +206,10 @@ fn builder() -> cc::Build { fn build_cmake() { let mut config = cmake::Config::new("lib"); - // sometimes openssl-sys decides not to set this value so we may need to set it anyway - if option_env("DEP_OPENSSL_ROOT").is_none() { - let include = env("DEP_OPENSSL_INCLUDE"); - if let Some(root) = Path::new(&include).parent() { - std::env::set_var("DEP_OPENSSL_ROOT", root); - } - } + let libcrypto = Libcrypto::default(); config - .register_dep("openssl") + .register_dep(&format!("aws_lc_{}", libcrypto.version)) .configure_arg("-DBUILD_TESTING=off"); if option_env("CARGO_FEATURE_PQ").is_none() { @@ -238,7 +233,7 @@ fn build_cmake() { println!("cargo:include={}", dst.join("include").display()); // tell rust we're linking with libcrypto - println!("cargo:rustc-link-lib=crypto"); + println!("cargo:rustc-link-lib={}", libcrypto.link); fn search(path: PathBuf) -> Option { if path.exists() { @@ -250,6 +245,41 @@ fn build_cmake() { } } +#[derive(PartialEq, Eq, PartialOrd, Ord)] +struct Libcrypto { + version: String, + link: String, + include: String, + root: String, +} + +impl Default for Libcrypto { + fn default() -> Self { + for (name, value) in std::env::vars() { + if let Some(version) = name.strip_prefix("DEP_AWS_LC_") { + if let Some(version) = version.strip_suffix("_INCLUDE") { + let version = version.to_string(); + + eprintln!("cargo:rerun-if-env-changed={}", name); + + let link = format!("aws_lc_{version}_crypto"); + let include = value; + let root = env(format!("DEP_AWS_LC_{version}_ROOT")); + + return Self { + version, + link, + include, + root, + }; + } + } + } + + panic!("missing DEP_AWS_LC paths"); + } +} + struct External { lib_dir: Option, include_dir: Option, diff --git a/bindings/rust/s2n-tls-sys/templates/Cargo.template b/bindings/rust/s2n-tls-sys/templates/Cargo.template index dd305e1fe07..5c7955db53f 100644 --- a/bindings/rust/s2n-tls-sys/templates/Cargo.template +++ b/bindings/rust/s2n-tls-sys/templates/Cargo.template @@ -33,10 +33,8 @@ stacktrace = [] # unstable-foo = [] [dependencies] +aws-lc-sys = { version = "0.12" } libc = "0.2" -# NOTE: The version of the `openssl-sys` crate is not the same as OpenSSL itself. -# Versions 1.0.1 - 3.0.0 are automatically discovered. -openssl-sys = { version = "0.9" } [build-dependencies] cc = { version = "1.0", features = ["parallel"] } @@ -44,8 +42,3 @@ cmake = { version = "0.1", optional = true } [dev-dependencies] jobserver = "=0.1.26" # newer versions require rust 1.66, see https://github.com/aws/s2n-tls/issues/4241 -# Build the vendored version to make it easy to test in dev -# -# NOTE: The version of the `openssl-sys` crate is not the same as OpenSSL itself. -# Versions 1.0.1 - 3.0.0 are automatically discovered. -openssl-sys = { version = "<= 0.9", features = ["vendored"] } diff --git a/tests/features/S2N_KTLS_SUPPORTED.c b/tests/features/S2N_KTLS_SUPPORTED.c index b779a832dbc..270b775f2b4 100644 --- a/tests/features/S2N_KTLS_SUPPORTED.c +++ b/tests/features/S2N_KTLS_SUPPORTED.c @@ -23,8 +23,11 @@ int main() /* Struct defined when kTLS support was added to linux * https://github.com/torvalds/linux/blob/3c4d7559159bfe1e3b94df3a657b2cda3a34e218/include/uapi/linux/tls.h */ - struct tls12_crypto_info_aes_gcm_128 aes_crypto_info; - struct tls_crypto_info crypto_info; + struct tls12_crypto_info_aes_gcm_128 aes_crypto_info_128 = { 0 }; + int aes_gcm_128_cipher_type = TLS_CIPHER_AES_GCM_128; + struct tls12_crypto_info_aes_gcm_256 aes_crypto_info_256 = { 0 }; + int aes_gcm_256_cipher_type = TLS_CIPHER_AES_GCM_256; + struct tls_crypto_info crypto_info = { 0 }; int get_record_type = TLS_GET_RECORD_TYPE; int set_record_type = TLS_SET_RECORD_TYPE; diff --git a/tls/s2n_auth_selection.c b/tls/s2n_auth_selection.c index 31ed894e1b7..564b8488027 100644 --- a/tls/s2n_auth_selection.c +++ b/tls/s2n_auth_selection.c @@ -88,7 +88,9 @@ static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg * Therefore, if a cipher suite uses a non-ephemeral kex, then any signature * algorithm that requires RSA-PSS certificates is not valid. */ - if (cipher_suite->key_exchange_alg != NULL && !cipher_suite->key_exchange_alg->is_ephemeral) { + const struct s2n_kex *kex = cipher_suite->key_exchange_alg; + POSIX_ENSURE_REF(kex); + if (!kex->is_ephemeral) { POSIX_ENSURE_NE(cert_type_for_sig_alg, S2N_PKEY_TYPE_RSA_PSS); } diff --git a/tls/s2n_cipher_suites.c b/tls/s2n_cipher_suites.c index 2ea36324938..c00e7852217 100644 --- a/tls/s2n_cipher_suites.c +++ b/tls/s2n_cipher_suites.c @@ -698,7 +698,7 @@ struct s2n_cipher_suite s2n_tls13_aes_128_gcm_sha256 = { .available = 0, .name = "TLS_AES_128_GCM_SHA256", .iana_value = { TLS_AES_128_GCM_SHA256 }, - .key_exchange_alg = NULL, + .key_exchange_alg = &s2n_tls13_kex, .auth_method = S2N_AUTHENTICATION_METHOD_TLS13, .record_alg = NULL, .all_record_algs = { &s2n_tls13_record_alg_aes128_gcm }, @@ -712,7 +712,7 @@ struct s2n_cipher_suite s2n_tls13_aes_256_gcm_sha384 = { .available = 0, .name = "TLS_AES_256_GCM_SHA384", .iana_value = { TLS_AES_256_GCM_SHA384 }, - .key_exchange_alg = NULL, + .key_exchange_alg = &s2n_tls13_kex, .auth_method = S2N_AUTHENTICATION_METHOD_TLS13, .record_alg = NULL, .all_record_algs = { &s2n_tls13_record_alg_aes256_gcm }, @@ -726,7 +726,7 @@ struct s2n_cipher_suite s2n_tls13_chacha20_poly1305_sha256 = { .available = 0, .name = "TLS_CHACHA20_POLY1305_SHA256", .iana_value = { TLS_CHACHA20_POLY1305_SHA256 }, - .key_exchange_alg = NULL, + .key_exchange_alg = &s2n_tls13_kex, .auth_method = S2N_AUTHENTICATION_METHOD_TLS13, .record_alg = NULL, .all_record_algs = { &s2n_tls13_record_alg_chacha20_poly1305 }, @@ -1276,19 +1276,15 @@ static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, continue; } - /* TLS 1.3 does not include key exchange in cipher suites */ - if (match->minimum_required_tls_version < S2N_TLS13) { - /* If the kex is not supported continue to the next candidate */ - bool kex_supported = false; - POSIX_GUARD_RESULT(s2n_kex_supported(match, conn, &kex_supported)); - if (!kex_supported) { - continue; - } - - /* If the kex is not configured correctly continue to the next candidate */ - if (s2n_result_is_error(s2n_configure_kex(match, conn))) { - continue; - } + /* If the kex is not supported continue to the next candidate */ + bool kex_supported = false; + POSIX_GUARD_RESULT(s2n_kex_supported(match, conn, &kex_supported)); + if (!kex_supported) { + continue; + } + /* If the kex is not configured correctly continue to the next candidate */ + if (s2n_result_is_error(s2n_configure_kex(match, conn))) { + continue; } /** diff --git a/tls/s2n_kex.c b/tls/s2n_kex.c index 0e5a80d8bf4..ac7529c5371 100644 --- a/tls/s2n_kex.c +++ b/tls/s2n_kex.c @@ -25,6 +25,14 @@ #include "tls/s2n_tls.h" #include "utils/s2n_safety.h" +static S2N_RESULT s2n_check_tls13(const struct s2n_cipher_suite *cipher_suite, + struct s2n_connection *conn, bool *is_supported) +{ + RESULT_ENSURE_REF(is_supported); + *is_supported = (s2n_connection_get_protocol_version(conn) >= S2N_TLS13); + return S2N_RESULT_OK; +} + static S2N_RESULT s2n_check_rsa_key(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { RESULT_ENSURE_REF(cipher_suite); @@ -135,11 +143,6 @@ static S2N_RESULT s2n_configure_kem(const struct s2n_cipher_suite *cipher_suite, return S2N_RESULT_OK; } -static S2N_RESULT s2n_no_op_configure(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn) -{ - return S2N_RESULT_OK; -} - static S2N_RESULT s2n_check_hybrid_ecdhe_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { RESULT_ENSURE_REF(cipher_suite); @@ -156,6 +159,34 @@ static S2N_RESULT s2n_check_hybrid_ecdhe_kem(const struct s2n_cipher_suite *ciph return S2N_RESULT_OK; } +static S2N_RESULT s2n_kex_configure_noop(const struct s2n_cipher_suite *cipher_suite, + struct s2n_connection *conn) +{ + return S2N_RESULT_OK; +} + +static int s2n_kex_server_key_recv_read_data_unimplemented(struct s2n_connection *conn, + struct s2n_blob *data_to_verify, struct s2n_kex_raw_server_data *kex_data) +{ + POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); +} + +static int s2n_kex_server_key_recv_parse_data_unimplemented(struct s2n_connection *conn, + struct s2n_kex_raw_server_data *kex_data) +{ + POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); +} + +static int s2n_kex_io_unimplemented(struct s2n_connection *conn, struct s2n_blob *data_to_sign) +{ + POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); +} + +static int s2n_kex_prf_unimplemented(struct s2n_connection *conn, struct s2n_blob *premaster_secret) +{ + POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); +} + const struct s2n_kex s2n_kem = { .is_ephemeral = true, .connection_supported = &s2n_check_kem, @@ -165,15 +196,16 @@ const struct s2n_kex s2n_kem = { .server_key_send = &s2n_kem_server_key_send, .client_key_recv = &s2n_kem_client_key_recv, .client_key_send = &s2n_kem_client_key_send, + .prf = &s2n_kex_prf_unimplemented, }; const struct s2n_kex s2n_rsa = { .is_ephemeral = false, .connection_supported = &s2n_check_rsa_key, - .configure_connection = &s2n_no_op_configure, - .server_key_recv_read_data = NULL, - .server_key_recv_parse_data = NULL, - .server_key_send = NULL, + .configure_connection = &s2n_kex_configure_noop, + .server_key_recv_read_data = &s2n_kex_server_key_recv_read_data_unimplemented, + .server_key_recv_parse_data = &s2n_kex_server_key_recv_parse_data_unimplemented, + .server_key_send = &s2n_kex_io_unimplemented, .client_key_recv = &s2n_rsa_client_key_recv, .client_key_send = &s2n_rsa_client_key_send, .prf = &s2n_prf_calculate_master_secret, @@ -182,7 +214,7 @@ const struct s2n_kex s2n_rsa = { const struct s2n_kex s2n_dhe = { .is_ephemeral = true, .connection_supported = &s2n_check_dhe, - .configure_connection = &s2n_no_op_configure, + .configure_connection = &s2n_kex_configure_noop, .server_key_recv_read_data = &s2n_dhe_server_key_recv_read_data, .server_key_recv_parse_data = &s2n_dhe_server_key_recv_parse_data, .server_key_send = &s2n_dhe_server_key_send, @@ -194,7 +226,7 @@ const struct s2n_kex s2n_dhe = { const struct s2n_kex s2n_ecdhe = { .is_ephemeral = true, .connection_supported = &s2n_check_ecdhe, - .configure_connection = &s2n_no_op_configure, + .configure_connection = &s2n_kex_configure_noop, .server_key_recv_read_data = &s2n_ecdhe_server_key_recv_read_data, .server_key_recv_parse_data = &s2n_ecdhe_server_key_recv_parse_data, .server_key_send = &s2n_ecdhe_server_key_send, @@ -216,6 +248,23 @@ const struct s2n_kex s2n_hybrid_ecdhe_kem = { .prf = &s2n_hybrid_prf_master_secret, }; +/* TLS1.3 key exchange is implemented differently from previous versions and does + * not currently require most of the functionality offered by s2n_kex. + * This structure primarily acts as a placeholder, so its methods are either + * noops or unimplemented. + */ +const struct s2n_kex s2n_tls13_kex = { + .is_ephemeral = true, + .connection_supported = &s2n_check_tls13, + .configure_connection = &s2n_kex_configure_noop, + .server_key_recv_read_data = &s2n_kex_server_key_recv_read_data_unimplemented, + .server_key_recv_parse_data = &s2n_kex_server_key_recv_parse_data_unimplemented, + .server_key_send = &s2n_kex_io_unimplemented, + .client_key_recv = &s2n_kex_io_unimplemented, + .client_key_send = &s2n_kex_io_unimplemented, + .prf = &s2n_kex_prf_unimplemented, +}; + S2N_RESULT s2n_kex_supported(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { RESULT_ENSURE_REF(cipher_suite); diff --git a/tls/s2n_kex.h b/tls/s2n_kex.h index 9f31b0bd2a5..f229914e2ad 100644 --- a/tls/s2n_kex.h +++ b/tls/s2n_kex.h @@ -40,6 +40,7 @@ extern const struct s2n_kex s2n_rsa; extern const struct s2n_kex s2n_dhe; extern const struct s2n_kex s2n_ecdhe; extern const struct s2n_kex s2n_hybrid_ecdhe_kem; +extern const struct s2n_kex s2n_tls13_kex; S2N_RESULT s2n_kex_supported(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported); S2N_RESULT s2n_configure_kex(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn);