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

Add support for X509_VERIFY_PARAM_set_time and X509_VERIFY_PARAM_set_… #1710

Merged
merged 1 commit into from Nov 12, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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(|_| ()) }
alexanderjordanbaker marked this conversation as resolved.
Show resolved Hide resolved
}
}

generic_foreign_type_and_impl_send_sync! {
Expand Down
127 changes: 126 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,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
)
}
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) {
alexanderjordanbaker marked this conversation as resolved.
Show resolved Hide resolved
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-----