diff --git a/Cargo.lock b/Cargo.lock index 2f71f9c4..d36f5ef2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -507,6 +507,7 @@ dependencies = [ "syslog", "tempfile", "thiserror", + "time", "ureq", "x509-cert", ] diff --git a/pkcs11/Cargo.toml b/pkcs11/Cargo.toml index 50085a0e..c2910aba 100644 --- a/pkcs11/Cargo.toml +++ b/pkcs11/Cargo.toml @@ -46,6 +46,7 @@ ureq = { version = "2.10", default-features = false } hex-literal = "0.4.1" pkcs11 = "0.5.0" tempfile = "3.12.0" +time = "0.3.36" [features] pkcs11-full-tests = [] diff --git a/pkcs11/tests/basic.rs b/pkcs11/tests/basic.rs index 9d86a7d4..4b08c817 100644 --- a/pkcs11/tests/basic.rs +++ b/pkcs11/tests/basic.rs @@ -17,7 +17,9 @@ fn basic() { administrator: None, description: Some("Test slot".into()), instances: vec![InstanceConfig { - url: "https://localhost:8443/api/v1".into(), + url: option_env!("TEST_NETHSM_INSTANCE") + .unwrap_or("https://localhost:8443/api/v1") + .into(), danger_insecure_cert: true, sha256_fingerprints: Vec::new(), max_idle_connections: None, diff --git a/pkcs11/tests/tools/mod.rs b/pkcs11/tests/tools/mod.rs index 9407623d..8ae04bdd 100644 --- a/pkcs11/tests/tools/mod.rs +++ b/pkcs11/tests/tools/mod.rs @@ -1,17 +1,198 @@ -use std::env::set_var; -use std::io::BufWriter; +use std::io::{BufWriter, Read}; +use std::process::{Child, Stdio}; +use std::sync::Arc; +use std::thread::sleep; +use std::time::Duration; +use std::{env::set_var, process::Command}; pub use config_file::P11Config; +use nethsm_sdk_rs::{ + apis::{ + configuration::Configuration, + default_api::{ + provision_post, system_factory_reset_post, users_post, SystemFactoryResetPostError, + }, + ResponseContent, + }, + models::{ProvisionRequestData, UserPostData, UserRole}, +}; use pkcs11::Ctx; +use rustls::{ + client::danger::ServerCertVerifier, + crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider}, +}; use tempfile::NamedTempFile; +use time::format_description; +use ureq::AgentBuilder; + +pub const TEST_NETHSM_INSTANCE: &str = match option_env!("TEST_NETHSM_INSTANCE") { + Some(v) => v, + None => "https://localhost:8443/api/v1", +}; + +#[derive(Debug)] +struct DangerIgnoreVerifier; + +impl ServerCertVerifier for DangerIgnoreVerifier { + fn verify_server_cert( + &self, + _end_entity: &rustls::pki_types::CertificateDer<'_>, + _intermediates: &[rustls::pki_types::CertificateDer<'_>], + _server_name: &rustls::pki_types::ServerName<'_>, + _ocsp_response: &[u8], + _now: rustls::pki_types::UnixTime, + ) -> Result { + Ok(rustls::client::danger::ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &rustls::pki_types::CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + let default_provider = CryptoProvider::get_default().unwrap(); + verify_tls12_signature( + message, + cert, + dss, + &default_provider.signature_verification_algorithms, + ) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &rustls::pki_types::CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + let default_provider = CryptoProvider::get_default().unwrap(); + verify_tls13_signature( + message, + cert, + dss, + &default_provider.signature_verification_algorithms, + ) + } + + fn supported_verify_schemes(&self) -> Vec { + let default_provider = CryptoProvider::get_default().unwrap(); + + default_provider + .signature_verification_algorithms + .supported_schemes() + } +} + +fn tls_conf() -> rustls::ClientConfig { + rustls::crypto::ring::default_provider() + .install_default() + .ok(); + rustls::ClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(Arc::new(DangerIgnoreVerifier)) + .with_no_client_auth() +} + +struct Dropper(Child); + +impl Drop for Dropper { + fn drop(&mut self) { + Command::new("kill") + .args([self.0.id().to_string()]) + .spawn() + .unwrap() + .wait() + .unwrap(); + self.0.wait().unwrap(); + let mut buf = String::new(); + self.0 + .stdout + .take() + .unwrap() + .read_to_string(&mut buf) + .unwrap(); + buf.push('\n'); + self.0 + .stderr + .take() + .unwrap() + .read_to_string(&mut buf) + .unwrap(); + println!("{buf}"); + } +} pub fn run_tests(config: P11Config, f: impl FnOnce(&mut Ctx)) { + let _dropper = Dropper( + Command::new("podman") + .args([ + "run", + "--rm", + "-ti", + "-p8443:8443", + "-p8080:8080", + "docker.io/nitrokey/nethsm:testing", + ]) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap(), + ); + + let client = AgentBuilder::new().tls_config(Arc::new(tls_conf())).build(); + + let sdk_config = Configuration { + client, + base_path: TEST_NETHSM_INSTANCE.into(), + basic_auth: Some(("admin".into(), Some("Administrator".into()))), + ..Default::default() + }; + + sleep(Duration::from_secs(1)); + + // match system_factory_reset_post(&sdk_config) { + // Ok(_) => {} + // Err(nethsm_sdk_rs::apis::Error::ResponseError(ResponseContent { + // entity: SystemFactoryResetPostError::Status412(), + // .. + // })) => {} + // Err(nethsm_sdk_rs::apis::Error::Ureq(ureq::Error::Status(412, _))) => {} + // Err(e) => panic!("{e}"), + // }; + provision_post( + &sdk_config, + ProvisionRequestData { + unlock_passphrase: "1234567890".into(), + admin_passphrase: "Administrator".into(), + system_time: time::OffsetDateTime::now_utc() + .format( + &format_description::parse("[year]-[month]-[day]T[hour]:[minute]:[second]Z") + .unwrap(), + ) + .unwrap(), + }, + ) + .unwrap(); + users_post( + &sdk_config, + UserPostData { + real_name: "Operator".into(), + role: UserRole::Operator, + passphrase: "opPassphrase".into(), + }, + ) + .unwrap(); + let mut tmpfile: NamedTempFile = NamedTempFile::new().unwrap(); serde_yaml::to_writer(BufWriter::new(tmpfile.as_file_mut()), &config).unwrap(); let path = tmpfile.path(); set_var(config_file::ENV_VAR_CONFIG_FILE, path); + dbg!("loading"); let mut ctx = Ctx::new_and_initialize("../target/release/libnethsm_pkcs11.so").unwrap(); f(&mut ctx); + ctx.close_all_sessions(0).unwrap(); }