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

Introduce X509Flags #209

Merged
merged 3 commits into from
Jan 3, 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
7 changes: 6 additions & 1 deletion boring/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3176,7 +3176,7 @@ impl SslRef {
/// This corresponds to [`SSL_get0_param`].
///
/// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html
pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
#[cfg(feature = "rpk")]
assert!(
!self.ssl_context().is_rpk(),
Expand All @@ -3186,6 +3186,11 @@ impl SslRef {
unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
}

/// See [`Self::verify_param_mut`].
pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
self.verify_param_mut()
}

/// Returns the certificate verification result.
///
/// This corresponds to [`SSL_get_verify_result`].
Expand Down
12 changes: 11 additions & 1 deletion boring/src/x509/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//! Internet protocols, including SSL/TLS, which is the basis for HTTPS,
//! the secure protocol for browsing the web.

use crate::ffi;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::{c_int, c_long, c_void};
use std::convert::TryInto;
Expand All @@ -30,12 +29,14 @@ use crate::bio::MemBioSlice;
use crate::conf::ConfRef;
use crate::error::ErrorStack;
use crate::ex_data::Index;
use crate::ffi;
use crate::hash::{DigestBytes, MessageDigest};
use crate::nid::Nid;
use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
use crate::ssl::SslRef;
use crate::stack::{Stack, StackRef, Stackable};
use crate::string::OpensslString;
use crate::x509::verify::X509VerifyParamRef;
use crate::{cvt, cvt_n, cvt_p};

pub mod extension;
Expand Down Expand Up @@ -147,6 +148,15 @@ impl X509StoreContextRef {
}
}

/// Returns a mutable reference to the X509 verification configuration.
///
/// This corresponds to [`X509_STORE_CTX_get0_param`].
///
/// [`SSL_get0_param`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_CTX_get0_param.html
pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_CTX_get0_param(self.as_ptr())) }
}

/// Verifies the stored certificate.
///
/// Returns `true` if verification succeeds. The `error` method will return the specific
Expand Down
32 changes: 25 additions & 7 deletions boring/src/x509/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@
//! let store: X509Store = builder.build();
//! ```

use crate::ffi;
use foreign_types::{ForeignType, ForeignTypeRef};
use std::mem;

use crate::error::ErrorStack;
use crate::ffi;
use crate::stack::StackRef;
use crate::x509::verify::{X509Flags, X509VerifyParamRef};
use crate::x509::{X509Object, X509};
use crate::{cvt, cvt_p};
use foreign_types::{ForeignType, ForeignTypeRef};
use std::mem;

foreign_type_and_impl_send_sync! {
type CType = ffi::X509_STORE;
Expand Down Expand Up @@ -92,6 +92,26 @@ impl X509StoreBuilderRef {
pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) }
}

/// Sets verify flags.
///
/// This corresponds to [`X509_STORE_set_flags`].
///
/// [`X509_STORE_set_flags`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_set_flags.html
pub fn set_flags(&mut self, flags: X509Flags) {
unsafe {
ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits());
}
}

/// Returns a mutable reference to the X509 verification configuration.
///
/// This corresponds to [`X509_STORE_get0_param`].
///
/// [`SSL_get0_param`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_get0_param.html
pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_get0_param(self.as_ptr())) }
}
}

foreign_type_and_impl_send_sync! {
Expand All @@ -105,8 +125,6 @@ foreign_type_and_impl_send_sync! {
impl X509StoreRef {
/// Get a reference to the cache of certificates in this store.
pub fn objects(&self) -> &StackRef<X509Object> {
unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) }
unsafe { StackRef::from_ptr(ffi::X509_STORE_get0_objects(self.as_ptr())) }
}
}

use crate::ffi::X509_STORE_get0_objects;
44 changes: 23 additions & 21 deletions boring/src/x509/tests.rs → boring/src/x509/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ use crate::x509::extension::{
use crate::x509::store::X509StoreBuilder;
use crate::x509::{X509Extension, X509Name, X509Req, X509StoreContext, X509};

mod trusted_first;

fn pkey() -> PKey<Private> {
let rsa = Rsa::generate(2048).unwrap();
PKey::from_rsa(rsa).unwrap()
}

#[test]
fn test_cert_loading() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let fingerprint = cert.digest(MessageDigest::sha1()).unwrap();

Expand All @@ -33,7 +35,7 @@ fn test_cert_loading() {

#[test]
fn test_debug() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let debugged = format!("{:#?}", cert);

Expand All @@ -47,7 +49,7 @@ fn test_debug() {

#[test]
fn test_cert_issue_validity() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let not_before = cert.not_before().to_string();
let not_after = cert.not_after().to_string();
Expand All @@ -58,7 +60,7 @@ fn test_cert_issue_validity() {

#[test]
fn test_save_der() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();

let der = cert.to_der().unwrap();
Expand All @@ -67,7 +69,7 @@ fn test_save_der() {

#[test]
fn test_subject_read_cn() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let subject = cert.subject_name();
let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap();
Expand All @@ -76,7 +78,7 @@ fn test_subject_read_cn() {

#[test]
fn test_nid_values() {
let cert = include_bytes!("../../test/nid_test_cert.pem");
let cert = include_bytes!("../../../test/nid_test_cert.pem");
let cert = X509::from_pem(cert).unwrap();
let subject = cert.subject_name();

Expand All @@ -95,7 +97,7 @@ fn test_nid_values() {

#[test]
fn test_nameref_iterator() {
let cert = include_bytes!("../../test/nid_test_cert.pem");
let cert = include_bytes!("../../../test/nid_test_cert.pem");
let cert = X509::from_pem(cert).unwrap();
let subject = cert.subject_name();
let mut all_entries = subject.entries();
Expand All @@ -122,7 +124,7 @@ fn test_nameref_iterator() {

#[test]
fn test_nid_uid_value() {
let cert = include_bytes!("../../test/nid_uid_test_cert.pem");
let cert = include_bytes!("../../../test/nid_uid_test_cert.pem");
let cert = X509::from_pem(cert).unwrap();
let subject = cert.subject_name();

Expand All @@ -132,7 +134,7 @@ fn test_nid_uid_value() {

#[test]
fn test_subject_alt_name() {
let cert = include_bytes!("../../test/alt_name_cert.pem");
let cert = include_bytes!("../../../test/alt_name_cert.pem");
let cert = X509::from_pem(cert).unwrap();

let subject_alt_names = cert.subject_alt_names().unwrap();
Expand All @@ -149,7 +151,7 @@ fn test_subject_alt_name() {

#[test]
fn test_subject_alt_name_iter() {
let cert = include_bytes!("../../test/alt_name_cert.pem");
let cert = include_bytes!("../../../test/alt_name_cert.pem");
let cert = X509::from_pem(cert).unwrap();

let subject_alt_names = cert.subject_alt_names().unwrap();
Expand Down Expand Up @@ -342,7 +344,7 @@ fn x509_req_builder() {

#[test]
fn test_stack_from_pem() {
let certs = include_bytes!("../../test/certs.pem");
let certs = include_bytes!("../../../test/certs.pem");
let certs = X509::stack_from_pem(certs).unwrap();

assert_eq!(certs.len(), 2);
Expand All @@ -358,9 +360,9 @@ fn test_stack_from_pem() {

#[test]
fn issued() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let ca = include_bytes!("../../test/root-ca.pem");
let ca = include_bytes!("../../../test/root-ca.pem");
let ca = X509::from_pem(ca).unwrap();

assert_eq!(ca.issued(&cert), Ok(()));
Expand All @@ -369,7 +371,7 @@ fn issued() {

#[test]
fn signature() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let signature = cert.signature();
assert_eq!(
Expand All @@ -390,16 +392,16 @@ fn signature() {
#[test]
#[allow(clippy::redundant_clone)]
fn clone_x509() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
drop(cert.clone());
}

#[test]
fn test_verify_cert() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let ca = include_bytes!("../../test/root-ca.pem");
let ca = include_bytes!("../../../test/root-ca.pem");
let ca = X509::from_pem(ca).unwrap();
let chain = Stack::new().unwrap();

Expand All @@ -418,9 +420,9 @@ fn test_verify_cert() {

#[test]
fn test_verify_fails() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let ca = include_bytes!("../../test/alt_name_cert.pem");
let ca = include_bytes!("../../../test/alt_name_cert.pem");
let ca = X509::from_pem(ca).unwrap();
let chain = Stack::new().unwrap();

Expand All @@ -436,7 +438,7 @@ fn test_verify_fails() {

#[test]
fn test_save_subject_der() {
let cert = include_bytes!("../../test/cert.pem");
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();

let der = cert.subject_name().to_der().unwrap();
Expand All @@ -446,7 +448,7 @@ fn test_save_subject_der() {

#[test]
fn test_load_subject_der() {
// The subject from ../../test/cert.pem
// The subject from ../../../test/cert.pem
const SUBJECT_DER: &[u8] = &[
48, 90, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 65, 85, 49, 19, 48, 17, 6, 3, 85, 4, 8, 12,
10, 83, 111, 109, 101, 45, 83, 116, 97, 116, 101, 49, 33, 48, 31, 6, 3, 85, 4, 10, 12, 24,
Expand Down
104 changes: 104 additions & 0 deletions boring/src/x509/tests/trusted_first.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! See https://github.com/google/boringssl/blob/cc696073cffe7978d489297fbdeac4c0030384aa/crypto/x509/x509_test.cc#L3977-L3980

use crate::stack::Stack;
use crate::x509::store::X509StoreBuilder;
use crate::x509::verify::{X509Flags, X509VerifyParamRef};
use crate::x509::{X509Ref, X509StoreContext, X509VerifyError, X509VerifyResult, X509};

#[test]
fn test_verify_cert() {
let root2 = X509::from_pem(include_bytes!("../../../test/root-ca-2.pem")).unwrap();
let root1 = X509::from_pem(include_bytes!("../../../test/root-ca.pem")).unwrap();
let root1_cross = X509::from_pem(include_bytes!("../../../test/root-ca-cross.pem")).unwrap();
let intermediate = X509::from_pem(include_bytes!("../../../test/intermediate-ca.pem")).unwrap();
let leaf = X509::from_pem(include_bytes!("../../../test/cert-with-intermediate.pem")).unwrap();

assert_eq!(Ok(()), verify(&leaf, &[&root1], &[&intermediate], |_| {}));

#[cfg(not(feature = "fips"))]
assert_eq!(
Ok(()),
verify(
&leaf,
&[&root1, &root2],
&[&intermediate, &root1_cross],
|_| {}
)
);

#[cfg(feature = "fips")]
assert_eq!(
Err(X509VerifyError::CERT_HAS_EXPIRED),
verify(
&leaf,
&[&root1, &root2],
&[&intermediate, &root1_cross],
|_| {}
)
);

assert_eq!(
Ok(()),
verify(
&leaf,
&[&root1, &root2],
&[&intermediate, &root1_cross],
|param| param.set_flags(X509Flags::TRUSTED_FIRST),
)
);

assert_eq!(
Err(X509VerifyError::CERT_HAS_EXPIRED),
verify(
&leaf,
&[&root1, &root2],
&[&intermediate, &root1_cross],
|param| param.clear_flags(X509Flags::TRUSTED_FIRST),
)
);

assert_eq!(
Ok(()),
verify(&leaf, &[&root1], &[&intermediate, &root1_cross], |param| {
param.clear_flags(X509Flags::TRUSTED_FIRST)
},)
);
}

fn verify(
cert: &X509Ref,
trusted: &[&X509Ref],
untrusted: &[&X509Ref],
configure: impl FnOnce(&mut X509VerifyParamRef),
) -> X509VerifyResult {
let trusted = {
let mut builder = X509StoreBuilder::new().unwrap();

for cert in trusted {
builder.add_cert((**cert).to_owned()).unwrap();
}

builder.build()
};

let untrusted = {
let mut stack = Stack::new().unwrap();

for cert in untrusted {
stack.push((**cert).to_owned()).unwrap();
}

stack
};

let mut store_ctx = X509StoreContext::new().unwrap();

let _ = store_ctx.init(&trusted, cert, &untrusted, |ctx| {
configure(ctx.verify_param_mut());
ctx.verify_cert().unwrap();

Ok(())
});

store_ctx.verify_result()
}
Loading
Loading