Commit 808b9519 authored by Alex Baker's avatar Alex Baker
Browse files

Add support for X509_VERIFY_PARAM_set_time and X509_VERIFY_PARAM_set_depth

parent bbdcaf7c
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -47,6 +47,12 @@ extern "C" {
    pub fn X509_STORE_set_flags(store: *mut X509_STORE, flags: c_ulong) -> c_int;
}

const_ptr_api! {
    extern "C" {
        pub fn X509_STORE_set1_param(store: *mut X509_STORE, pm: #[const_ptr_if(ossl300)] X509_VERIFY_PARAM) -> c_int;
    }
}

const_ptr_api! {
    extern "C" {
        pub fn X509_STORE_CTX_get_ex_data(ctx: #[const_ptr_if(ossl300)] X509_STORE_CTX, idx: c_int) -> *mut c_void;
@@ -73,6 +79,8 @@ cfg_if! {
}

extern "C" {
    #[cfg(any(ossl102, libressl261))]
    pub fn X509_VERIFY_PARAM_new() -> *mut X509_VERIFY_PARAM;
    #[cfg(any(ossl102, libressl261))]
    pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM);

@@ -80,6 +88,12 @@ extern "C" {
    pub fn X509_VERIFY_PARAM_set_flags(param: *mut X509_VERIFY_PARAM, flags: c_ulong) -> c_int;
    #[cfg(any(ossl102, libressl261))]
    pub fn X509_VERIFY_PARAM_clear_flags(param: *mut X509_VERIFY_PARAM, flags: c_ulong) -> c_int;

    #[cfg(any(ossl102, libressl261))]
    pub fn X509_VERIFY_PARAM_set_time(param: *mut X509_VERIFY_PARAM, t: time_t);

    #[cfg(any(ossl102, libressl261))]
    pub fn X509_VERIFY_PARAM_set_depth(param: *mut X509_VERIFY_PARAM, depth: c_int);
}
const_ptr_api! {
    extern "C" {
+8 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ use crate::error::ErrorStack;
use crate::ssl::SslFiletype;
use crate::stack::StackRef;
#[cfg(any(ossl102, libressl261))]
use crate::x509::verify::X509VerifyFlags;
use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef};
use crate::x509::{X509Object, X509};
use crate::{cvt, cvt_p};
use openssl_macros::corresponds;
@@ -122,6 +122,13 @@ impl X509StoreBuilderRef {
    pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
        unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) }
    }

    /// Sets certificate chain validation related parameters.
    #[corresponds[X509_STORE_set1_param]]
    #[cfg(any(ossl102, libressl261))]
    pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
        unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())).map(|_| ()) }
    }
}

generic_foreign_type_and_impl_send_sync! {
+126 −1
Original line number Diff line number Diff line
@@ -13,11 +13,13 @@ use crate::x509::extension::{
};
use crate::x509::store::X509StoreBuilder;
#[cfg(any(ossl102, libressl261))]
use crate::x509::verify::X509VerifyFlags;
use crate::x509::verify::{X509VerifyFlags, X509VerifyParam};
#[cfg(ossl110)]
use crate::x509::X509Builder;
use crate::x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509};
use hex::{self, FromHex};
#[cfg(any(ossl102, libressl261))]
use libc::time_t;

fn pkey() -> PKey<Private> {
    let rsa = Rsa::generate(2048).unwrap();
@@ -543,3 +545,126 @@ fn test_name_cmp() {
    assert_eq!(Ordering::Equal, subject.try_cmp(subject).unwrap());
    assert_eq!(Ordering::Greater, subject.try_cmp(issuer).unwrap());
}

#[test]
#[cfg(any(ossl102, libressl261))]
fn test_verify_param_set_time_fails_verification() {
    const TEST_T_2030: time_t = 1893456000;

    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();
    let mut verify_params = X509VerifyParam::new().unwrap();
    verify_params.set_time(TEST_T_2030);
    store_bldr.set_param(&verify_params).unwrap();
    let store = store_bldr.build();

    let mut context = X509StoreContext::new().unwrap();
    assert_eq!(
        context
            .init(&store, &cert, &chain, |c| {
                c.verify_cert()?;
                Ok(c.error())
            })
            .unwrap()
            .error_string(),
        "certificate has expired"
    )
}

#[test]
#[cfg(any(ossl102, libressl261))]
fn test_verify_param_set_time() {
    const TEST_T_2020: time_t = 1577836800;

    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();
    let mut verify_params = X509VerifyParam::new().unwrap();
    verify_params.set_time(TEST_T_2020);
    store_bldr.set_param(&verify_params).unwrap();
    let store = store_bldr.build();

    let mut context = X509StoreContext::new().unwrap();
    assert!(context
        .init(&store, &cert, &chain, |c| c.verify_cert())
        .unwrap());
}

#[test]
#[cfg(any(ossl102, libressl261))]
fn test_verify_param_set_depth() {
    let cert = include_bytes!("../../test/leaf.pem");
    let cert = X509::from_pem(cert).unwrap();
    let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem");
    let intermediate_ca = X509::from_pem(intermediate_ca).unwrap();
    let ca = include_bytes!("../../test/root-ca.pem");
    let ca = X509::from_pem(ca).unwrap();
    let mut chain = Stack::new().unwrap();
    chain.push(intermediate_ca).unwrap();

    let mut store_bldr = X509StoreBuilder::new().unwrap();
    store_bldr.add_cert(ca).unwrap();
    let mut verify_params = X509VerifyParam::new().unwrap();
    // OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do
    let expected_depth = if cfg!(any(ossl110)) { 1 } else { 2 };
    verify_params.set_depth(expected_depth);
    store_bldr.set_param(&verify_params).unwrap();
    let store = store_bldr.build();

    let mut context = X509StoreContext::new().unwrap();
    assert!(context
        .init(&store, &cert, &chain, |c| c.verify_cert())
        .unwrap());
}

#[test]
#[cfg(any(ossl102, libressl261))]
fn test_verify_param_set_depth_fails_verification() {
    let cert = include_bytes!("../../test/leaf.pem");
    let cert = X509::from_pem(cert).unwrap();
    let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem");
    let intermediate_ca = X509::from_pem(intermediate_ca).unwrap();
    let ca = include_bytes!("../../test/root-ca.pem");
    let ca = X509::from_pem(ca).unwrap();
    let mut chain = Stack::new().unwrap();
    chain.push(intermediate_ca).unwrap();

    let mut store_bldr = X509StoreBuilder::new().unwrap();
    store_bldr.add_cert(ca).unwrap();
    let mut verify_params = X509VerifyParam::new().unwrap();
    // OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do
    let expected_depth = if cfg!(any(ossl110)) { 0 } else { 1 };
    verify_params.set_depth(expected_depth);
    store_bldr.set_param(&verify_params).unwrap();
    let store = store_bldr.build();

    // OpenSSL 1.1.0+ added support for X509_V_ERR_CERT_CHAIN_TOO_LONG, while 1.0.2 simply ignores the intermediate
    let expected_error = if cfg!(any(ossl110, libressl261)) {
        "certificate chain too long"
    } else {
        "unable to get local issuer certificate"
    };

    let mut context = X509StoreContext::new().unwrap();
    assert_eq!(
        context
            .init(&store, &cert, &chain, |c| {
                c.verify_cert()?;
                Ok(c.error())
            })
            .unwrap()
            .error_string(),
        expected_error
    )
}
+25 −2
Original line number Diff line number Diff line
use bitflags::bitflags;
use foreign_types::ForeignTypeRef;
use libc::{c_uint, c_ulong};
use libc::{c_int, c_uint, c_ulong, time_t};
use std::net::IpAddr;

use crate::cvt;
use crate::error::ErrorStack;
use crate::{cvt, cvt_p};
use openssl_macros::corresponds;

bitflags! {
@@ -69,6 +69,17 @@ foreign_type_and_impl_send_sync! {
    pub struct X509VerifyParamRef;
}

impl X509VerifyParam {
    /// Create an X509VerifyParam
    #[corresponds(X509_VERIFY_PARAM_new)]
    pub fn new() -> Result<X509VerifyParam, ErrorStack> {
        unsafe {
            ffi::init();
            cvt_p(ffi::X509_VERIFY_PARAM_new()).map(X509VerifyParam)
        }
    }
}

impl X509VerifyParamRef {
    /// Set the host flags.
    #[corresponds(X509_VERIFY_PARAM_set_hostflags)]
@@ -139,4 +150,16 @@ impl X509VerifyParamRef {
            .map(|_| ())
        }
    }

    /// Set the verification time, where time is of type time_t, traditionaly defined as seconds since the epoch
    #[corresponds(X509_VERIFY_PARAM_set_time)]
    pub fn set_time(&mut self, time: time_t) {
        unsafe { ffi::X509_VERIFY_PARAM_set_time(self.as_ptr(), time) }
    }

    /// Set the verification depth
    #[corresponds(X509_VERIFY_PARAM_set_depth)]
    pub fn set_depth(&mut self, depth: c_int) {
        unsafe { ffi::X509_VERIFY_PARAM_set_depth(self.as_ptr(), depth) }
    }
}
+27 −0
Original line number Diff line number Diff line
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1HsHFTpgKeWL/y6oKtARZm0Dy6J/08E0CujmdpVp0xnkXi/A
RARnbMEbOPfmBUMOkVtQT3+l5aCgIAX+Kg6K7sQvio8nQUgOxuO1YpGlYu9EMtc7
5fNxA1T0CuXXx8ClfEqW1ZV7ziQV0J4gzvuI26A7XyUhdk1oP/Al3F/94TmH6dtP
SQ2K901O2zknU+bpPheQy08SE20k/nUOJAsiwtsxqY8hHOL1sXZ4K+I311hl0QpD
OYf7eBcBdo2Mc5Nzjd9LPGLk1lE3itAXpayFMmfuuA0IdH1gNfy18axFEEVnj6CS
2epGpmAckUEWUOse1WBhDEt6ddowT1iw7X4mWwIDAQABAoIBAGMGXzuudAiymTc5
OFiTlbhlkAJEXkyC201GU7nqUmJ2y651lKZeYxEVQimfpszG/rARnXEfbWKCJH4o
LNbO5kL2na12n/XVrkVU9EDW3fwoxGDpXFoDxaSm4AGAMrs+diFh5b/upb9ho+UQ
/PtZ0OOCXokuFdU7qB08P3jgJ8LhooqWnZ4AC0rhN85CMNIKs/nrUrnmS3FZLVd/
NWI9Vfjsndd41Gkho0A7tgOSnwRupk/Bv1b0px31h8ucp9/nLuR8vbGSdS/R9Sta
pB9KNYYQ3LrhQGjddnEU0gj8qsuWgnoPf7eaWsLVunPLHQzL2hNNKL1eBADm7Lhh
avIlnrkCgYEA8Q8UhOeIO0sMU8sB4NPTUf2UT9xjURoowGsGgbDEk21eABH6VC33
VYt5r5xwbZFQvVaTbe+EI1YDpjH1cvpmorEWI47Nm4Vbf9JujW/hoQwuwpzOpdUT
2G4tfMQrmTw/9HJ0l9+1Ib+A93dB8GvR0NE1uueaWanWvXARInwGiscCgYEA4aZ9
mbhuwx88sSRMXwxSZw+R5BRrjdC0CeoimGg4/P84bKgc0YsjAha5jWaC/h8xN2Pb
w45b3hQ0/FP8xohP0bp/5eeiDbqb6JuO5bI3CnfBrVpu1CAuIrf7lhkar3a0wluB
k03fVHuVLtydACDJBKrZm1F39lpiZiEqlBIp080CgYEAwRwYjwPAEefkHzhQ7+Ah
uNwQtQ1TjsQLA2J5mumWAJirphjA1jDgo+oQ+Iq1UkEIUjWJ85bd30TntXruK0bH
c+uzVZbvxXfGvhZAtBN9x/svdn4R2a1hsY9J51prpt0qStRp7MSsoTV9xkEGVOi6
87K1fV5OOyggvC+Lunlq8D8CgYAVSCOObPOdWYPa3SaKzFm1OKW00iw2qtlgGgH7
R9EgI14J+W0GYk4B82y6plFycDSvGa7vaazGbDd3GOC9RLvqduF7KHaDPvdXX9yB
U2aXiSXuGJpdTU+snJeQ13tJ0zNHJWQ6JV0L1cADNHFmQrFSzF5LpMpgpLOlGDmw
z2m8fQKBgQDclFeonyn0zcXqznun9kAKkMij4s6lSdRgi/5Zh1WbJwOso9oWfwz9
SSTP2KBO8B+/yFvuo5SWrbNaTz9/KuzMTv4HXz5ukLbyN9Jjtk73fdBBRSjL+zF5
jU56oXHrwBhEqWQ77Ps60r+FmDjUgUhyJl14ZfkzICUK7NLFxKrvMQ==
-----END RSA PRIVATE KEY-----
Loading