From 0f6834247b6b8d79c8f7d20d517ff2a71fab04bc Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 26 Jun 2024 17:27:06 -0400 Subject: [PATCH] conf: implement Options SessionTicket/-SessionTicket cmd --- rustls-libssl/src/conf.rs | 54 +++++++++++++++++++++- rustls-libssl/tests/config.c | 90 ++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/rustls-libssl/src/conf.rs b/rustls-libssl/src/conf.rs index 0293c21..ebd586c 100644 --- a/rustls-libssl/src/conf.rs +++ b/rustls-libssl/src/conf.rs @@ -279,6 +279,44 @@ impl SslConfigCtx { 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, @@ -481,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 { @@ -539,10 +585,16 @@ const SUPPORTED_COMMANDS: &[Command] = &[ 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 // - CANames (?) // - Groups/-groups // - SignatureAlgorithms/-sigalgs diff --git a/rustls-libssl/tests/config.c b/rustls-libssl/tests/config.c index c94e5da..4a4b4d5 100644 --- a/rustls-libssl/tests/config.c +++ b/rustls-libssl/tests/config.c @@ -3,6 +3,7 @@ */ #include +#include #include #include @@ -403,6 +404,92 @@ void test_no_ticket(void) { 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"); @@ -437,4 +524,7 @@ int main(void) { printf("no_ticket\n"); test_no_ticket(); + + printf("Options SessionTicket\n"); + test_options_session_ticket(); }