Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose set_compliance_policy and get_ciphers #212

Merged
merged 1 commit into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 71 additions & 2 deletions boring/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
use crate::ssl::bio::BioMethod;
use crate::ssl::callbacks::*;
use crate::ssl::error::InnerError;
use crate::stack::{Stack, StackRef};
use crate::stack::{Stack, StackRef, Stackable};
use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef};
use crate::x509::verify::X509VerifyParamRef;
use crate::x509::{
Expand Down Expand Up @@ -701,6 +701,27 @@ impl SslCurve {
pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::NID_P256Kyber768Draft00);
}

/// A compliance policy.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg(not(feature = "fips"))]
pub struct CompliancePolicy(ffi::ssl_compliance_policy_t);

#[cfg(not(feature = "fips"))]
impl CompliancePolicy {
/// Does nothing, however setting this does not undo other policies, so trying to set this is an error.
pub const NONE: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_none);

/// Configures a TLS connection to try and be compliant with NIST requirements, but does not guarantee success.
/// This policy can be called even if Boring is not built with FIPS.
pub const FIPS_202205: Self =
Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_fips_202205);

/// Partially configures a TLS connection to be compliant with WPA3. Callers must enforce certificate chain requirements themselves.
/// Use of this policy is less secure than the default and not recommended.
pub const WPA3_192_202304: Self =
Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_wpa3_192_202304);
}

/// A standard implementation of protocol selection for Application Layer Protocol Negotiation
/// (ALPN).
///
Expand Down Expand Up @@ -1262,7 +1283,9 @@ impl SslContextBuilder {

/// Sets the list of supported ciphers for protocols before TLSv1.3.
///
/// The `set_ciphersuites` method controls the cipher suites for TLSv1.3.
/// The `set_ciphersuites` method controls the cipher suites for TLSv1.3 in OpenSSL.
/// BoringSSL doesn't implement `set_ciphersuites`.
/// See https://github.com/google/boringssl/blob/master/include/openssl/ssl.h#L1542-L1544
///
/// See [`ciphers`] for details on the format.
///
Expand All @@ -1281,6 +1304,18 @@ impl SslContextBuilder {
}
}

/// Gets the list of supported ciphers for protocols before TLSv1.3.
///
/// See [`ciphers`] for details on the format
///
/// This corresponds to [`SSL_CTX_get_ciphers`].
///
/// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html
/// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ciphers.html
pub fn ciphers(&self) -> Option<&StackRef<SslCipher>> {
nox marked this conversation as resolved.
Show resolved Hide resolved
self.ctx.ciphers()
}

/// Sets the options used by the context, returning the old set.
///
/// This corresponds to [`SSL_CTX_set_options`].
Expand Down Expand Up @@ -1856,6 +1891,17 @@ impl SslContextBuilder {
}
}

/// Sets the context's compliance policy.
///
/// This corresponds to [`SSL_CTX_set_compliance_policy`]
///
/// [`SSL_CTX_set_compliance_policy`] https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_compliance_policy
/// This feature isn't available in the certified version of BoringSSL.
#[cfg(not(feature = "fips"))]
pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> {
unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) }
}

/// Consumes the builder, returning a new `SslContext`.
pub fn build(self) -> SslContext {
self.ctx
Expand Down Expand Up @@ -1936,6 +1982,25 @@ impl SslContext {
Index::from_raw(idx)
}
}

/// Gets the list of supported ciphers for protocols before TLSv1.3.
///
/// See [`ciphers`] for details on the format
///
/// This corresponds to [`SSL_CTX_get_ciphers`].
///
/// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html
/// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ciphers.html
pub fn ciphers(&self) -> Option<&StackRef<SslCipher>> {
unsafe {
let ciphers = ffi::SSL_CTX_get_ciphers(self.as_ptr());
if ciphers.is_null() {
None
} else {
Some(StackRef::from_ptr(ciphers))
}
}
}
}

impl SslContextRef {
Expand Down Expand Up @@ -2181,6 +2246,10 @@ impl ClientHello<'_> {
/// Information about a cipher.
pub struct SslCipher(*mut ffi::SSL_CIPHER);

impl Stackable for SslCipher {
type StackType = ffi::stack_st_SSL_CIPHER;
}

unsafe impl ForeignType for SslCipher {
type CType = ffi::SSL_CIPHER;
type Ref = SslCipherRef;
Expand Down
77 changes: 77 additions & 0 deletions boring/src/ssl/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ use crate::ssl::{
use crate::x509::verify::X509CheckFlags;
use crate::x509::{X509Name, X509};

#[cfg(not(feature = "fips"))]
use super::CompliancePolicy;

mod custom_verify;
mod private_key_method;
mod server;
Expand Down Expand Up @@ -917,6 +920,80 @@ fn server_set_default_curves_list() {
ssl.server_set_default_curves_list();
}

#[test]
fn test_get_ciphers() {
let ctx_builder = SslContext::builder(SslMethod::tls()).unwrap();
let ctx_builder_ciphers: Vec<&str> = ctx_builder
.ciphers()
.unwrap()
.into_iter()
.map(|v| v.name())
.collect();
assert!(!(ctx_builder_ciphers.is_empty()));

let ctx = ctx_builder.build();
let ctx_ciphers: Vec<&str> = ctx
.ciphers()
.unwrap()
.into_iter()
.map(|v| v.name())
.collect();
assert!(!(ctx_ciphers.is_empty()));

assert_eq!(ctx_builder_ciphers.len(), ctx_ciphers.len());

for (ctx_builder_cipher, ctx_cipher) in ctx_builder_ciphers.into_iter().zip(ctx_ciphers) {
assert_eq!(ctx_builder_cipher, ctx_cipher);
}
}

#[test]
#[cfg(not(feature = "fips"))]
fn test_set_compliance() {
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_compliance_policy(CompliancePolicy::FIPS_202205)
.unwrap();

assert_eq!(ctx.max_proto_version().unwrap(), SslVersion::TLS1_3);
assert_eq!(ctx.min_proto_version().unwrap(), SslVersion::TLS1_2);

const FIPS_CIPHERS: [&str; 4] = [
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
];

let ciphers = ctx.ciphers().unwrap();
assert_eq!(ciphers.len(), FIPS_CIPHERS.len());

for cipher in ciphers.into_iter().zip(FIPS_CIPHERS) {
assert_eq!(cipher.0.name(), cipher.1)
}

let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_compliance_policy(CompliancePolicy::WPA3_192_202304)
.unwrap();

assert_eq!(ctx.max_proto_version().unwrap(), SslVersion::TLS1_3);
assert_eq!(ctx.min_proto_version().unwrap(), SslVersion::TLS1_2);

const WPA3_192_CIPHERS: [&str; 2] = [
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
];

let ciphers = ctx.ciphers().unwrap();
assert_eq!(ciphers.len(), WPA3_192_CIPHERS.len());

for cipher in ciphers.into_iter().zip(WPA3_192_CIPHERS) {
assert_eq!(cipher.0.name(), cipher.1)
}

ctx.set_compliance_policy(CompliancePolicy::NONE)
.expect_err("Testing expect err if set compliance policy to NONE");
}

#[test]
fn drop_ex_data_in_context() {
let index = SslContext::new_ex_index::<&'static str>().unwrap();
Expand Down
Loading