From 1bcfb4f777f0989d1d4a140f0b4640cc76342468 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sun, 23 Jun 2024 12:51:57 -0400 Subject: [PATCH] conf: implement VerifyMode command An nginx integration test is blocked on implementing `SSL_CTX_set_verify`. --- rustls-libssl/src/conf.rs | 62 +++++++++++++++++++++++++- rustls-libssl/tests/config.c | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) diff --git a/rustls-libssl/src/conf.rs b/rustls-libssl/src/conf.rs index cac89c0..6b4893b 100644 --- a/rustls-libssl/src/conf.rs +++ b/rustls-libssl/src/conf.rs @@ -6,7 +6,7 @@ use rustls::ProtocolVersion; use crate::error::Error; use crate::not_thread_safe::NotThreadSafe; -use crate::{Ssl, SslContext}; +use crate::{Ssl, SslContext, VerifyMode}; #[derive(Default)] pub(super) struct SslConfigCtx { @@ -123,6 +123,57 @@ impl SslConfigCtx { }) } + fn verify_mode(&mut self, raw_mode: Option<&str>) -> Result { + // If there's a SSL_CTX or SSL set then we want to mutate the existing verify_mode. + let mut verify_mode = match &self.state { + State::Validating => VerifyMode::default(), + State::ApplyingToSsl(ssl) => ssl.get().verify_mode, + State::ApplyingToCtx(ctx) => ctx.get().verify_mode, + }; + + let raw_mode = match raw_mode { + Some(raw_mode) => raw_mode, + None => return Ok(ActionResult::ValueRequired), + }; + + if !self.flags.is_server() && !self.flags.is_client() { + return Err(Error::bad_data("neither a client or a server")); + } + + // "The value argument is a comma separated list of flags to set." + let mode_parts = raw_mode.split(',').collect::>(); + for part in mode_parts { + match (part, self.flags.is_server()) { + // "Peer enables peer verification: for clients only." + ("Peer", false) => verify_mode.0 |= VerifyMode::PEER, + // "Request requests but does not require a certificate from the client. Servers only." + ("Request", true) => verify_mode.0 |= VerifyMode::PEER, + // "Require requests and requires a certificate from the client: an error occurs if the + // client does not present a certificate. Servers only." + ("Require", true) => { + verify_mode.0 |= VerifyMode::PEER | VerifyMode::FAIL_IF_NO_PEER_CERT + } + // We do not implement Once, RequestPostHandshake and RequiresPostHandshake, + // but don't error if provided. + ("Once" | "RequestPostHandshake" | "RequirePostHandshake", _) => {} + _ => return Err(Error::bad_data("unrecognized verify mode")), + } + } + + Ok(match &self.state { + // OpenSSL returns "2" for this case... + State::Validating => ActionResult::Applied, + State::ApplyingToCtx(ctx) => { + ctx.get_mut().set_verify(verify_mode); + ActionResult::Applied + } + State::ApplyingToSsl(ssl) => { + ssl.get_mut().set_verify(verify_mode); + ActionResult::Applied + } + }) + } + fn parse_protocol_version(proto: Option<&str>) -> Option { Some(match proto { Some("None") => 0, @@ -256,6 +307,8 @@ type CommandAction = fn(&mut SslConfigCtx, value: Option<&str>) -> Result