Compare commits
1 Commits
main
...
crl-suppor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d66031ab1 |
@ -253,6 +253,16 @@ impl<T: Stackable> StackRef<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for StackRef<T>
|
||||
where
|
||||
T: Stackable,
|
||||
T::Ref: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_list().entries(self).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> Index<usize> for StackRef<T> {
|
||||
type Output = T::Ref;
|
||||
|
||||
|
||||
506
boring/src/x509/crl.rs
Normal file
506
boring/src/x509/crl.rs
Normal file
@ -0,0 +1,506 @@
|
||||
//! Certificate revocation lists describe certificates that have been revoked
|
||||
//! by their issuer and should no longer be trusted.
|
||||
//!
|
||||
//! An `X509CRL` can be provided along with an issuing `X509` to verify that
|
||||
//! issued certificates have not been revoked.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use boring::hash::MessageDigest;
|
||||
//! use boring::pkey::{PKey, Private};
|
||||
//! use boring::x509::crl::{X509CRLBuilder, X509Revoked};
|
||||
//! use boring::x509::extension::BasicConstraints;
|
||||
//! use boring::x509::verify::X509VerifyFlags;
|
||||
//! use boring::x509::X509Extension;
|
||||
//! use boring::x509::X509;
|
||||
//! use boring::x509::store::{X509Store, X509StoreBuilder};
|
||||
//! use boring::asn1::Asn1Time;
|
||||
//! use boring::bn::BigNum;
|
||||
//! use boring::error::ErrorStack;
|
||||
//!
|
||||
//! fn crl_checking_store(issuer: X509, pkey: PKey<Private>) -> Result<X509Store, ErrorStack> {
|
||||
//! let mut builder = X509CRLBuilder::new()?;
|
||||
//! builder.set_issuer_name(issuer.subject_name())?;
|
||||
//! builder.add_revoked(X509Revoked::from_parts(
|
||||
//! &*BigNum::from_u32(1)?.to_asn1_integer()?,
|
||||
//! &*Asn1Time::days_from_now(0)?
|
||||
//! )?)?;
|
||||
//! builder.set_last_update(&*Asn1Time::days_from_now(0)?)?;
|
||||
//! builder.set_next_update(&*Asn1Time::days_from_now(30)?)?;
|
||||
//! builder.sign(&pkey, MessageDigest::sha256())?;
|
||||
//!
|
||||
//! let mut store_builder = X509StoreBuilder::new()?;
|
||||
//! store_builder.add_cert(issuer)?;
|
||||
//! store_builder.add_crl(builder.build())?;
|
||||
//! store_builder
|
||||
//! .param_mut()
|
||||
//! .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?;
|
||||
//! Ok(store_builder.build())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::asn1::{Asn1BitStringRef, Asn1IntegerRef, Asn1TimeRef};
|
||||
use crate::foreign_types::ForeignType;
|
||||
use crate::foreign_types::ForeignTypeRef;
|
||||
use crate::hash::{DigestBytes, MessageDigest};
|
||||
use crate::pkey::{HasPrivate, HasPublic, PKeyRef};
|
||||
use crate::stack::{StackRef, Stackable};
|
||||
use crate::x509::X509ExtensionRef;
|
||||
use crate::x509::{X509AlgorithmRef, X509Extension, X509NameRef};
|
||||
use crate::{cvt, cvt_n, cvt_p, ErrorStack};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Formatter;
|
||||
use std::{fmt, mem, ptr};
|
||||
|
||||
foreign_type_and_impl_send_sync! {
|
||||
type CType = ffi::X509_REVOKED;
|
||||
fn drop = ffi::X509_REVOKED_free;
|
||||
|
||||
/// An `X509_REVOKED` containing information about a revoked certificate
|
||||
pub struct X509Revoked;
|
||||
}
|
||||
|
||||
impl Stackable for X509Revoked {
|
||||
type StackType = ffi::stack_st_X509_REVOKED;
|
||||
}
|
||||
|
||||
impl X509Revoked {
|
||||
/// Create an `X509Revoked`
|
||||
///
|
||||
/// This corresponds to [`X509_REVOKED_new`] followed by calls to
|
||||
/// [`X509_REVOKED_set_serialNumber`] and [`X509_REVOKED_set_revocationDate`]
|
||||
/// with the provided parameters
|
||||
///
|
||||
/// [`X509_REVOKED_new`]: https://www.openssl.org/docs/man1.1.1/man3/X509_REVOKED_new.html
|
||||
/// [`X509_REVOKED_set_serialNumber`]: https://www.openssl.org/docs/man1.1.1/man3/X509_REVOKED_set_serialNumber.html
|
||||
/// [`X509_REVOKED_set_revocationDate`]: https://www.openssl.org/docs/man1.1.1/man3/X509_REVOKED_set_revocationDate.html
|
||||
pub fn from_parts(
|
||||
serial_number: &Asn1IntegerRef,
|
||||
revocation_date: &Asn1TimeRef,
|
||||
) -> Result<X509Revoked, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
let revoked = cvt_p(ffi::X509_REVOKED_new())?;
|
||||
cvt(ffi::X509_REVOKED_set_serialNumber(
|
||||
revoked,
|
||||
serial_number.as_ptr(),
|
||||
))?;
|
||||
cvt(ffi::X509_REVOKED_set_revocationDate(
|
||||
revoked,
|
||||
revocation_date.as_ptr(),
|
||||
))?;
|
||||
Ok(X509Revoked::from_ptr(revoked))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl X509RevokedRef {
|
||||
/// Returns the serial number of the revoked certificate
|
||||
///
|
||||
/// This corresponds to [`X509_REVOKED_get0_serialNumber`].
|
||||
///
|
||||
/// [`X509_REVOKED_get0_serialNumber`]: https://www.openssl.org/docs/man1.1.1/man3/X509_REVOKED_get0_serialNumber.html
|
||||
pub fn serial_number(&self) -> &Asn1IntegerRef {
|
||||
unsafe {
|
||||
let r = ffi::X509_REVOKED_get0_serialNumber(self.as_ptr());
|
||||
assert!(!r.is_null());
|
||||
Asn1IntegerRef::from_ptr(r as *mut _)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns certificate's revocation date
|
||||
///
|
||||
/// This corresponds to [`X509_REVOKED_get0_revocationDate`].
|
||||
///
|
||||
/// [`X509_REVOKED_get0_revocationDate`]: https://www.openssl.org/docs/man1.1.1/man3/X509_REVOKED_get0_revocationDate
|
||||
pub fn revocation_date(&self) -> &Asn1TimeRef {
|
||||
unsafe {
|
||||
let date = ffi::X509_REVOKED_get0_revocationDate(self.as_ptr());
|
||||
assert!(!date.is_null());
|
||||
Asn1TimeRef::from_ptr(date as *mut _)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for X509RevokedRef {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||
let sn = self.serial_number().to_bn().and_then(|bn| bn.to_hex_str());
|
||||
let sn = sn.as_ref().map(|x| &***x).unwrap_or("");
|
||||
|
||||
fmt.debug_struct("X509Revoked")
|
||||
.field("serial_number", &sn)
|
||||
.field("revocation_date", self.revocation_date())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type_and_impl_send_sync! {
|
||||
type CType = ffi::X509_CRL;
|
||||
fn drop = ffi::X509_CRL_free;
|
||||
|
||||
/// An `X509CRL` certificate revocation list
|
||||
pub struct X509CRL;
|
||||
}
|
||||
|
||||
impl Stackable for X509CRL {
|
||||
type StackType = ffi::stack_st_X509_CRL;
|
||||
}
|
||||
|
||||
impl X509CRL {
|
||||
from_pem! {
|
||||
/// Deserializes a PEM-encoded X509CRL structure.
|
||||
///
|
||||
/// The input should have a header of `-----BEGIN X509 CRL-----`
|
||||
///
|
||||
/// This corresponds to [`PEM_read_bio_X509_CRL`].
|
||||
///
|
||||
/// [`PEM_read_bio_X509_CRL`]: https://www.openssl.org/docs/man1.1.1/man3/PEM_read_bio_X509_CRL
|
||||
from_pem,
|
||||
X509CRL,
|
||||
ffi::PEM_read_bio_X509_CRL
|
||||
}
|
||||
|
||||
from_der! {
|
||||
/// Deserializes a DER-encoded X509 structure.
|
||||
///
|
||||
/// This corresponds to [`d2i_X509_CRL`].
|
||||
///
|
||||
/// [`d2i_X509_CRL`]: https://www.openssl.org/docs/man1.1.1/man3/d2i_X509_CRL.html
|
||||
from_der,
|
||||
X509CRL,
|
||||
ffi::d2i_X509_CRL,
|
||||
::libc::c_long
|
||||
}
|
||||
}
|
||||
|
||||
impl X509CRLRef {
|
||||
/// Returns the CRL's last update time
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_get0_lastUpdate`]
|
||||
///
|
||||
/// [`X509_CRL_get0_lastUpdate`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_get0_lastUpdate
|
||||
pub fn last_update(&self) -> Option<&Asn1TimeRef> {
|
||||
unsafe {
|
||||
let date = ffi::X509_CRL_get0_lastUpdate(self.as_ptr());
|
||||
if date.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Asn1TimeRef::from_ptr(date as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the CRL's next update time
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_get0_nextUpdate`]
|
||||
///
|
||||
/// [`X509_CRL_get0_nextUpdate`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_get0_nextUpdate
|
||||
pub fn next_update(&self) -> Option<&Asn1TimeRef> {
|
||||
unsafe {
|
||||
let date = ffi::X509_CRL_get0_nextUpdate(self.as_ptr());
|
||||
if date.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Asn1TimeRef::from_ptr(date as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the CRL's issuer name
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_get_issuer`]
|
||||
///
|
||||
/// [`X509_CRL_get_issuer`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_get_issuer
|
||||
pub fn issuer(&self) -> &X509NameRef {
|
||||
unsafe {
|
||||
let name = ffi::X509_CRL_get_issuer(self.as_ptr());
|
||||
|
||||
assert!(!name.is_null());
|
||||
X509NameRef::from_ptr(name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the CRL's extensions
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_get0_extensions`]
|
||||
///
|
||||
/// [`X509_CRL_get0_extensions`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_get0_extensions
|
||||
pub fn extensions(&self) -> Option<&StackRef<X509Extension>> {
|
||||
unsafe {
|
||||
let extensions = ffi::X509_CRL_get0_extensions(self.as_ptr());
|
||||
if extensions.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(StackRef::from_ptr(extensions as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the revoked certificates in this CRL
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_get_REVOKED`]
|
||||
///
|
||||
/// [`X509_CRL_get_REVOKED`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_get_REVOKED
|
||||
pub fn revoked(&self) -> Option<&StackRef<X509Revoked>> {
|
||||
unsafe {
|
||||
let revoked = ffi::X509_CRL_get_REVOKED(self.as_ptr());
|
||||
if revoked.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(StackRef::from_ptr(revoked))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the CRL's signature and signature algorithm
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_get0_signature`]
|
||||
///
|
||||
/// [`X509_CRL_get0_signature`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_get0_signature
|
||||
pub fn signature(&self) -> (&Asn1BitStringRef, &X509AlgorithmRef) {
|
||||
unsafe {
|
||||
let mut signature = ptr::null();
|
||||
let mut algor = ptr::null();
|
||||
ffi::X509_CRL_get0_signature(self.as_ptr(), &mut signature, &mut algor);
|
||||
assert!(!algor.is_null());
|
||||
assert!(!signature.is_null());
|
||||
(
|
||||
Asn1BitStringRef::from_ptr(signature as *mut _),
|
||||
X509AlgorithmRef::from_ptr(algor as *mut _),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a digest of the DER representation of the CRL
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_digest`]
|
||||
///
|
||||
/// [`X509_CRL_digest`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_digest
|
||||
pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
|
||||
unsafe {
|
||||
let mut digest = DigestBytes {
|
||||
buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
|
||||
len: ffi::EVP_MAX_MD_SIZE as usize,
|
||||
};
|
||||
let mut len = ffi::EVP_MAX_MD_SIZE.try_into().unwrap();
|
||||
cvt(ffi::X509_CRL_digest(
|
||||
self.as_ptr(),
|
||||
hash_type.as_ptr(),
|
||||
digest.buf.as_mut_ptr() as *mut _,
|
||||
&mut len,
|
||||
))?;
|
||||
digest.len = len as usize;
|
||||
|
||||
Ok(digest)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the CRL is signed using the given public key.
|
||||
///
|
||||
/// Only the signature is checked: no other checks (such as certificate chain validity)
|
||||
/// are performed.
|
||||
///
|
||||
/// Returns `true` if verification succeeds.
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_verify"].
|
||||
///
|
||||
/// [`X509_CRL_verify`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_verify
|
||||
pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
|
||||
where
|
||||
T: HasPublic,
|
||||
{
|
||||
unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
|
||||
}
|
||||
|
||||
to_pem! {
|
||||
/// Serializes the CRL into a PEM-encoded X509 CRL structure.
|
||||
///
|
||||
/// The output will have a header of `-----BEGIN X509 CRL-----`
|
||||
///
|
||||
/// This corresponds to [`PEM_write_bio_X509_CRL`]
|
||||
///
|
||||
/// [`PEM_write_bio_X509_CRL`]: https://www.openssl.org/docs/man1.1.1/man3/PEM_write_bio_X509_CRL
|
||||
to_pem,
|
||||
ffi::PEM_write_bio_X509_CRL
|
||||
}
|
||||
|
||||
to_der! {
|
||||
/// Serializes the CRL into a DER-encoded X509 CRL structure
|
||||
///
|
||||
/// This corresponds to `i2d_X509_CRL`
|
||||
///
|
||||
/// [`i2d_X509_CRL`]: https://www.openssl.org/docs/man1.1.1/man3/i2d_X509_CRL
|
||||
to_der,
|
||||
ffi::i2d_X509_CRL
|
||||
}
|
||||
}
|
||||
impl ToOwned for X509CRLRef {
|
||||
type Owned = X509CRL;
|
||||
|
||||
fn to_owned(&self) -> X509CRL {
|
||||
unsafe {
|
||||
ffi::X509_CRL_up_ref(self.as_ptr());
|
||||
X509CRL::from_ptr(self.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for X509CRL {
|
||||
fn clone(&self) -> X509CRL {
|
||||
X509CRLRef::to_owned(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for X509CRLRef {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut debug_struct = formatter.debug_struct("X509CRL");
|
||||
debug_struct.field("issuer", self.issuer());
|
||||
debug_struct.field("signature_algorithm", &self.signature().1.object());
|
||||
|
||||
if let Some(next_update) = self.next_update() {
|
||||
debug_struct.field("next_update", next_update);
|
||||
}
|
||||
if let Some(last_update) = self.last_update() {
|
||||
debug_struct.field("last_update", last_update);
|
||||
}
|
||||
if let Some(revoked) = self.revoked() {
|
||||
debug_struct.field("revoked", &revoked);
|
||||
}
|
||||
debug_struct.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for X509CRL {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let x: &X509CRLRef = self;
|
||||
x.fmt(formatter)
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder used to construct an `X509CRL`
|
||||
pub struct X509CRLBuilder(X509CRL);
|
||||
|
||||
impl X509CRLBuilder {
|
||||
/// Creates a new builder.
|
||||
pub fn new() -> Result<X509CRLBuilder, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(ffi::X509_CRL_new()).map(|p| X509CRLBuilder(X509CRL::from_ptr(p)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Append an `X509Extension` to the certificate revocation list
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_add_ext`]
|
||||
///
|
||||
/// [`X509_CRL_add_ext`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_add_ext
|
||||
pub fn append_extension(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
// -1 indicates append to end
|
||||
cvt(ffi::X509_CRL_add_ext(
|
||||
self.0.as_ptr(),
|
||||
extension.as_ptr(),
|
||||
-1,
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Signs the certificate revocation list with a private key.
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_sign`]
|
||||
///
|
||||
/// [`X509_CRL_sign`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_sign
|
||||
pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
|
||||
where
|
||||
T: HasPrivate,
|
||||
{
|
||||
unsafe {
|
||||
cvt(ffi::X509_CRL_sign(
|
||||
self.0.as_ptr(),
|
||||
key.as_ptr(),
|
||||
hash.as_ptr(),
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a revoked certificate to the certificate revocation list
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_add0_revoked`]
|
||||
///
|
||||
/// [`X509_CRL_add0_revoked`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_add0_revoked
|
||||
pub fn add_revoked(&mut self, revoked: X509Revoked) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_CRL_add0_revoked(
|
||||
self.0.as_ptr(),
|
||||
revoked.as_ptr(),
|
||||
))?;
|
||||
mem::forget(revoked);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the issuer name of the certificate revocation list.
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_set_issuer_name`]
|
||||
///
|
||||
/// [`X509_CRL_set_issuer_name`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_set_issuer_name
|
||||
pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_CRL_set_issuer_name(
|
||||
self.0.as_ptr(),
|
||||
issuer_name.as_ptr(),
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the version of the certificate revocation list.
|
||||
///
|
||||
/// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of
|
||||
/// the X.509 standard should pass `2` to this method.
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_set_version`]
|
||||
///
|
||||
/// [`X509_CRL_set_version`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_set_version
|
||||
pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::X509_CRL_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Sets the last update time on the certificate revocation list.
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_set1_lastUpdate`]
|
||||
///
|
||||
/// [`X509_CRL_set1_lastUpdate`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_set1_lastUpdate
|
||||
pub fn set_last_update(&mut self, last_update: &Asn1TimeRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_CRL_set1_lastUpdate(
|
||||
self.0.as_ptr(),
|
||||
last_update.as_ptr(),
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the next update time on the certificate revocation list.
|
||||
///
|
||||
/// This corresponds to [`X509_CRL_set1_nextUpdate`]
|
||||
///
|
||||
/// [`X509_CRL_set1_nextUpdate`]: https://www.openssl.org/docs/man1.1.1/man3/X509_CRL_set1_nextUpdate
|
||||
pub fn set_next_update(&mut self, next_update: &Asn1TimeRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_CRL_set1_nextUpdate(
|
||||
self.0.as_ptr(),
|
||||
next_update.as_ptr(),
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the builder, returning the certificate revocation list
|
||||
pub fn build(self) -> X509CRL {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@ -36,8 +36,10 @@ 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::crl::X509CRL;
|
||||
use crate::{cvt, cvt_n, cvt_p};
|
||||
|
||||
pub mod crl;
|
||||
pub mod extension;
|
||||
pub mod store;
|
||||
pub mod verify;
|
||||
@ -161,6 +163,32 @@ impl X509StoreContextRef {
|
||||
unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
|
||||
}
|
||||
|
||||
/// Verifies the stored certificate with additional untrusted CRLs
|
||||
///
|
||||
/// Returns `true` if verification succeeds. The `error` method will return the specific
|
||||
/// validation error if the certificate was not valid.
|
||||
///
|
||||
/// This will only work inside of a call to `init`.
|
||||
///
|
||||
/// This corresponds to [`X509_STORE_CTX_set0_crls`] followed by [`X509_verify_cert`].
|
||||
///
|
||||
/// [`X509_STORE_CTX_set0_crls`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_set0_crls.html
|
||||
/// [`X509_verify_cert`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html
|
||||
pub fn verify_cert_with_crls(
|
||||
&mut self,
|
||||
untrusted_crls: Stack<X509CRL>,
|
||||
) -> Result<bool, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::X509_STORE_CTX_set0_crls(self.as_ptr(), untrusted_crls.as_ptr());
|
||||
let res = cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0);
|
||||
// set0_crls does not take ownership of the stack, so we'll drop and free
|
||||
// untrusted_crls after this method. null out the crls in ctx to make sure
|
||||
// no one has a reference to it.
|
||||
ffi::X509_STORE_CTX_set0_crls(self.as_ptr(), ptr::null_mut());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the verify result of the context.
|
||||
///
|
||||
/// This corresponds to [`X509_STORE_CTX_set_error`].
|
||||
|
||||
@ -46,6 +46,8 @@ use std::mem;
|
||||
|
||||
use crate::error::ErrorStack;
|
||||
use crate::stack::StackRef;
|
||||
use crate::x509::crl::X509CRL;
|
||||
use crate::x509::verify::X509VerifyParamRef;
|
||||
use crate::x509::{X509Object, X509};
|
||||
use crate::{cvt, cvt_p};
|
||||
|
||||
@ -84,6 +86,24 @@ impl X509StoreBuilderRef {
|
||||
unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Adds a CRL to the certificate store.
|
||||
///
|
||||
/// This corresponds to [`X509_STORE_add_crl`].
|
||||
///
|
||||
/// [`X509_STORE_add_crl`]: https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_add_crl
|
||||
pub fn add_crl(&mut self, crl: X509CRL) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::X509_STORE_add_crl(self.as_ptr(), crl.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the X509 verification configuration.
|
||||
///
|
||||
/// This corresponds to [`X509_STORE_get0_param`].
|
||||
///
|
||||
/// [`X509_STORE_get0_param`]: https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_get0_param
|
||||
pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
|
||||
unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_get0_param(self.as_ptr())) }
|
||||
}
|
||||
|
||||
/// Load certificates from their default locations.
|
||||
///
|
||||
/// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
|
||||
|
||||
@ -6,12 +6,14 @@ use crate::hash::MessageDigest;
|
||||
use crate::nid::Nid;
|
||||
use crate::pkey::{PKey, Private};
|
||||
use crate::rsa::Rsa;
|
||||
use crate::stack::Stack;
|
||||
use crate::stack::{Stack, Stackable};
|
||||
use crate::x509::crl::{X509CRLBuilder, X509Revoked, X509CRL};
|
||||
use crate::x509::extension::{
|
||||
AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName,
|
||||
SubjectKeyIdentifier,
|
||||
};
|
||||
use crate::x509::store::X509StoreBuilder;
|
||||
use crate::x509::verify::X509VerifyFlags;
|
||||
use crate::x509::{X509Extension, X509Name, X509Req, X509StoreContext, X509};
|
||||
|
||||
fn pkey() -> PKey<Private> {
|
||||
@ -19,6 +21,15 @@ fn pkey() -> PKey<Private> {
|
||||
PKey::from_rsa(rsa).unwrap()
|
||||
}
|
||||
|
||||
fn stack_of<T>(item: T) -> Stack<T>
|
||||
where
|
||||
T: Stackable,
|
||||
{
|
||||
let mut stack = Stack::new().expect("unable to initialize stack");
|
||||
stack.push(item).expect("failed to add to stack");
|
||||
stack
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cert_loading() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
@ -250,6 +261,48 @@ fn x509_builder() {
|
||||
assert_eq!(serial, x509.serial_number().to_bn().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn x509_crl_builder() {
|
||||
let mut builder = X509CRLBuilder::new().unwrap();
|
||||
|
||||
let mut name = X509Name::builder().unwrap();
|
||||
name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com")
|
||||
.unwrap();
|
||||
let name = name.build();
|
||||
builder.set_issuer_name(&name).unwrap();
|
||||
|
||||
let mut serial = BigNum::new().unwrap();
|
||||
serial.rand(128, MsbOption::MAYBE_ZERO, false).unwrap();
|
||||
let serial_asn = serial.to_asn1_integer().unwrap();
|
||||
let revoked =
|
||||
X509Revoked::from_parts(&serial_asn, &Asn1Time::days_from_now(0).unwrap()).unwrap();
|
||||
builder.add_revoked(revoked).unwrap();
|
||||
|
||||
builder
|
||||
.set_last_update(&Asn1Time::days_from_now(0).unwrap())
|
||||
.unwrap();
|
||||
builder
|
||||
.set_next_update(&Asn1Time::days_from_now(30).unwrap())
|
||||
.unwrap();
|
||||
|
||||
let pkey = pkey();
|
||||
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
||||
|
||||
let crl = builder.build();
|
||||
|
||||
let cn = crl.issuer().entries_by_nid(Nid::COMMONNAME).next().unwrap();
|
||||
assert_eq!(cn.data().as_slice(), b"foobar.com");
|
||||
let revoked_sn = crl
|
||||
.revoked()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
.serial_number();
|
||||
assert_eq!(serial, revoked_sn.to_bn().unwrap());
|
||||
assert!(crl.verify(&pkey).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn x509_extension_new() {
|
||||
assert!(X509Extension::new(None, None, "crlDistributionPoints", "section").is_err());
|
||||
@ -434,6 +487,257 @@ fn test_verify_fails() {
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_revoked() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
let crl = include_bytes!("../../test/crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let chain = Stack::new().unwrap();
|
||||
|
||||
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||
store_bldr.add_cert(ca).unwrap();
|
||||
store_bldr.add_crl(crl).unwrap();
|
||||
store_bldr
|
||||
.param_mut()
|
||||
.set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)
|
||||
.unwrap();
|
||||
let store = store_bldr.build();
|
||||
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(!context
|
||||
.init(&store, &cert, &chain, |c| c.verify_cert())
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_crl_signature() {
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
|
||||
let crl = include_bytes!("../../test/bad_sig.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
assert!(!crl.verify(&ca.public_key().unwrap()).unwrap());
|
||||
|
||||
let crl = include_bytes!("../../test/crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
assert!(crl.verify(&ca.public_key().unwrap()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_untrusted_valid_crl() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
let chain = Stack::new().unwrap();
|
||||
|
||||
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||
store_bldr.add_cert(ca).unwrap();
|
||||
store_bldr
|
||||
.param_mut()
|
||||
.set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)
|
||||
.unwrap();
|
||||
store_bldr.param_mut().set_time(1656633600); // 2022-07-01, everything is valid
|
||||
let store = store_bldr.build();
|
||||
|
||||
// cert is not revoked
|
||||
let crl = include_bytes!("../../test/empty_crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(context
|
||||
.init(&store, &cert, &chain, |c| c
|
||||
.verify_cert_with_crls(stack_of(crl)))
|
||||
.unwrap());
|
||||
|
||||
// cert is revoked
|
||||
let crl = include_bytes!("../../test/crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(!context
|
||||
.init(&store, &cert, &chain, |c| c
|
||||
.verify_cert_with_crls(stack_of(crl)))
|
||||
.unwrap());
|
||||
assert_eq!(
|
||||
context.verify_result().unwrap_err().as_raw(),
|
||||
ffi::X509_V_ERR_CERT_REVOKED
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_untrusted_invalid_crl() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
let chain = Stack::new().unwrap();
|
||||
|
||||
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||
store_bldr.add_cert(ca).unwrap();
|
||||
store_bldr
|
||||
.param_mut()
|
||||
.set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)
|
||||
.unwrap();
|
||||
store_bldr.param_mut().set_time(1656633600); // 2022-07-01, everything is valid
|
||||
let store = store_bldr.build();
|
||||
|
||||
// this CRL was issued by a different CA (not in the trusted store)
|
||||
let crl = include_bytes!("../../test/invalid_crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(!context
|
||||
.init(&store, &cert, &chain, |c| c
|
||||
.verify_cert_with_crls(stack_of(crl)))
|
||||
.unwrap());
|
||||
assert_eq!(
|
||||
context.verify_result().unwrap_err().as_raw(),
|
||||
ffi::X509_V_ERR_UNABLE_TO_GET_CRL
|
||||
);
|
||||
|
||||
// this CRL has an invalid signature
|
||||
let crl = include_bytes!("../../test/bad_sig.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(!context
|
||||
.init(&store, &cert, &chain, |c| c
|
||||
.verify_cert_with_crls(stack_of(crl)))
|
||||
.unwrap());
|
||||
assert_eq!(
|
||||
context.verify_result().unwrap_err().as_raw(),
|
||||
ffi::X509_V_ERR_CRL_SIGNATURE_FAILURE
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_revoked_serial_numbers() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let cert_sn = cert.serial_number().to_bn().unwrap();
|
||||
|
||||
let crl = include_bytes!("../../test/crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
crl.revoked()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|revoked| revoked.serial_number().to_bn().unwrap() == cert_sn)
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_crl() {
|
||||
let crl = include_bytes!("../../test/crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let digest = hex::encode(crl.digest(MessageDigest::sha1()).unwrap());
|
||||
|
||||
let serialized = crl.to_pem().unwrap();
|
||||
let crl_deserialized = X509CRL::from_pem(&serialized).unwrap();
|
||||
let new_digest = crl_deserialized.digest(MessageDigest::sha1()).unwrap();
|
||||
assert_eq!(digest, hex::encode(new_digest));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug_crl() {
|
||||
let crl = include_bytes!("../../test/crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let debugged = format!("{:#?}", crl);
|
||||
assert!(debugged.contains(r#"countryName = "AU""#));
|
||||
assert!(debugged.contains(r#"stateOrProvinceName = "Some-State""#));
|
||||
assert!(debugged.contains(r#"organizationName = "Internet Widgits Pty Ltd""#));
|
||||
assert!(debugged.contains(r#"last_update: Jun 21 20:22:02 2022 GMT"#));
|
||||
assert!(debugged.contains(r#"next_update: Jun 18 20:22:02 2032 GMT"#));
|
||||
assert!(debugged.contains(r#"revocation_date: Jun 21 20:21:55 2022 GMT"#));
|
||||
assert!(debugged.contains(r#"serial_number: "8771f7bdee982fa5""#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_time_valid() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
let chain = Stack::new().unwrap();
|
||||
|
||||
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||
store_bldr.add_cert(ca).unwrap();
|
||||
store_bldr.param_mut().set_time(1656633600); // 2022-07-01, everything is valid
|
||||
let store = store_bldr.build();
|
||||
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(context
|
||||
.init(&store, &cert, &chain, |c| c.verify_cert())
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_time_expired() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
let chain = Stack::new().unwrap();
|
||||
|
||||
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||
store_bldr.add_cert(ca).unwrap();
|
||||
store_bldr.param_mut().set_time(1786838400); // 2026-08-16, after the root and leaf expiration
|
||||
let store = store_bldr.build();
|
||||
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(!context
|
||||
.init(&store, &cert, &chain, |c| c.verify_cert())
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_time_too_soon() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
let chain = Stack::new().unwrap();
|
||||
|
||||
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||
store_bldr.add_cert(ca).unwrap();
|
||||
store_bldr.param_mut().set_time(1262304000); // 2010-01-01, before the root and leaf issuance
|
||||
let store = store_bldr.build();
|
||||
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(!context
|
||||
.init(&store, &cert, &chain, |c| c.verify_cert())
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_time_crl() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
let crl = include_bytes!("../../test/crl.pem");
|
||||
let crl = X509CRL::from_pem(crl).unwrap();
|
||||
let chain = Stack::new().unwrap();
|
||||
|
||||
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||
store_bldr.add_cert(ca).unwrap();
|
||||
store_bldr
|
||||
.param_mut()
|
||||
.set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)
|
||||
.unwrap();
|
||||
store_bldr.param_mut().set_time(1640995200); // 2022-01-01, before the CRL's issue date
|
||||
let store = store_bldr.build();
|
||||
|
||||
let mut context = X509StoreContext::new().unwrap();
|
||||
assert!(!context
|
||||
.init(&store, &cert, &chain, |c| c
|
||||
.verify_cert_with_crls(stack_of(crl)))
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_save_subject_der() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::ffi;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use libc::c_uint;
|
||||
use libc::{c_uint, time_t};
|
||||
use std::net::IpAddr;
|
||||
|
||||
use crate::cvt;
|
||||
@ -22,6 +22,30 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags used to configure verification of an `X509` certificate
|
||||
pub struct X509VerifyFlags: c_uint {
|
||||
const CB_ISSUER_CHECK = ffi::X509_V_FLAG_CB_ISSUER_CHECK as _;
|
||||
const USE_CHECK_TIME = ffi::X509_V_FLAG_USE_CHECK_TIME as _;
|
||||
const CRL_CHECK = ffi::X509_V_FLAG_CRL_CHECK as _;
|
||||
const CRL_CHECK_ALL = ffi::X509_V_FLAG_CRL_CHECK_ALL as _;
|
||||
const IGNORE_CRITICAL = ffi::X509_V_FLAG_IGNORE_CRITICAL as _;
|
||||
const X509_STRICT = ffi::X509_V_FLAG_X509_STRICT as _;
|
||||
const ALLOW_PROXY_CERTS = ffi::X509_V_FLAG_ALLOW_PROXY_CERTS as _;
|
||||
const POLICY_CHECK = ffi::X509_V_FLAG_POLICY_CHECK as _;
|
||||
const EXPLICIT_POLICY = ffi::X509_V_FLAG_EXPLICIT_POLICY as _;
|
||||
const INHIBIT_ANY = ffi::X509_V_FLAG_INHIBIT_ANY as _;
|
||||
const INHIBIT_MAP = ffi::X509_V_FLAG_INHIBIT_MAP as _;
|
||||
const NOTIFY_POLICY = ffi::X509_V_FLAG_NOTIFY_POLICY as _;
|
||||
const EXTENDED_CRL_SUPPORT = ffi::X509_V_FLAG_EXTENDED_CRL_SUPPORT as _;
|
||||
const FLAG_USE_DELTAS = ffi::X509_V_FLAG_USE_DELTAS as _;
|
||||
const CHECK_SS_SIGNATURE = ffi::X509_V_FLAG_CHECK_SS_SIGNATURE as _;
|
||||
const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST as _;
|
||||
const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN as _;
|
||||
const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS as _;
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type_and_impl_send_sync! {
|
||||
type CType = ffi::X509_VERIFY_PARAM;
|
||||
fn drop = ffi::X509_VERIFY_PARAM_free;
|
||||
@ -84,4 +108,62 @@ impl X509VerifyParamRef {
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the time to check certificates and CRLs against.
|
||||
///
|
||||
/// If unset, uses the current time.
|
||||
///
|
||||
/// This corresponds to [`X509_VERIFY_PARAM_set_time`]. Note that BoringSSL does not support
|
||||
/// the OpenSSL `NO_CHECK_TIME` option.
|
||||
///
|
||||
/// [`X509_VERIFY_PARAM_set_time`]: https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_time.html
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use boring::x509::store::X509StoreBuilder;
|
||||
/// use std::convert::TryInto;
|
||||
/// use std::time::SystemTime;
|
||||
///
|
||||
/// let mut store_builder = X509StoreBuilder::new().expect("can create a new builder");
|
||||
/// let duration_since_epoch = SystemTime::UNIX_EPOCH.elapsed().expect("it's after 1970");
|
||||
/// let seconds_since_epoch: libc::time_t = duration_since_epoch
|
||||
/// .as_secs()
|
||||
/// .try_into()
|
||||
/// .expect("time_t is large enough to represent this time");
|
||||
/// store_builder.param_mut().set_time(seconds_since_epoch);
|
||||
/// ```
|
||||
pub fn set_time(&mut self, unix_time: time_t) {
|
||||
unsafe { ffi::X509_VERIFY_PARAM_set_time(self.as_ptr(), unix_time) }
|
||||
}
|
||||
|
||||
/// Set the verify flags by OR-ing them with `flags`
|
||||
///
|
||||
/// This corresponds to [`X509_VERIFY_PARAM_set_flags`].
|
||||
///
|
||||
/// [`X509_VERIFY_PARAM_set_flags`]: https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_flags.html
|
||||
pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_VERIFY_PARAM_set_flags(
|
||||
self.as_ptr(),
|
||||
flags.bits().into(),
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the verify flags in `flags`
|
||||
///
|
||||
/// This corresponds to [`X509_VERIFY_PARAM_clear_flags`]
|
||||
///
|
||||
/// [`X509_VERIFY_PARAM_clear_flags`]: https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_clear_flags.html
|
||||
pub fn clear_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_VERIFY_PARAM_clear_flags(
|
||||
self.as_ptr(),
|
||||
flags.bits().into(),
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
boring/test/bad_sig.pem
Normal file
11
boring/test/bad_sig.pem
Normal file
@ -0,0 +1,11 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIBqTCBkjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwK
|
||||
U29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkFw0y
|
||||
MjA2MTYyMjQ0NDFaFw0yMzA2MTYyMjQ0NDFaMBwwGgIJAIdx973umC+lFw0yMjA2
|
||||
MTYyMjIxMDVaMA0GCSqGSIb3DQEBBQUAA4IBAQApqFdwm46jxkJK8J5kprGm6cp8
|
||||
b7XMKB1epvhJGIkXHjp7O+2rxYGIExcNlM7jPcwqnUE0E50qGrqSMEupmtaBH03a
|
||||
fmmDKyhLema7KD64UaERLqWjaW2DPeX9VX6vL4ECc6zTVLxfmYzxVt6A9hhqCm3b
|
||||
fu8klWczGTa79r/WhTbA7uVf5+OI98da5tlxw+DlAQfqd34L2qq5aFg2dcTGqIdz
|
||||
3pxP6UlTyj0ZPK3tUtTpIURVO2/MX3j5V+QjWz81UeCv0gQcmOiIVSRUGwi9c6JY
|
||||
jDqBIvDY6df0riz5is1SS+D94sp1iovBlluwpq4kB8xyDuwt7vblkzleS2YU
|
||||
-----END X509 CRL-----
|
||||
13
boring/test/crl.pem
Normal file
13
boring/test/crl.pem
Normal file
@ -0,0 +1,13 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIB3jCBxwIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJBVTETMBEGA1UE
|
||||
CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
|
||||
Fw0yMjA2MjEyMDIyMDJaFw0zMjA2MTgyMDIyMDJaMBwwGgIJAIdx973umC+lFw0y
|
||||
MjA2MjEyMDIxNTVaoDAwLjAfBgNVHSMEGDAWgBRs06UDqw1fLMmNipyIp4h3uDf9
|
||||
mjALBgNVHRQEBAICEAEwDQYJKoZIhvcNAQELBQADggEBABgsWr/sVZqXm1AzgGCJ
|
||||
JBMJW1oUY18aqroxo4kAIoI4QveLmHxi1Wm2I4dqdc6pM09SJhU5v5CfqpJ2BDc0
|
||||
JBfEk8KKi5O/OYyLcUKa4dEpAlYPgeDyLc6zF8rGLtJoDIYuk4JUeuuByoXt0Sh+
|
||||
7vx6UzuI7EH+mr4ZjnyAkD3f9jZy+mDcTm/+0REuh4iZ1AotE2YuQWQgxc1Y8TlD
|
||||
eK+ks1zBKI23s0hPBxJQunmz2k3Uu9Yf+Sg0KxCiDgJZWFiGSw/6DtnT0oYAFGaD
|
||||
mCyQWtwmS6zGBg+p76wNXkwyJMVvSDgrXSZ55bmImNmA38yKqOLOpB5i+FAS3r4V
|
||||
ApQ=
|
||||
-----END X509 CRL-----
|
||||
11
boring/test/empty_crl.pem
Normal file
11
boring/test/empty_crl.pem
Normal file
@ -0,0 +1,11 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIBijB0MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApT
|
||||
b21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQXDTIy
|
||||
MDYxNjIyNDU1NVoXDTIzMDYxNjIyNDU1NVowDQYJKoZIhvcNAQEFBQADggEBAEtx
|
||||
nBr3aI0qlegMVJsJn3GfkMzaPVTSTHuw76Dzdl9eGDj0hXzAzZW5k4WBHvaInzNT
|
||||
NKkeISoQJHLH981R9sQU2zA8sTESLTJGyCFu05Y6XhdmqX4ywmzVRjL6p/aoHNdZ
|
||||
H1mxgK16wG+Sv0pd+9qNJgC/cNFmNbWzbiEAi5kID4IUxSmId/FZsXsms1EjqDH4
|
||||
DFIwLIQO/kR5zwE5fZ5EjqUBdAxoSVHfD+OPKl4x2t8CHMmao+ih2FOfd70+NLBD
|
||||
2oxaJMjZL/SIf8vYxjpjimMR+7yJ5J5P1j/RBfG3LwwUDP0RtWLIvRQo/dZUyXTg
|
||||
LuC1vNuUoObe12z/NQ4=
|
||||
-----END X509 CRL-----
|
||||
11
boring/test/invalid_crl.pem
Normal file
11
boring/test/invalid_crl.pem
Normal file
@ -0,0 +1,11 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIBmTCBggIBATANBgkqhkiG9w0BAQsFADAhMQ0wCwYDVQQKDARGQUtFMRAwDgYD
|
||||
VQQDDAdGQUtFIENBFw0yMjA2MjcyMTQ3NTBaFw0zMjA2MjQyMTQ3NTBaMBwwGgIJ
|
||||
AIdx973umC+lFw0yMjA2MjcyMTQ2MjhaoA8wDTALBgNVHRQEBAICEAMwDQYJKoZI
|
||||
hvcNAQELBQADggEBAMXZRqTG28rnJSUPnVaqkmePSH15iz5Q/e4MdrM0cipXGuzX
|
||||
z5C8Oh0D2uT3ddawBxTosnbjuzlT7Tanbp3xCRBm9spRPxFbGaFWysBlG1aLTDka
|
||||
e9t9YeErg7wpwU6Qar0dzkLL5IkW3NArgbe8gP9PkYQxz/B0ESdHIPYJP1YBMNG6
|
||||
tLgEhg74Xs9UhOBInNsQB8qMGsEeOnzfiuvfspU/yvKHHzvjAcjeIrONLJaZcu2Y
|
||||
Dsfm5gOXGkHEm5/qJZ/IILoY0GSsSBekCAZda5+v3nvyjfRaBPyhx3Zv+rXh7u5z
|
||||
77bIzPZP60rslomacgEr4p/Y52E4GmKGV+X2+Hc=
|
||||
-----END X509 CRL-----
|
||||
Loading…
Reference in New Issue
Block a user