Skip to content

Commit b30313a

Browse files
authored
Merge pull request #1710 from alexanderjordanbaker/X509VerifyTimeDepth
Add support for X509_VERIFY_PARAM_set_time and X509_VERIFY_PARAM_set_…
2 parents 2aed206 + 808b951 commit b30313a

File tree

7 files changed

+243
-4
lines changed

7 files changed

+243
-4
lines changed

openssl-sys/src/handwritten/x509_vfy.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ extern "C" {
4747
pub fn X509_STORE_set_flags(store: *mut X509_STORE, flags: c_ulong) -> c_int;
4848
}
4949

50+
const_ptr_api! {
51+
extern "C" {
52+
pub fn X509_STORE_set1_param(store: *mut X509_STORE, pm: #[const_ptr_if(ossl300)] X509_VERIFY_PARAM) -> c_int;
53+
}
54+
}
55+
5056
const_ptr_api! {
5157
extern "C" {
5258
pub fn X509_STORE_CTX_get_ex_data(ctx: #[const_ptr_if(ossl300)] X509_STORE_CTX, idx: c_int) -> *mut c_void;
@@ -73,13 +79,21 @@ cfg_if! {
7379
}
7480

7581
extern "C" {
82+
#[cfg(any(ossl102, libressl261))]
83+
pub fn X509_VERIFY_PARAM_new() -> *mut X509_VERIFY_PARAM;
7684
#[cfg(any(ossl102, libressl261))]
7785
pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM);
7886

7987
#[cfg(any(ossl102, libressl261))]
8088
pub fn X509_VERIFY_PARAM_set_flags(param: *mut X509_VERIFY_PARAM, flags: c_ulong) -> c_int;
8189
#[cfg(any(ossl102, libressl261))]
8290
pub fn X509_VERIFY_PARAM_clear_flags(param: *mut X509_VERIFY_PARAM, flags: c_ulong) -> c_int;
91+
92+
#[cfg(any(ossl102, libressl261))]
93+
pub fn X509_VERIFY_PARAM_set_time(param: *mut X509_VERIFY_PARAM, t: time_t);
94+
95+
#[cfg(any(ossl102, libressl261))]
96+
pub fn X509_VERIFY_PARAM_set_depth(param: *mut X509_VERIFY_PARAM, depth: c_int);
8397
}
8498
const_ptr_api! {
8599
extern "C" {

openssl/src/x509/store.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use crate::error::ErrorStack;
5050
use crate::ssl::SslFiletype;
5151
use crate::stack::StackRef;
5252
#[cfg(any(ossl102, libressl261))]
53-
use crate::x509::verify::X509VerifyFlags;
53+
use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef};
5454
use crate::x509::{X509Object, X509};
5555
use crate::{cvt, cvt_p};
5656
use openssl_macros::corresponds;
@@ -122,6 +122,13 @@ impl X509StoreBuilderRef {
122122
pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
123123
unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) }
124124
}
125+
126+
/// Sets certificate chain validation related parameters.
127+
#[corresponds[X509_STORE_set1_param]]
128+
#[cfg(any(ossl102, libressl261))]
129+
pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
130+
unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())).map(|_| ()) }
131+
}
125132
}
126133

127134
generic_foreign_type_and_impl_send_sync! {

openssl/src/x509/tests.rs

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ use crate::x509::extension::{
1313
};
1414
use crate::x509::store::X509StoreBuilder;
1515
#[cfg(any(ossl102, libressl261))]
16-
use crate::x509::verify::X509VerifyFlags;
16+
use crate::x509::verify::{X509VerifyFlags, X509VerifyParam};
1717
#[cfg(ossl110)]
1818
use crate::x509::X509Builder;
1919
use crate::x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509};
2020
use hex::{self, FromHex};
21+
#[cfg(any(ossl102, libressl261))]
22+
use libc::time_t;
2123

2224
fn pkey() -> PKey<Private> {
2325
let rsa = Rsa::generate(2048).unwrap();
@@ -543,3 +545,126 @@ fn test_name_cmp() {
543545
assert_eq!(Ordering::Equal, subject.try_cmp(subject).unwrap());
544546
assert_eq!(Ordering::Greater, subject.try_cmp(issuer).unwrap());
545547
}
548+
549+
#[test]
550+
#[cfg(any(ossl102, libressl261))]
551+
fn test_verify_param_set_time_fails_verification() {
552+
const TEST_T_2030: time_t = 1893456000;
553+
554+
let cert = include_bytes!("../../test/cert.pem");
555+
let cert = X509::from_pem(cert).unwrap();
556+
let ca = include_bytes!("../../test/root-ca.pem");
557+
let ca = X509::from_pem(ca).unwrap();
558+
let chain = Stack::new().unwrap();
559+
560+
let mut store_bldr = X509StoreBuilder::new().unwrap();
561+
store_bldr.add_cert(ca).unwrap();
562+
let mut verify_params = X509VerifyParam::new().unwrap();
563+
verify_params.set_time(TEST_T_2030);
564+
store_bldr.set_param(&verify_params).unwrap();
565+
let store = store_bldr.build();
566+
567+
let mut context = X509StoreContext::new().unwrap();
568+
assert_eq!(
569+
context
570+
.init(&store, &cert, &chain, |c| {
571+
c.verify_cert()?;
572+
Ok(c.error())
573+
})
574+
.unwrap()
575+
.error_string(),
576+
"certificate has expired"
577+
)
578+
}
579+
580+
#[test]
581+
#[cfg(any(ossl102, libressl261))]
582+
fn test_verify_param_set_time() {
583+
const TEST_T_2020: time_t = 1577836800;
584+
585+
let cert = include_bytes!("../../test/cert.pem");
586+
let cert = X509::from_pem(cert).unwrap();
587+
let ca = include_bytes!("../../test/root-ca.pem");
588+
let ca = X509::from_pem(ca).unwrap();
589+
let chain = Stack::new().unwrap();
590+
591+
let mut store_bldr = X509StoreBuilder::new().unwrap();
592+
store_bldr.add_cert(ca).unwrap();
593+
let mut verify_params = X509VerifyParam::new().unwrap();
594+
verify_params.set_time(TEST_T_2020);
595+
store_bldr.set_param(&verify_params).unwrap();
596+
let store = store_bldr.build();
597+
598+
let mut context = X509StoreContext::new().unwrap();
599+
assert!(context
600+
.init(&store, &cert, &chain, |c| c.verify_cert())
601+
.unwrap());
602+
}
603+
604+
#[test]
605+
#[cfg(any(ossl102, libressl261))]
606+
fn test_verify_param_set_depth() {
607+
let cert = include_bytes!("../../test/leaf.pem");
608+
let cert = X509::from_pem(cert).unwrap();
609+
let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem");
610+
let intermediate_ca = X509::from_pem(intermediate_ca).unwrap();
611+
let ca = include_bytes!("../../test/root-ca.pem");
612+
let ca = X509::from_pem(ca).unwrap();
613+
let mut chain = Stack::new().unwrap();
614+
chain.push(intermediate_ca).unwrap();
615+
616+
let mut store_bldr = X509StoreBuilder::new().unwrap();
617+
store_bldr.add_cert(ca).unwrap();
618+
let mut verify_params = X509VerifyParam::new().unwrap();
619+
// OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do
620+
let expected_depth = if cfg!(any(ossl110)) { 1 } else { 2 };
621+
verify_params.set_depth(expected_depth);
622+
store_bldr.set_param(&verify_params).unwrap();
623+
let store = store_bldr.build();
624+
625+
let mut context = X509StoreContext::new().unwrap();
626+
assert!(context
627+
.init(&store, &cert, &chain, |c| c.verify_cert())
628+
.unwrap());
629+
}
630+
631+
#[test]
632+
#[cfg(any(ossl102, libressl261))]
633+
fn test_verify_param_set_depth_fails_verification() {
634+
let cert = include_bytes!("../../test/leaf.pem");
635+
let cert = X509::from_pem(cert).unwrap();
636+
let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem");
637+
let intermediate_ca = X509::from_pem(intermediate_ca).unwrap();
638+
let ca = include_bytes!("../../test/root-ca.pem");
639+
let ca = X509::from_pem(ca).unwrap();
640+
let mut chain = Stack::new().unwrap();
641+
chain.push(intermediate_ca).unwrap();
642+
643+
let mut store_bldr = X509StoreBuilder::new().unwrap();
644+
store_bldr.add_cert(ca).unwrap();
645+
let mut verify_params = X509VerifyParam::new().unwrap();
646+
// OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do
647+
let expected_depth = if cfg!(any(ossl110)) { 0 } else { 1 };
648+
verify_params.set_depth(expected_depth);
649+
store_bldr.set_param(&verify_params).unwrap();
650+
let store = store_bldr.build();
651+
652+
// OpenSSL 1.1.0+ added support for X509_V_ERR_CERT_CHAIN_TOO_LONG, while 1.0.2 simply ignores the intermediate
653+
let expected_error = if cfg!(any(ossl110, libressl261)) {
654+
"certificate chain too long"
655+
} else {
656+
"unable to get local issuer certificate"
657+
};
658+
659+
let mut context = X509StoreContext::new().unwrap();
660+
assert_eq!(
661+
context
662+
.init(&store, &cert, &chain, |c| {
663+
c.verify_cert()?;
664+
Ok(c.error())
665+
})
666+
.unwrap()
667+
.error_string(),
668+
expected_error
669+
)
670+
}

openssl/src/x509/verify.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use bitflags::bitflags;
22
use foreign_types::ForeignTypeRef;
3-
use libc::{c_uint, c_ulong};
3+
use libc::{c_int, c_uint, c_ulong, time_t};
44
use std::net::IpAddr;
55

6-
use crate::cvt;
76
use crate::error::ErrorStack;
7+
use crate::{cvt, cvt_p};
88
use openssl_macros::corresponds;
99

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

72+
impl X509VerifyParam {
73+
/// Create an X509VerifyParam
74+
#[corresponds(X509_VERIFY_PARAM_new)]
75+
pub fn new() -> Result<X509VerifyParam, ErrorStack> {
76+
unsafe {
77+
ffi::init();
78+
cvt_p(ffi::X509_VERIFY_PARAM_new()).map(X509VerifyParam)
79+
}
80+
}
81+
}
82+
7283
impl X509VerifyParamRef {
7384
/// Set the host flags.
7485
#[corresponds(X509_VERIFY_PARAM_set_hostflags)]
@@ -139,4 +150,16 @@ impl X509VerifyParamRef {
139150
.map(|_| ())
140151
}
141152
}
153+
154+
/// Set the verification time, where time is of type time_t, traditionaly defined as seconds since the epoch
155+
#[corresponds(X509_VERIFY_PARAM_set_time)]
156+
pub fn set_time(&mut self, time: time_t) {
157+
unsafe { ffi::X509_VERIFY_PARAM_set_time(self.as_ptr(), time) }
158+
}
159+
160+
/// Set the verification depth
161+
#[corresponds(X509_VERIFY_PARAM_set_depth)]
162+
pub fn set_depth(&mut self, depth: c_int) {
163+
unsafe { ffi::X509_VERIFY_PARAM_set_depth(self.as_ptr(), depth) }
164+
}
142165
}

openssl/test/intermediate-ca.key

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpAIBAAKCAQEA1HsHFTpgKeWL/y6oKtARZm0Dy6J/08E0CujmdpVp0xnkXi/A
3+
RARnbMEbOPfmBUMOkVtQT3+l5aCgIAX+Kg6K7sQvio8nQUgOxuO1YpGlYu9EMtc7
4+
5fNxA1T0CuXXx8ClfEqW1ZV7ziQV0J4gzvuI26A7XyUhdk1oP/Al3F/94TmH6dtP
5+
SQ2K901O2zknU+bpPheQy08SE20k/nUOJAsiwtsxqY8hHOL1sXZ4K+I311hl0QpD
6+
OYf7eBcBdo2Mc5Nzjd9LPGLk1lE3itAXpayFMmfuuA0IdH1gNfy18axFEEVnj6CS
7+
2epGpmAckUEWUOse1WBhDEt6ddowT1iw7X4mWwIDAQABAoIBAGMGXzuudAiymTc5
8+
OFiTlbhlkAJEXkyC201GU7nqUmJ2y651lKZeYxEVQimfpszG/rARnXEfbWKCJH4o
9+
LNbO5kL2na12n/XVrkVU9EDW3fwoxGDpXFoDxaSm4AGAMrs+diFh5b/upb9ho+UQ
10+
/PtZ0OOCXokuFdU7qB08P3jgJ8LhooqWnZ4AC0rhN85CMNIKs/nrUrnmS3FZLVd/
11+
NWI9Vfjsndd41Gkho0A7tgOSnwRupk/Bv1b0px31h8ucp9/nLuR8vbGSdS/R9Sta
12+
pB9KNYYQ3LrhQGjddnEU0gj8qsuWgnoPf7eaWsLVunPLHQzL2hNNKL1eBADm7Lhh
13+
avIlnrkCgYEA8Q8UhOeIO0sMU8sB4NPTUf2UT9xjURoowGsGgbDEk21eABH6VC33
14+
VYt5r5xwbZFQvVaTbe+EI1YDpjH1cvpmorEWI47Nm4Vbf9JujW/hoQwuwpzOpdUT
15+
2G4tfMQrmTw/9HJ0l9+1Ib+A93dB8GvR0NE1uueaWanWvXARInwGiscCgYEA4aZ9
16+
mbhuwx88sSRMXwxSZw+R5BRrjdC0CeoimGg4/P84bKgc0YsjAha5jWaC/h8xN2Pb
17+
w45b3hQ0/FP8xohP0bp/5eeiDbqb6JuO5bI3CnfBrVpu1CAuIrf7lhkar3a0wluB
18+
k03fVHuVLtydACDJBKrZm1F39lpiZiEqlBIp080CgYEAwRwYjwPAEefkHzhQ7+Ah
19+
uNwQtQ1TjsQLA2J5mumWAJirphjA1jDgo+oQ+Iq1UkEIUjWJ85bd30TntXruK0bH
20+
c+uzVZbvxXfGvhZAtBN9x/svdn4R2a1hsY9J51prpt0qStRp7MSsoTV9xkEGVOi6
21+
87K1fV5OOyggvC+Lunlq8D8CgYAVSCOObPOdWYPa3SaKzFm1OKW00iw2qtlgGgH7
22+
R9EgI14J+W0GYk4B82y6plFycDSvGa7vaazGbDd3GOC9RLvqduF7KHaDPvdXX9yB
23+
U2aXiSXuGJpdTU+snJeQ13tJ0zNHJWQ6JV0L1cADNHFmQrFSzF5LpMpgpLOlGDmw
24+
z2m8fQKBgQDclFeonyn0zcXqznun9kAKkMij4s6lSdRgi/5Zh1WbJwOso9oWfwz9
25+
SSTP2KBO8B+/yFvuo5SWrbNaTz9/KuzMTv4HXz5ukLbyN9Jjtk73fdBBRSjL+zF5
26+
jU56oXHrwBhEqWQ77Ps60r+FmDjUgUhyJl14ZfkzICUK7NLFxKrvMQ==
27+
-----END RSA PRIVATE KEY-----

openssl/test/intermediate-ca.pem

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDszCCApugAwIBAgIEFSQSITANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
3+
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
4+
cyBQdHkgTHRkMB4XDTIyMTEwMzA3MDc0OVoXDTI2MDgxMTA3MDc0OVowgYkxCzAJ
5+
BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l
6+
dCBXaWRnaXRzIFB0eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRt
7+
ZW50MSAwHgYDVQQDDBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTCCASIwDQYJKoZI
8+
hvcNAQEBBQADggEPADCCAQoCggEBANR7BxU6YCnli/8uqCrQEWZtA8uif9PBNAro
9+
5naVadMZ5F4vwEQEZ2zBGzj35gVDDpFbUE9/peWgoCAF/ioOiu7EL4qPJ0FIDsbj
10+
tWKRpWLvRDLXO+XzcQNU9Arl18fApXxKltWVe84kFdCeIM77iNugO18lIXZNaD/w
11+
Jdxf/eE5h+nbT0kNivdNTts5J1Pm6T4XkMtPEhNtJP51DiQLIsLbMamPIRzi9bF2
12+
eCviN9dYZdEKQzmH+3gXAXaNjHOTc43fSzxi5NZRN4rQF6WshTJn7rgNCHR9YDX8
13+
tfGsRRBFZ4+gktnqRqZgHJFBFlDrHtVgYQxLenXaME9YsO1+JlsCAwEAAaNmMGQw
14+
HQYDVR0OBBYEFAXJImmmxYXx6L1SRRhgP3Tyq2J6MB8GA1UdIwQYMBaAFGzTpQOr
15+
DV8syY2KnIiniHe4N/2aMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD
16+
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQCnUh7iNbnFBjVa4sFx02r65syxUhcvM/ya
17+
DcSe1esGUwjZLyKVl9BTfQ6kfNa/6Z/t5cprp0R3etalN31dxka7xSDwzFNdBczB
18+
zYDIVOVlcGLL1Xjozacm6YHo773dqxZS36rVMk3NqNUY6GJJ+CGso2xZShcBg2KG
19+
fPlNPiRz3847E3dwouDYcP1MXf2ql/Y7dRbE+8kb3bWkSusJVb/4EHjpR7yZjKmh
20+
eXHVVx1dKnCGRldn3+dSNhN6mxNaSeBE2hb158+diQvL5u3f//va7SOpCi0f4d8E
21+
UCnLhieyrDlr42XXfz42BqRpqBO1SDjQwzIIc9Fbevwb916OSExp
22+
-----END CERTIFICATE-----

openssl/test/leaf.pem

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDejCCAmICBBUkEiQwDQYJKoZIhvcNAQELBQAwgYkxCzAJBgNVBAYTAkFVMRMw
3+
EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0
4+
eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRtZW50MSAwHgYDVQQD
5+
DBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTAeFw0yMjExMDMwNzE3NTJaFw0yNjA4
6+
MTEwNzE3NTJaMHkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
7+
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAsMD0xlYWYg
8+
RGVwYXJ0bWVudDEYMBYGA1UEAwwPbGVhZi5mb29iYXIuY29tMIIBIjANBgkqhkiG
9+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs9STUHGIcSOtioK6+02k9Jx4JuYVJ0SB7Ebd
10+
FAhGiOxBSoOljRVmmALti89QMmRiRqlyJnGJch7AloCCRsLJA0MfUYvauqmKHZFk
11+
iqtZ1HocHQ/LGNKfkILcclb4xp2nGYntKAyEqer3Qc6aPWAnQAV/+BshU1vlMfwU
12+
T6vOJRG69mft6dkHEWSzZd7++7HmFQGnDmIs5jBJVCOgKVttkN8Bk2EsTvJi9zl2
13+
SXLTcVrTAxEvuawv2ZXvdI/Cpt1WW0litXlFLcYBGwt/N93TX/L3Iyw5HcNd/xf9
14+
QwOr6RR66krQJzKxwcIY934uq6cyTQhexgnffb65qXL4bbV5fwIDAQABMA0GCSqG
15+
SIb3DQEBCwUAA4IBAQAZf0/r04AeKN2QhQ7Z0o2Iu/Yj3OD2tnbxVoltYk8CRfp3
16+
7VGl/5PUbmXXBSwMc4Udj88JlreU7iNEPAKtBqFczw0pwNfvxKG4Eh3vsfKrP+5g
17+
gtVwDG0mWeKJ7udrmFt8N0uwxVYDKp/gv5+Bw2eMew9Eoyenj6k2yg0nbFKzA3EH
18+
DqngETzX0dhdiYwVcoJFUK5ni3tVl9qi6FpmaTE6C5nTQLyH4CI+vo2x/QHINGaJ
19+
OzY/rx35iyVqXVqxN/gO/hp6g0nT5zLuMg2rfvcAhdDsD7htYcHiNkofrC8s0oQE
20+
W+r01EhxdEVvY1nYWanBCF6tktc5v5qf2WMS4ye5
21+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)