Skip to content

Commit

Permalink
Add support for X509_VERIFY_PARAM_set_time and X509_VERIFY_PARAM_set_…
Browse files Browse the repository at this point in the history
…depth
  • Loading branch information
alexanderjordanbaker committed Nov 3, 2022
1 parent bbdcaf7 commit 449bd45
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 4 deletions.
14 changes: 14 additions & 0 deletions openssl-sys/src/handwritten/x509_vfy.rs
Expand Up @@ -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;
Expand All @@ -73,13 +79,21 @@ 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);

#[cfg(any(ossl102, libressl261))]
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" {
Expand Down
9 changes: 8 additions & 1 deletion openssl/src/x509/store.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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! {
Expand Down
135 changes: 134 additions & 1 deletion openssl/src/x509/tests.rs
Expand Up @@ -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();
Expand Down Expand Up @@ -543,3 +545,134 @@ 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
)
}
27 changes: 25 additions & 2 deletions openssl/src/x509/verify.rs
@@ -1,10 +1,10 @@
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! {
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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 changes: 27 additions & 0 deletions openssl/test/intermediate-ca.key
@@ -0,0 +1,27 @@
-----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-----
22 changes: 22 additions & 0 deletions openssl/test/intermediate-ca.pem
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIEFSQSITANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMB4XDTIyMTEwMzA3MDc0OVoXDTI2MDgxMTA3MDc0OVowgYkxCzAJ
BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l
dCBXaWRnaXRzIFB0eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRt
ZW50MSAwHgYDVQQDDBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANR7BxU6YCnli/8uqCrQEWZtA8uif9PBNAro
5naVadMZ5F4vwEQEZ2zBGzj35gVDDpFbUE9/peWgoCAF/ioOiu7EL4qPJ0FIDsbj
tWKRpWLvRDLXO+XzcQNU9Arl18fApXxKltWVe84kFdCeIM77iNugO18lIXZNaD/w
Jdxf/eE5h+nbT0kNivdNTts5J1Pm6T4XkMtPEhNtJP51DiQLIsLbMamPIRzi9bF2
eCviN9dYZdEKQzmH+3gXAXaNjHOTc43fSzxi5NZRN4rQF6WshTJn7rgNCHR9YDX8
tfGsRRBFZ4+gktnqRqZgHJFBFlDrHtVgYQxLenXaME9YsO1+JlsCAwEAAaNmMGQw
HQYDVR0OBBYEFAXJImmmxYXx6L1SRRhgP3Tyq2J6MB8GA1UdIwQYMBaAFGzTpQOr
DV8syY2KnIiniHe4N/2aMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQCnUh7iNbnFBjVa4sFx02r65syxUhcvM/ya
DcSe1esGUwjZLyKVl9BTfQ6kfNa/6Z/t5cprp0R3etalN31dxka7xSDwzFNdBczB
zYDIVOVlcGLL1Xjozacm6YHo773dqxZS36rVMk3NqNUY6GJJ+CGso2xZShcBg2KG
fPlNPiRz3847E3dwouDYcP1MXf2ql/Y7dRbE+8kb3bWkSusJVb/4EHjpR7yZjKmh
eXHVVx1dKnCGRldn3+dSNhN6mxNaSeBE2hb158+diQvL5u3f//va7SOpCi0f4d8E
UCnLhieyrDlr42XXfz42BqRpqBO1SDjQwzIIc9Fbevwb916OSExp
-----END CERTIFICATE-----
21 changes: 21 additions & 0 deletions openssl/test/leaf.pem
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDejCCAmICBBUkEiQwDQYJKoZIhvcNAQELBQAwgYkxCzAJBgNVBAYTAkFVMRMw
EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0
eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRtZW50MSAwHgYDVQQD
DBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTAeFw0yMjExMDMwNzE3NTJaFw0yNjA4
MTEwNzE3NTJaMHkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAsMD0xlYWYg
RGVwYXJ0bWVudDEYMBYGA1UEAwwPbGVhZi5mb29iYXIuY29tMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs9STUHGIcSOtioK6+02k9Jx4JuYVJ0SB7Ebd
FAhGiOxBSoOljRVmmALti89QMmRiRqlyJnGJch7AloCCRsLJA0MfUYvauqmKHZFk
iqtZ1HocHQ/LGNKfkILcclb4xp2nGYntKAyEqer3Qc6aPWAnQAV/+BshU1vlMfwU
T6vOJRG69mft6dkHEWSzZd7++7HmFQGnDmIs5jBJVCOgKVttkN8Bk2EsTvJi9zl2
SXLTcVrTAxEvuawv2ZXvdI/Cpt1WW0litXlFLcYBGwt/N93TX/L3Iyw5HcNd/xf9
QwOr6RR66krQJzKxwcIY934uq6cyTQhexgnffb65qXL4bbV5fwIDAQABMA0GCSqG
SIb3DQEBCwUAA4IBAQAZf0/r04AeKN2QhQ7Z0o2Iu/Yj3OD2tnbxVoltYk8CRfp3
7VGl/5PUbmXXBSwMc4Udj88JlreU7iNEPAKtBqFczw0pwNfvxKG4Eh3vsfKrP+5g
gtVwDG0mWeKJ7udrmFt8N0uwxVYDKp/gv5+Bw2eMew9Eoyenj6k2yg0nbFKzA3EH
DqngETzX0dhdiYwVcoJFUK5ni3tVl9qi6FpmaTE6C5nTQLyH4CI+vo2x/QHINGaJ
OzY/rx35iyVqXVqxN/gO/hp6g0nT5zLuMg2rfvcAhdDsD7htYcHiNkofrC8s0oQE
W+r01EhxdEVvY1nYWanBCF6tktc5v5qf2WMS4ye5
-----END CERTIFICATE-----

0 comments on commit 449bd45

Please sign in to comment.