mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust/pv/test: Code + Certificate refactoring
* Get rid of Mockito * create certs with AKID * simplify things in the `create_certs.py` script Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
committed by
Steffen Eiden
parent
966e67a252
commit
f6c6f0cc71
+12
-4
@@ -7,8 +7,12 @@ use log::debug;
|
||||
use openssl::stack::Stack;
|
||||
use openssl::x509::store::X509Store;
|
||||
use openssl::x509::{CrlStatus, X509Ref, X509StoreContext, X509};
|
||||
use openssl_extensions::crl::StackableX509Crl;
|
||||
use openssl_extensions::crl::X509StoreContextExtension;
|
||||
use openssl_extensions::crl::{StackableX509Crl, X509StoreContextExtension, X509StoreExtension};
|
||||
|
||||
#[cfg(not(test))]
|
||||
use helper::download_first_crl_from_x509;
|
||||
#[cfg(test)]
|
||||
use test::download_first_crl_from_x509;
|
||||
|
||||
use crate::error::bail_hkd_verify;
|
||||
use crate::misc::{read_certs, read_file};
|
||||
@@ -113,7 +117,7 @@ impl CertVerifier {
|
||||
|
||||
if !self.offline {
|
||||
// Try to download a CRL if defined in the HKD
|
||||
if let Some(crl) = helper::download_first_crl_from_x509(hkd)? {
|
||||
if let Some(crl) = download_first_crl_from_x509(hkd)? {
|
||||
crl.into_iter().try_for_each(|c| crls.push(c.into()))?;
|
||||
}
|
||||
}
|
||||
@@ -143,7 +147,11 @@ impl CertVerifier {
|
||||
for path in cert_paths {
|
||||
let mut crt = read_certs(&read_file(path, "certificate")?)?;
|
||||
if !offline {
|
||||
helper::download_crls_into_store(&mut store, &crt)?;
|
||||
for c in &crt {
|
||||
if let Some(crl) = download_first_crl_from_x509(c)? {
|
||||
crl.iter().try_for_each(|c| store.add_crl(c))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
untr_certs.append(&mut crt);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use crate::error::bail_hkd_verify;
|
||||
use crate::misc::read_crls;
|
||||
use crate::HkdVerifyErrorType::*;
|
||||
use crate::{Error, Result};
|
||||
use curl::easy::{Easy2, Handler, WriteError};
|
||||
use log::debug;
|
||||
use openssl::{
|
||||
asn1::{Asn1Time, Asn1TimeRef},
|
||||
@@ -15,17 +13,14 @@ use openssl::{
|
||||
ssl::SslFiletype,
|
||||
stack::{Stack, Stackable},
|
||||
x509::{
|
||||
store::{File, X509Lookup, X509StoreBuilder, X509StoreBuilderRef, X509StoreRef},
|
||||
store::{File, X509Lookup, X509StoreBuilder, X509StoreRef},
|
||||
verify::{X509VerifyFlags, X509VerifyParam},
|
||||
X509Crl, X509CrlRef, X509Name, X509NameRef, X509PurposeId, X509Ref, X509StoreContext,
|
||||
X509CrlRef, X509Name, X509NameRef, X509PurposeId, X509Ref, X509StoreContext,
|
||||
X509StoreContextRef, X509VerifyResult, X509,
|
||||
},
|
||||
};
|
||||
use openssl_extensions::{
|
||||
akid::{AkidCheckResult, AkidExtension},
|
||||
crl::X509StoreExtension,
|
||||
};
|
||||
use std::{cmp::Ordering, ffi::c_int, time::Duration, usize};
|
||||
use openssl_extensions::akid::{AkidCheckResult, AkidExtension};
|
||||
use std::{cmp::Ordering, ffi::c_int, usize};
|
||||
|
||||
/// Minimum security level for the keys/certificates used to establish a chain of
|
||||
/// trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
|
||||
@@ -192,17 +187,6 @@ pub fn extract_ibm_sign_key(certs: Vec<X509>) -> Result<(X509, Stack<X509>)> {
|
||||
Ok((ibm_z_sign_key, chain))
|
||||
}
|
||||
|
||||
/// for all certs load the first CRL specified into our store
|
||||
pub fn download_crls_into_store(store: &mut X509StoreBuilderRef, crts: &[X509]) -> Result<()> {
|
||||
for crt in crts {
|
||||
debug!("Download crls for {crt:?}");
|
||||
if let Some(crl) = download_first_crl_from_x509(crt)? {
|
||||
crl.iter().try_for_each(|c| store.add_crl(c))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Name Entry values of an IBM Z key signing cert
|
||||
//Asn1StringRef::as_slice aka ASN1_STRING_get0_data gives a string without \0 delimiter
|
||||
const IBM_Z_COMMON_NAME: &[u8; 43usize] = b"International Business Machines Corporation";
|
||||
@@ -319,14 +303,17 @@ pub fn x509_dist_points(cert: &X509Ref) -> Vec<String> {
|
||||
res
|
||||
}
|
||||
|
||||
const CRL_TIMEOUT_MAX: Duration = Duration::from_secs(3);
|
||||
|
||||
/// Searches for CRL Distribution points and downloads the CRL. Stops after the first successful
|
||||
/// download.
|
||||
///
|
||||
/// Error if sth bad(=unexpected) happens (not bad: crl not available at link, unexpected format)
|
||||
/// Other issues are mapped to Ok(None)
|
||||
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<X509Crl>>> {
|
||||
#[cfg(not(test))]
|
||||
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<openssl::x509::X509Crl>>> {
|
||||
use crate::misc::read_crls;
|
||||
use curl::easy::{Easy2, Handler, WriteError};
|
||||
use std::time::Duration;
|
||||
const CRL_TIMEOUT_MAX: Duration = Duration::from_secs(3);
|
||||
struct Buf(Vec<u8>);
|
||||
|
||||
impl Handler for Buf {
|
||||
@@ -420,8 +407,6 @@ pub fn stack_err_hlp<T: Stackable>(
|
||||
/// tests for some private functions
|
||||
mod test {
|
||||
|
||||
use openssl_extensions::x509_crl_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::test_utils::*;
|
||||
use std::time::{Duration, SystemTime};
|
||||
@@ -497,20 +482,4 @@ mod test {
|
||||
));
|
||||
assert!(super::get_ibm_z_sign_key(&[ibm_crt, no_sign_crt]).is_ok(),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn download_first_crl_from_x509() {
|
||||
let ibm_crt = load_gen_cert("ibm.crt");
|
||||
let inter_crl = load_gen_crl("inter_ca.crl");
|
||||
let _m_inter = super::super::test::mock_endpt("inter_ca.crl");
|
||||
|
||||
let crl_d = super::download_first_crl_from_x509(&ibm_crt)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(crl_d.len(), 1);
|
||||
assert!(x509_crl_eq(
|
||||
crl_d.first().unwrap().as_ref(),
|
||||
inter_crl.as_ref()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
+46
-90
@@ -5,32 +5,30 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use super::{helper, helper::*, *};
|
||||
use crate::{Error, HkdVerifyErrorType::*};
|
||||
use core::slice;
|
||||
use once_cell::sync::OnceCell;
|
||||
use openssl::stack::Stack;
|
||||
use std::sync::Mutex;
|
||||
use crate::{misc::read_crls, Error, HkdVerifyErrorType::*};
|
||||
use openssl::{stack::Stack, x509::X509Crl};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::test_utils::*;
|
||||
|
||||
pub fn mock_endpt(res: &str) -> mockito::Mock {
|
||||
static MOCK_SERVER: OnceCell<Mutex<mockito::Server>> = OnceCell::new();
|
||||
//mock function
|
||||
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<X509Crl>>> {
|
||||
fn mock_download<P: AsRef<Path>>(path: P) -> Result<Vec<X509Crl>> {
|
||||
read_crls(&std::fs::read(path)?)
|
||||
}
|
||||
|
||||
let res_path = get_cert_asset_path(res);
|
||||
|
||||
MOCK_SERVER
|
||||
.get_or_init(|| mockito::Server::new_with_port(1234).into())
|
||||
.lock()
|
||||
.expect("COULD NOT GET THE MOCK_SERVER LOCK")
|
||||
.mock("GET", format!("/crl/{res}").as_str())
|
||||
.with_header("content-type", "application/pkix-crl")
|
||||
.with_body_from_file(res_path)
|
||||
.create()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mockito_server_available() {
|
||||
let _mock = mock_endpt("ibm.crt");
|
||||
for dist_point in x509_dist_points(cert) {
|
||||
{
|
||||
let path = get_cert_asset_path(&dist_point);
|
||||
let crls = if let Ok(buf) = mock_download(&path) {
|
||||
buf
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
return Ok(Some(crls));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -44,22 +42,12 @@ fn store_setup() {
|
||||
|
||||
#[test]
|
||||
fn verify_chain_online() {
|
||||
let ibm_crt = load_gen_cert("ibm.crt");
|
||||
let inter_crt = load_gen_cert("inter_ca.crt");
|
||||
let ibm_crt = get_cert_asset_path_string("ibm.crt");
|
||||
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
|
||||
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
|
||||
|
||||
let mock_inter = mock_endpt("inter_ca.crl");
|
||||
|
||||
let mut store = helper::store_setup(&Some(root_crt), &[], &[]).unwrap();
|
||||
download_crls_into_store(&mut store, slice::from_ref(&ibm_crt)).unwrap();
|
||||
let store = store.build();
|
||||
|
||||
mock_inter.assert();
|
||||
|
||||
let mut sk = Stack::<X509>::new().unwrap();
|
||||
sk.push(inter_crt).unwrap();
|
||||
verify_chain(&store, &sk, &[ibm_crt.clone()]).unwrap();
|
||||
assert!(verify_chain(&store, &sk, &[ibm_crt]).is_ok());
|
||||
let ret = CertVerifier::new(&[ibm_crt, inter_crt], &[], &root_crt.into(), false);
|
||||
assert!(ret.is_ok(), "CertVerifier::new failed: {ret:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -79,33 +67,36 @@ fn verify_chain_offline() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_online() {
|
||||
fn dist_points() {
|
||||
let crt = load_gen_cert("ibm.crt");
|
||||
let res = x509_dist_points(&crt);
|
||||
let exp = vec!["inter_ca.crl"];
|
||||
assert_eq!(res, exp);
|
||||
}
|
||||
|
||||
fn verify(offline: bool, ibm_crt: &'static str, ibm_crl: &'static str) {
|
||||
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
|
||||
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
|
||||
let ibm_crt = get_cert_asset_path_string("ibm.crt");
|
||||
let inter_crl = get_cert_asset_path_string("inter_ca.crl");
|
||||
let ibm_crt = get_cert_asset_path_string(ibm_crt);
|
||||
let ibm_crl = get_cert_asset_path_string(ibm_crl);
|
||||
let hkd_revoked = load_gen_cert("host_rev.crt");
|
||||
let hkd_inv = load_gen_cert("host_invalid_signing_key.crt");
|
||||
let hkd_exp = load_gen_cert("host_crt_expired.crt");
|
||||
let hkd = load_gen_cert("host.crt");
|
||||
|
||||
let mock_inter = mock_endpt("inter_ca.crl");
|
||||
let mock_ibm = mock_endpt("ibm.crl");
|
||||
|
||||
let inter_crl = get_cert_asset_path_string("inter_ca.crl");
|
||||
let ibm_crl = get_cert_asset_path_string("ibm.crl");
|
||||
let crls = &[ibm_crl, inter_crl];
|
||||
let verifier = CertVerifier::new(
|
||||
&[ibm_crt, inter_crt],
|
||||
&[ibm_crl, inter_crl],
|
||||
if offline { crls } else { &[] },
|
||||
&Some(root_crt),
|
||||
false,
|
||||
offline,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mock_inter.assert();
|
||||
let res = verifier.verify(&hkd);
|
||||
assert!(res.is_ok(), "Verify failed: res: {res:?}");
|
||||
|
||||
verifier.verify(&hkd).unwrap();
|
||||
|
||||
mock_ibm.assert();
|
||||
assert!(matches!(
|
||||
verifier.verify(&hkd_revoked),
|
||||
Err(Error::HkdVerify(HdkRevoked))
|
||||
@@ -122,47 +113,12 @@ fn verify_online() {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_online() {
|
||||
verify(false, "ibm.crt", "ibm.crl")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_offline() {
|
||||
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
|
||||
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
|
||||
let inter_crl = get_cert_asset_path_string("inter_ca.crl");
|
||||
let ibm_crt = get_cert_asset_path_string("ibm.crt");
|
||||
let ibm_crl = get_cert_asset_path_string("ibm.crl");
|
||||
let hkd_revoked = load_gen_cert("host_rev.crt");
|
||||
let hkd_inv = load_gen_cert("host_invalid_signing_key.crt");
|
||||
let hkd_exp = load_gen_cert("host_crt_expired.crt");
|
||||
let hkd = load_gen_cert("host.crt");
|
||||
|
||||
let verifier = CertVerifier::new(
|
||||
&[ibm_crt, inter_crt],
|
||||
&[ibm_crl, inter_crl],
|
||||
&Some(root_crt),
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
verifier.verify(&hkd).unwrap();
|
||||
assert!(matches!(
|
||||
verifier.verify(&hkd_revoked),
|
||||
Err(Error::HkdVerify(HdkRevoked))
|
||||
));
|
||||
|
||||
assert!(matches!(
|
||||
verifier.verify(&hkd_inv),
|
||||
Err(Error::HkdVerify(IssuerMismatch))
|
||||
));
|
||||
|
||||
assert!(matches!(
|
||||
verifier.verify(&hkd_exp),
|
||||
Err(Error::HkdVerify(AfterValidity))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_points() {
|
||||
let crt = load_gen_cert("ibm.crt");
|
||||
let res = x509_dist_points(&crt);
|
||||
let exp = vec!["http://127.0.0.1:1234/crl/inter_ca.crl"];
|
||||
assert_eq!(res, exp);
|
||||
verify(true, "ibm.crt", "ibm.crl")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user