Skip to content

Commit

Permalink
conf: implement VerifyMode command
Browse files Browse the repository at this point in the history
An nginx integration test is blocked on implementing
`SSL_CTX_set_verify`.
  • Loading branch information
cpu committed Jun 25, 2024
1 parent 16380fc commit 1bcfb4f
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 1 deletion.
62 changes: 61 additions & 1 deletion rustls-libssl/src/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -123,6 +123,57 @@ impl SslConfigCtx {
})
}

fn verify_mode(&mut self, raw_mode: Option<&str>) -> Result<ActionResult, Error> {
// 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::<Vec<&str>>();
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<u16> {
Some(match proto {
Some("None") => 0,
Expand Down Expand Up @@ -256,6 +307,8 @@ type CommandAction = fn(&mut SslConfigCtx, value: Option<&str>) -> Result<Action
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(i32)]
enum ActionResult {
/// The action required a value but was provided NULL.
ValueRequired = -3,
/// The action value was recognized, but not applied.
///
/// For example, if no `SSL_CTX` has been set a [`CommandAction`] may return `NotApplied` after
Expand Down Expand Up @@ -340,4 +393,11 @@ const SUPPORTED_COMMANDS: &[Command] = &[
value_type: ValueType::String,
action: SslConfigCtx::max_protocol,
},
Command {
name_file: Some("VerifyMode"),
name_cmdline: None,
flags: Flags(Flags::ANY),
value_type: ValueType::String,
action: SslConfigCtx::verify_mode,
},
];
85 changes: 85 additions & 0 deletions rustls-libssl/tests/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ static const char *supported_cmds[] = {

"-max_protocol", CUSTOM_PREFIX "max_protocol",
"MaxProtocol", CUSTOM_PREFIX "MaxProtocol",

"VerifyMode", CUSTOM_PREFIX "VerifyMode",
};

#define NUM_SUPPORTED_CMDS (sizeof(supported_cmds) / sizeof(supported_cmds[0]))
Expand Down Expand Up @@ -148,6 +150,86 @@ void test_min_max_versions(void) {
SSL_free(ssl);
}

static const char *verify_modes[] = {
NULL, "", "Ludicrous", "Ludicrous,Absurd",
"Peer", "Request", "Require", "Request,Require",
};

#define NUM_VERIFY_MODES (sizeof(verify_modes) / sizeof(verify_modes[0]))

void set_verify_modes(SSL_CONF_CTX *cctx, SSL_CTX *ctx, SSL *ssl) {
for (unsigned long i = 0; i < NUM_VERIFY_MODES; i++) {
const char *mode = verify_modes[i];
int res = SSL_CONF_cmd(cctx, "VerifyMode", mode);
printf("\t\tcmd VerifyMode '%s' returns %d\n", mode == NULL ? "NULL" : mode,
res);
if (ctx != NULL) {
printf("\t\tSSL_CTX_get_verify_mode %d\n", SSL_CTX_get_verify_mode(ctx));
}
if (ssl != NULL) {
printf("\t\tSSL_get_verify_mode %d\n", SSL_get_verify_mode(ssl));
}
}
}

void test_verify_mode(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 (not client or server):\n");
set_verify_modes(cctx, NULL, NULL);

printf("\tPre-ctx (client):\n");
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
set_verify_modes(cctx, NULL, NULL);
SSL_CONF_CTX_clear_flags(cctx, SSL_CONF_FLAG_CLIENT);

printf("\tPre-ctx (server):\n");
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER);
set_verify_modes(cctx, NULL, NULL);
SSL_CONF_CTX_clear_flags(cctx, SSL_CONF_FLAG_SERVER);

SSL_CTX *ctx = SSL_CTX_new(TLS_method());
assert(ctx != NULL);
SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);

printf("\tWith ctx (not client or server):\n");
set_verify_modes(cctx, ctx, NULL);

printf("\tWith ctx (client):\n");
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
set_verify_modes(cctx, ctx, NULL);
SSL_CONF_CTX_clear_flags(cctx, SSL_CONF_FLAG_CLIENT);

printf("\tWith ctx (server):\n");
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER);
set_verify_modes(cctx, ctx, NULL);
SSL_CONF_CTX_clear_flags(cctx, SSL_CONF_FLAG_SERVER);

SSL *ssl = SSL_new(ctx);
assert(ssl != NULL);
SSL_CONF_CTX_set_ssl(cctx, ssl);

printf("\tWith ssl (not client or server):\n");
set_verify_modes(cctx, NULL, ssl);

printf("\tWith ssl (client):\n");
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
set_verify_modes(cctx, NULL, ssl);
SSL_CONF_CTX_clear_flags(cctx, SSL_CONF_FLAG_CLIENT);

printf("\tWith ssl (server):\n");
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER);
set_verify_modes(cctx, NULL, ssl);
SSL_CONF_CTX_clear_flags(cctx, SSL_CONF_FLAG_SERVER);

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");
Expand All @@ -170,4 +252,7 @@ int main(void) {

printf("Min/Max version:\n");
test_min_max_versions();

printf("VerifyMode:\n");
test_verify_mode();
}

0 comments on commit 1bcfb4f

Please sign in to comment.