diff --git a/rustls-libssl/Cargo.lock b/rustls-libssl/Cargo.lock index 746a00a..4f4a5a2 100644 --- a/rustls-libssl/Cargo.lock +++ b/rustls-libssl/Cargo.lock @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.5" +version = "0.23.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afabcee0551bd1aa3e18e5adbf2c0544722014b899adb31bd186ec638d3da97e" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ "aws-lc-rs", "log", @@ -450,15 +450,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048a63e5b3ac996d78d402940b5fa47973d2d080c6c6fffa1d0f19c4445310b7" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.3" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "aws-lc-rs", "ring", diff --git a/rustls-libssl/MATRIX.md b/rustls-libssl/MATRIX.md index 950adf5..f638584 100644 --- a/rustls-libssl/MATRIX.md +++ b/rustls-libssl/MATRIX.md @@ -96,7 +96,7 @@ | `SSL_CTX_get_info_callback` | | | | | `SSL_CTX_get_keylog_callback` | | | | | `SSL_CTX_get_max_early_data` | | :white_check_mark: | :white_check_mark: | -| `SSL_CTX_get_num_tickets` | | | | +| `SSL_CTX_get_num_tickets` | | | :white_check_mark: | | `SSL_CTX_get_options` | | :white_check_mark: | :white_check_mark: | | `SSL_CTX_get_quiet_shutdown` | | | | | `SSL_CTX_get_record_padding_callback_arg` | | | | @@ -165,7 +165,7 @@ | `SSL_CTX_set_next_proto_select_cb` [^nextprotoneg] | :white_check_mark: | | :exclamation: [^stub] | | `SSL_CTX_set_next_protos_advertised_cb` [^nextprotoneg] | | :white_check_mark: | :exclamation: [^stub] | | `SSL_CTX_set_not_resumable_session_callback` | | | | -| `SSL_CTX_set_num_tickets` | | | | +| `SSL_CTX_set_num_tickets` | | | :white_check_mark: | | `SSL_CTX_set_options` | :white_check_mark: | :white_check_mark: | :white_check_mark: | | `SSL_CTX_set_post_handshake_auth` | :white_check_mark: | | :exclamation: [^stub] | | `SSL_CTX_set_psk_client_callback` [^psk] | | | | @@ -343,7 +343,7 @@ | `SSL_get_info_callback` | | | | | `SSL_get_key_update_type` | | | | | `SSL_get_max_early_data` | | | | -| `SSL_get_num_tickets` | | | | +| `SSL_get_num_tickets` | | | :white_check_mark: | | `SSL_get_options` | | :white_check_mark: | :white_check_mark: | | `SSL_get_peer_cert_chain` | :white_check_mark: | :white_check_mark: | :white_check_mark: | | `SSL_get_peer_finished` | | | | @@ -444,7 +444,7 @@ | `SSL_set_max_early_data` | | | | | `SSL_set_msg_callback` | | | | | `SSL_set_not_resumable_session_callback` | | | | -| `SSL_set_num_tickets` | | | | +| `SSL_set_num_tickets` | | | :white_check_mark: | | `SSL_set_options` | | :white_check_mark: | :white_check_mark: | | `SSL_set_post_handshake_auth` | | | :exclamation: [^stub] | | `SSL_set_psk_client_callback` [^psk] | | | | diff --git a/rustls-libssl/build.rs b/rustls-libssl/build.rs index 3f44ac0..641bd2e 100644 --- a/rustls-libssl/build.rs +++ b/rustls-libssl/build.rs @@ -83,6 +83,7 @@ const ENTRYPOINTS: &[&str] = &[ "SSL_CTX_get_client_CA_list", "SSL_CTX_get_ex_data", "SSL_CTX_get_max_early_data", + "SSL_CTX_get_num_tickets", "SSL_CTX_get_options", "SSL_CTX_get_timeout", "SSL_CTX_get_verify_callback", @@ -116,6 +117,7 @@ const ENTRYPOINTS: &[&str] = &[ "SSL_CTX_set_msg_callback", "SSL_CTX_set_next_proto_select_cb", "SSL_CTX_set_next_protos_advertised_cb", + "SSL_CTX_set_num_tickets", "SSL_CTX_set_options", "SSL_CTX_set_post_handshake_auth", "SSL_CTX_set_session_id_context", @@ -144,6 +146,7 @@ const ENTRYPOINTS: &[&str] = &[ "SSL_get_error", "SSL_get_ex_data", "SSL_get_ex_data_X509_STORE_CTX_idx", + "SSL_get_num_tickets", "SSL_get_options", "SSL_get_peer_cert_chain", "SSL_get_peer_signature_type_nid", @@ -190,6 +193,7 @@ const ENTRYPOINTS: &[&str] = &[ "SSL_set_connect_state", "SSL_set_ex_data", "SSL_set_fd", + "SSL_set_num_tickets", "SSL_set_options", "SSL_set_post_handshake_auth", "SSL_set_quiet_shutdown", diff --git a/rustls-libssl/src/conf.rs b/rustls-libssl/src/conf.rs index 1df44d0..ebd586c 100644 --- a/rustls-libssl/src/conf.rs +++ b/rustls-libssl/src/conf.rs @@ -262,6 +262,61 @@ impl SslConfigCtx { } } + fn no_tickets(&mut self, path: Option<&str>) -> Result { + debug_assert!(path.is_none()); + + match &self.state { + State::Validating => {} + State::ApplyingToCtx(ctx) => { + ctx.get_mut().set_options(crate::SSL_OP_NO_TICKET); + } + State::ApplyingToSsl(ssl) => { + ssl.get_mut().set_options(crate::SSL_OP_NO_TICKET); + } + }; + + // OpenSSL's implementation returns 1 (NotApplied) even when applying (???) + Ok(ActionResult::NotApplied) + } + + fn options(&mut self, opts: Option<&str>) -> Result { + let opts = match opts { + Some(path) => path, + None => return Ok(ActionResult::ValueRequired), + }; + + for part in opts.split(',').map(|part| part.trim()) { + let flag = match part.starts_with('-') { + true => OptionFlag::Disable, + false => OptionFlag::Enable, + }; + match part { + "SessionTicket" | "-SessionTicket" => self.session_ticket_option(flag)?, + _ => {} + } + } + + Ok(ActionResult::Applied) + } + + fn session_ticket_option(&mut self, flag: OptionFlag) -> Result<(), Error> { + if !self.flags.is_server() { + return Err(Error::bad_data( + "SessionTicket is only supported for servers", + )); + } + let opts = match &self.state { + State::ApplyingToCtx(ctx) => &mut ctx.get_mut().raw_options, + State::ApplyingToSsl(ssl) => &mut ssl.get_mut().raw_options, + State::Validating => return Ok(()), + }; + match flag { + OptionFlag::Disable => *opts |= crate::SSL_OP_NO_TICKET, + OptionFlag::Enable => *opts &= !crate::SSL_OP_NO_TICKET, + } + Ok(()) + } + fn parse_protocol_version(proto: Option<&str>) -> Option { Some(match proto { Some("None") => 0, @@ -318,8 +373,8 @@ pub(super) enum ValueType { File = 0x2, /// The option value is a directory name. Dir = 0x3, - // The option value is not used. - //None = 0x4, + /// The option value is not used. + None = 0x4, } impl From for c_int { @@ -401,7 +456,6 @@ enum ActionResult { /// /// For example, if no `SSL_CTX` has been set a [`CommandAction`] may return `NotApplied` after /// validating the command value. - #[allow(dead_code)] // TODO(XXX): remove with first ref. NotApplied = 1, /// The action value was recognized and applied. Applied = 2, @@ -465,6 +519,14 @@ impl From for c_uint { } } +/// Representation of whether an "Options" value flag should be enabled or disabled. +enum OptionFlag { + /// The option flag value begins with '-' indicating it should be disabled. + Disable, + /// The option flag does not begin with '-' indicating it should be enabled. + Enable, +} + /// All the [`Command`]s that are supported by [`SslConfigCtx`]. const SUPPORTED_COMMANDS: &[Command] = &[ Command { @@ -516,10 +578,23 @@ const SUPPORTED_COMMANDS: &[Command] = &[ value_type: ValueType::File, action: SslConfigCtx::verify_ca_file, }, + Command { + name_file: None, + name_cmdline: Some("no_ticket"), + flags: Flags(Flags::ANY), + value_type: ValueType::None, + action: SslConfigCtx::no_tickets, + }, + Command { + name_file: Some("Options"), + name_cmdline: None, + flags: Flags(Flags::ANY), + value_type: ValueType::String, + action: SslConfigCtx::options, + }, // Some commands that would be reasonable to implement in the future: // - ClientCAFile/ClientCAPath // - Options - // - SessionTicket/-no_ticket // - CANames (?) // - Groups/-groups // - SignatureAlgorithms/-sigalgs diff --git a/rustls-libssl/src/entry.rs b/rustls-libssl/src/entry.rs index 56c6e4c..53733d5 100644 --- a/rustls-libssl/src/entry.rs +++ b/rustls-libssl/src/entry.rs @@ -176,6 +176,19 @@ entry! { } } +entry! { + pub fn _SSL_CTX_set_num_tickets(ctx: *mut SSL_CTX, num_tickets: usize) -> c_int { + try_clone_arc!(ctx).get_mut().set_num_tickets(num_tickets); + C_INT_SUCCESS + } +} + +entry! { + pub fn _SSL_CTX_get_num_tickets(ctx: *const SSL_CTX) -> usize { + try_clone_arc!(ctx).get().get_num_tickets() + } +} + entry! { pub fn _SSL_CTX_ctrl(ctx: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long { let ctx = try_clone_arc!(ctx); @@ -205,7 +218,9 @@ entry! { C_INT_SUCCESS as c_long } Ok(SslCtrl::GetMaxProtoVersion) => ctx.get().get_max_protocol_version().into(), - Ok(SslCtrl::SetTlsExtHostname) | Ok(SslCtrl::SetTlsExtServerNameCallback) => { + Ok(SslCtrl::SetTlsExtHostname) + | Ok(SslCtrl::SetTlsExtServerNameCallback) + | Ok(SslCtrl::SetTlsExtTicketKeyCallback) => { // not a defined operation in the OpenSSL API 0 } @@ -622,6 +637,10 @@ entry! { ctx.get_mut().set_servername_callback(fp); C_INT_SUCCESS as c_long } + Ok(SslCtrl::SetTlsExtTicketKeyCallback) => { + log::warn!("ignoring tls ext ticket key callback"); + C_INT_SUCCESS as c_long + } _ => 0, } } @@ -842,6 +861,7 @@ entry! { } // not a defined operation in the OpenSSL API Ok(SslCtrl::SetTlsExtServerNameCallback) + | Ok(SslCtrl::SetTlsExtTicketKeyCallback) | Ok(SslCtrl::SetTlsExtServerNameArg) | Ok(SslCtrl::SetSessCacheSize) | Ok(SslCtrl::GetSessCacheSize) @@ -872,6 +892,19 @@ entry! { } } +entry! { + pub fn _SSL_set_num_tickets(ssl: *mut SSL, num_tickets: usize) -> c_int { + try_clone_arc!(ssl).get_mut().set_num_tickets(num_tickets); + C_INT_SUCCESS + } +} + +entry! { + pub fn _SSL_get_num_tickets(ssl: *const SSL) -> usize { + try_clone_arc!(ssl).get().get_num_tickets() + } +} + entry! { pub fn _SSL_set_alpn_protos( ssl: *mut SSL, @@ -1859,6 +1892,7 @@ num_enum! { SetTlsExtServerNameCallback = 53, SetTlsExtServerNameArg = 54, SetTlsExtHostname = 55, + SetTlsExtTicketKeyCallback = 72, SetChain = 88, SetMinProtoVersion = 123, SetMaxProtoVersion = 124, diff --git a/rustls-libssl/src/error.rs b/rustls-libssl/src/error.rs index 7e5e0b8..8e95290 100644 --- a/rustls-libssl/src/error.rs +++ b/rustls-libssl/src/error.rs @@ -174,6 +174,13 @@ impl From for c_int { } } +impl From for usize { + fn from(_: Error) -> Self { + // ditto + 0 + } +} + impl From for MysteriouslyOppositeReturnValue { fn from(_: Error) -> Self { // for a small subset of OpenSSL functions (return 1 on error) diff --git a/rustls-libssl/src/lib.rs b/rustls-libssl/src/lib.rs index 3a8ede3..257df31 100644 --- a/rustls-libssl/src/lib.rs +++ b/rustls-libssl/src/lib.rs @@ -14,7 +14,7 @@ use openssl_sys::{ use rustls::client::Resumption; use rustls::crypto::aws_lc_rs as provider; use rustls::pki_types::{CertificateDer, ServerName}; -use rustls::server::{Accepted, Acceptor}; +use rustls::server::{Accepted, Acceptor, ProducesTickets}; use rustls::{ CipherSuite, ClientConfig, ClientConnection, Connection, HandshakeKind, ProtocolVersion, RootCertStore, ServerConfig, SignatureScheme, SupportedProtocolVersion, @@ -411,6 +411,8 @@ pub struct SslContext { ex_data: ex_data::ExData, versions: EnabledVersions, caches: cache::SessionCaches, + ticketer: Option>, + num_tickets: usize, raw_options: u64, verify_mode: VerifyMode, verify_depth: c_int, @@ -428,11 +430,20 @@ pub struct SslContext { impl SslContext { fn new(method: &'static SslMethod) -> Self { + // If the method indicates possible server use, and we're not using miri, construct + // a ticketer. Doing so is wasteful for a client, and incompatible with miri + // (due to calls to a foreign function, `RAND_bytes`). + let ticketer = match !method.server_versions.is_empty() && cfg!(not(miri)) { + true => provider::Ticketer::new().ok(), + false => None, + }; Self { method, ex_data: ex_data::ExData::default(), versions: EnabledVersions::default(), caches: cache::SessionCaches::default(), + ticketer, + num_tickets: 2, // match OpenSSL default: see `man SSL_CTX_set_num_tickets` raw_options: 0, verify_mode: VerifyMode::default(), verify_depth: -1, @@ -478,6 +489,14 @@ impl SslContext { self.raw_options } + fn get_num_tickets(&self) -> usize { + self.num_tickets + } + + fn set_num_tickets(&mut self, num: usize) { + self.num_tickets = num + } + fn clear_options(&mut self, clear: u64) -> u64 { self.raw_options &= !clear; self.raw_options @@ -712,6 +731,7 @@ struct Ssl { ex_data: ex_data::ExData, versions: EnabledVersions, raw_options: u64, + num_tickets: usize, mode: ConnMode, verify_mode: VerifyMode, verify_depth: c_int, @@ -752,6 +772,7 @@ impl Ssl { ex_data: ex_data::ExData::default(), versions: inner.versions.clone(), raw_options: inner.raw_options, + num_tickets: inner.num_tickets, mode: inner.method.mode(), verify_mode: inner.verify_mode, verify_depth: inner.verify_depth, @@ -802,6 +823,14 @@ impl Ssl { self.raw_options } + fn get_num_tickets(&self) -> usize { + self.num_tickets + } + + fn set_num_tickets(&mut self, num: usize) { + self.num_tickets = num + } + fn clear_options(&mut self, clear: u64) -> u64 { self.raw_options &= !clear; self.raw_options @@ -1103,7 +1132,14 @@ impl Ssl { config.alpn_protocols = mem::take(&mut self.alpn); config.max_early_data_size = self.max_early_data; - config.send_tls13_tickets = 2; // match OpenSSL default: see `man SSL_CTX_set_num_tickets` + + if let Some(ticketer) = &self.ctx.get().ticketer { + if (self.raw_options & SSL_OP_NO_TICKET) != SSL_OP_NO_TICKET { + config.ticketer = ticketer.clone(); + } + } + + config.send_tls13_tickets = self.num_tickets; let cache = self.ctx.get_mut().caches.get_server(); config.session_storage = cache.clone(); @@ -1654,6 +1690,8 @@ impl EnabledVersions { } } +pub(crate) const SSL_OP_NO_TICKET: u64 = 1 << 14; // See ssl.h + #[cfg(test)] mod tests { use super::*; diff --git a/rustls-libssl/tests/config.c b/rustls-libssl/tests/config.c index 913ad74..4a4b4d5 100644 --- a/rustls-libssl/tests/config.c +++ b/rustls-libssl/tests/config.c @@ -3,6 +3,7 @@ */ #include +#include #include #include @@ -14,38 +15,46 @@ static const int conf_flags[] = {SSL_CONF_FLAG_SERVER, SSL_CONF_FLAG_CLIENT, #define NUM_FLAGS (sizeof(conf_flags) / sizeof(conf_flags[0])) -static const char *supported_cmds[] = {"-min_protocol", - CUSTOM_PREFIX "min_protocol", - "MinProtocol", - CUSTOM_PREFIX "MinProtocol", - - "-max_protocol", - CUSTOM_PREFIX "max_protocol", - "MaxProtocol", - CUSTOM_PREFIX "MaxProtocol", - - "VerifyMode", - CUSTOM_PREFIX "VerifyMode", - - "-cert", - CUSTOM_PREFIX "cert", - "Certificate", - CUSTOM_PREFIX "Certificate", - - "-key", - CUSTOM_PREFIX "key", - "PrivateKey", - CUSTOM_PREFIX "PrivateKey" - - "-verifyCApath", - CUSTOM_PREFIX "verifyCApath", - "VerifyCAPath", - CUSTOM_PREFIX "VerifyCAPath", - - "-verifyCAfile", - CUSTOM_PREFIX "verifyCAfile", - "VerifyCAFile", - CUSTOM_PREFIX "VerifyCAFile"}; +static const char *supported_cmds[] = { + "-min_protocol", + CUSTOM_PREFIX "min_protocol", + "MinProtocol", + CUSTOM_PREFIX "MinProtocol", + + "-max_protocol", + CUSTOM_PREFIX "max_protocol", + "MaxProtocol", + CUSTOM_PREFIX "MaxProtocol", + + "VerifyMode", + CUSTOM_PREFIX "VerifyMode", + + "-cert", + CUSTOM_PREFIX "cert", + "Certificate", + CUSTOM_PREFIX "Certificate", + + "-key", + CUSTOM_PREFIX "key", + "PrivateKey", + CUSTOM_PREFIX "PrivateKey" + + "-verifyCApath", + CUSTOM_PREFIX "verifyCApath", + "VerifyCAPath", + CUSTOM_PREFIX "VerifyCAPath", + + "-verifyCAfile", + CUSTOM_PREFIX "verifyCAfile", + "VerifyCAFile", + CUSTOM_PREFIX "VerifyCAFile" + + "-no_ticket", + CUSTOM_PREFIX "no_ticket", + + "Options", + CUSTOM_PREFIX "Options", +}; #define NUM_SUPPORTED_CMDS (sizeof(supported_cmds) / sizeof(supported_cmds[0])) @@ -350,6 +359,137 @@ void test_verify_ca_path_file(void) { SSL_CTX_free(ctx); } +#define NO_TICKET_SET(X) (((X)&SSL_OP_NO_TICKET) == SSL_OP_NO_TICKET) + +void test_no_ticket(void) { + SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); + assert(cctx != NULL); + + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CMDLINE); + + printf("\tPre-ctx:\n"); + printf("\t\tcmd -no_ticket NULL returns %d\n", + SSL_CONF_cmd(cctx, "-no_ticket", NULL)); + + SSL_CTX *ctx = SSL_CTX_new(TLS_method()); + assert(ctx != NULL); + SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); + + printf("\tWith ctx:\n"); + printf("\t\tSSL_OP_NO_TICKET before: %d\n", + NO_TICKET_SET(SSL_CTX_get_options(ctx))); + printf("\t\tcmd -no_ticket NULL returns %d\n", + SSL_CONF_cmd(cctx, "-no_ticket", NULL)); + printf("\t\tSSL_OP_NO_TICKET after: %d\n", + NO_TICKET_SET(SSL_CTX_get_options(ctx))); + + SSL_CTX_clear_options( + ctx, SSL_OP_NO_TICKET); // Reset the ctx opts since ssl will inherit. + + SSL *ssl = SSL_new(ctx); + assert(ssl != NULL); + SSL_CONF_CTX_set_ssl(cctx, ssl); + + printf("\tWith ssl:\n"); + printf("\t\tSSL_OP_NO_TICKET before: %d\n", + NO_TICKET_SET(SSL_get_options(ssl))); + printf("\t\tcmd -no_ticket NULL returns %d\n", + SSL_CONF_cmd(cctx, "-no_ticket", NULL)); + printf("\t\tSSL_OP_NO_TICKET after: %d\n", + NO_TICKET_SET(SSL_get_options(ssl))); + + assert(SSL_CONF_CTX_finish(cctx)); + SSL_CONF_CTX_free(cctx); + SSL_CTX_free(ctx); + SSL_free(ssl); +} + +void set_options_values(SSL_CONF_CTX *cctx, SSL_CTX *ctx, SSL *ssl, + uint64_t opts, const char *values) { + // Put the CTX and SSL_CTX into a known options state beforehand. + if (ctx != NULL) { + SSL_CTX_clear_options(ctx, UINT64_MAX); + SSL_CTX_set_options(ctx, opts); + printf("\t\tSSL_CTX_get_options before: 0x%lx\n", SSL_CTX_get_options(ctx)); + } + if (ssl != NULL) { + SSL_clear_options(ssl, UINT64_MAX); + SSL_set_options(ssl, opts); + printf("\t\tSSL_get_options before: 0x%lx\n", SSL_get_options(ssl)); + } + + // Apply the Options command + printf("\t\tSSL_CONF_cmd Options %s == %d\n", + values == NULL ? "NULL" : values, + SSL_CONF_cmd(cctx, "Options", values)); + + if (ctx != NULL) { + printf("\t\tSSL_CTX_get_options after: 0x%lx\n", SSL_CTX_get_options(ctx)); + } + if (ssl != NULL) { + printf("\t\tSSL_get_options after: 0x%lx\n", SSL_get_options(ssl)); + } +} + +void test_options_session_ticket_variations(SSL_CONF_CTX *cctx, SSL_CTX *ctx, + SSL *ssl) { + // Try NULL + set_options_values(cctx, ctx, ssl, 0, NULL); + // NOTE: we don't try invalid/unknown values because Rustls will ignore them + // without error + // while OpenSSL will erorr. + + // Test enabling the option when it has not been disabled, and when it has + // been disabled + set_options_values(cctx, ctx, ssl, 0, "SessionTicket"); + set_options_values(cctx, ctx, ssl, SSL_OP_NO_TICKET, "SessionTicket"); + + // Test disabling the option when it has been enabled, and when it has not + // been enabled + set_options_values(cctx, ctx, ssl, SSL_OP_NO_TICKET, "-SessionTicket"); + set_options_values(cctx, ctx, ssl, 0, "-SessionTicket"); + + // Test enabling and disabling the option in the same command for both initial + // states + set_options_values(cctx, ctx, ssl, 0, "SessionTicket,-SessionTicket"); + set_options_values(cctx, ctx, ssl, SSL_OP_NO_TICKET, + "SessionTicket,-SessionTicket"); + set_options_values(cctx, ctx, ssl, SSL_OP_NO_TICKET, + "-SessionTicket,SessionTicket"); + set_options_values(cctx, ctx, ssl, 0, "-SessionTicket,SessionTicket"); +} + +void test_options_session_ticket(void) { + SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); + assert(cctx != NULL); + + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); + + printf("\tPre-ctx, no server flag:\n"); + test_options_session_ticket_variations(cctx, NULL, NULL); + + printf("\tPre-ctx, with server flag: \n"); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); + test_options_session_ticket_variations(cctx, NULL, NULL); + + SSL_CTX *ctx = SSL_CTX_new(TLS_method()); + assert(ctx != NULL); + SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); + printf("\tWith ctx\n"); + test_options_session_ticket_variations(cctx, ctx, NULL); + + SSL *ssl = SSL_new(ctx); + assert(ssl != NULL); + SSL_CONF_CTX_set_ssl(cctx, ssl); + printf("\tWith ssl\n"); + test_options_session_ticket_variations(cctx, NULL, ssl); + + assert(SSL_CONF_CTX_finish(cctx)); + SSL_CONF_CTX_free(cctx); + SSL_CTX_free(ctx); + SSL_free(ssl); +} + int main(void) { printf("Supported commands:\n"); printf("no base flags, default prefix:\n"); @@ -381,4 +521,10 @@ int main(void) { printf("VerifyCAPath/VerifyCAFile:\n"); test_verify_ca_path_file(); + + printf("no_ticket\n"); + test_no_ticket(); + + printf("Options SessionTicket\n"); + test_options_session_ticket(); } diff --git a/rustls-libssl/tests/nginx.conf b/rustls-libssl/tests/nginx.conf index 62cef49..c685525 100644 --- a/rustls-libssl/tests/nginx.conf +++ b/rustls-libssl/tests/nginx.conf @@ -14,6 +14,7 @@ http { listen 8443 ssl; ssl_certificate ../../../test-ca/rsa/server.cert; ssl_certificate_key ../../../test-ca/rsa/server.key; + ssl_session_tickets off; server_name localhost; location = / { @@ -50,6 +51,7 @@ http { # per-worker resumption listen 8444 ssl; ssl_session_cache builtin; + ssl_session_tickets off; ssl_certificate ../../../test-ca/rsa/server.cert; ssl_certificate_key ../../../test-ca/rsa/server.key; server_name localhost; @@ -75,11 +77,11 @@ http { # per-worker & per-server resumption listen 8445 ssl; ssl_session_cache builtin shared:port8445:1M; + ssl_session_tickets off; ssl_certificate ../../../test-ca/rsa/server.cert; ssl_certificate_key ../../../test-ca/rsa/server.key; server_name localhost; - location = / { return 200 "hello world\n"; } @@ -102,10 +104,6 @@ http { # per-server resumption listen 8446 ssl; ssl_session_cache shared:port8446:1M; - # We don't presently support session tickets and on nginx 1.23.2+ the "shared" - # ssl_session_cache is also used to generate, store, and rotate TLS session - # ticket keys. With this enabled, the 'shared' cache will not function. - # TODO(XXX): revisit with ticket support, https://github.com/rustls/rustls-openssl-compat/issues/30 ssl_session_tickets off; ssl_certificate ../../../test-ca/rsa/server.cert; ssl_certificate_key ../../../test-ca/rsa/server.key; @@ -127,4 +125,29 @@ http { return 200 "reused:$ssl_session_reused\n"; } } + + server { + # session ticket resumption + listen 8449 ssl; + ssl_session_tickets on; + ssl_certificate ../../../test-ca/rsa/server.cert; + ssl_certificate_key ../../../test-ca/rsa/server.key; + server_name localhost; + + location = / { + return 200 "hello world\n"; + } + + location /ssl-agreed { + return 200 "protocol:$ssl_protocol,cipher:$ssl_cipher\n"; + } + + location /ssl-server-name { + return 200 "server-name:$ssl_server_name\n"; + } + + location /ssl-was-reused { + return 200 "reused:$ssl_session_reused\n"; + } + } } diff --git a/rustls-libssl/tests/runner.rs b/rustls-libssl/tests/runner.rs index 843d472..372f38b 100644 --- a/rustls-libssl/tests/runner.rs +++ b/rustls-libssl/tests/runner.rs @@ -376,6 +376,46 @@ fn server() { let rustls_output = print_output(rustls_server.wait_with_timeout()); assert_eq!(openssl_output, rustls_output); + + let mut openssl_server = KillOnDrop(Some( + Command::new("tests/maybe-valgrind.sh") + .env("LD_LIBRARY_PATH", "") + .args([ + "target/server", + &port_str, + "test-ca/rsa/server.key", + "test-ca/rsa/server.cert", + "unauth", + "ticket", + ]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(), + )); + wait_for_stdout(openssl_server.0.as_mut().unwrap(), b"listening\n"); + curl(port); + + let openssl_output = print_output(openssl_server.wait_with_timeout()); + + let mut rustls_server = KillOnDrop(Some( + Command::new("tests/maybe-valgrind.sh") + .args([ + "target/server", + &port_str, + "test-ca/rsa/server.key", + "test-ca/rsa/server.cert", + "unauth", + "ticket", + ]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(), + )); + wait_for_stdout(rustls_server.0.as_mut().unwrap(), b"listening\n"); + curl(port); + + let rustls_output = print_output(rustls_server.wait_with_timeout()); + assert_eq!(openssl_output, rustls_output); } fn server_with_key_algorithm(key_type: &str, sig_algs: &str, version_flag: &str) { @@ -502,7 +542,13 @@ fn nginx() { b"hello world\n" ); - for (port, reused) in [(8443, '.'), (8444, 'r'), (8445, 'r'), (8446, 'r')] { + for (port, reused) in [ + (8443, '.'), + (8444, 'r'), + (8445, 'r'), + (8446, 'r'), + (8449, 'r'), + ] { // multiple requests without http connection reuse // (second should be a TLS resumption if possible) assert_eq!( diff --git a/rustls-libssl/tests/server.c b/rustls-libssl/tests/server.c index e3d7b5e..f1a6a29 100644 --- a/rustls-libssl/tests/server.c +++ b/rustls-libssl/tests/server.c @@ -100,7 +100,7 @@ static void sess_remove_callback(SSL_CTX *ctx, SSL_SESSION *sess) { int main(int argc, char **argv) { if (argc != 6) { printf("%s |unauth " - "none|internal|external|internal+external\n\n", + "none|internal|external|internal+external|ticket\n\n", argv[0]); return 1; } @@ -152,6 +152,10 @@ int main(int argc, char **argv) { SSL_CTX_set_tlsext_servername_arg(ctx, &sni_cookie); dump_openssl_error_stack(); + // Default to no tickets. + SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); + TRACE(SSL_CTX_set_num_tickets(ctx, 0)); + if (strstr(cache, "external")) { SSL_CTX_sess_set_new_cb(ctx, sess_new_callback); SSL_CTX_sess_set_get_cb(ctx, sess_get_callback); @@ -168,6 +172,12 @@ int main(int argc, char **argv) { TRACE(SSL_CTX_set_session_cache_mode(ctx, 0)); } + if (strcmp(cache, "ticket") == 0) { + SSL_CTX_clear_options(ctx, SSL_OP_NO_TICKET); + TRACE(SSL_CTX_set_num_tickets(ctx, 3)); + } + TRACE(SSL_CTX_get_num_tickets(ctx)); + X509 *server_cert = NULL; EVP_PKEY *server_key = NULL; TRACE(SSL_CTX_use_certificate_chain_file(ctx, certfile)); @@ -184,6 +194,7 @@ int main(int argc, char **argv) { SSL_get_privatekey(ssl) == server_key ? "same as" : "differs to"); printf("SSL_new: SSL_get_certificate %s SSL_CTX_get0_certificate\n", SSL_get_certificate(ssl) == server_cert ? "same as" : "differs to"); + TRACE(SSL_get_num_tickets(ssl)); ssl_ex_data_idx_message = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); TRACE(SSL_set_ex_data(ssl, ssl_ex_data_idx_message, "hello from SSL!"));