diff --git a/src/config.rs b/src/config.rs index 33f7002c..db44b7d8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,16 +3,23 @@ use std::{ net::SocketAddr, os::unix::fs::PermissionsExt, path::{Path, PathBuf}, + sync::Arc, + time::Duration, }; -use rustls::pki_types::ServerName; +use rustls::{ + pki_types::{pem::PemObject, ServerName}, + version::TLS13, +}; +use rustls_platform_verifier::Verifier; use serde::Deserialize; +use tokio_rustls::{TlsAcceptor, TlsConnector}; use tracing::{info, warn}; -#[derive(Deserialize, Debug)] +#[derive(Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct Config { - pub nts_pool_ke_server: NtsPoolKeConfig, + pub server: NtsPoolKeConfig, #[serde(default)] pub observability: ObservabilityConfig, } @@ -83,20 +90,112 @@ pub struct ObservabilityConfig { #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] -pub struct NtsPoolKeConfig { - pub certificate_authority_path: PathBuf, - pub certificate_chain_path: PathBuf, - pub private_key_path: PathBuf, +struct BareNtsPoolKeConfig { + /// Additional CAs used to validate the certificates of upstream servers + #[serde(default)] + upstream_cas: Option, + /// Certificate chain for the key used by the server to identify itself during tls sessions + certificate_chain: PathBuf, + /// Private key used by the server to identify itself during tls sessions + private_key: PathBuf, #[serde(default = "default_nts_ke_timeout")] - pub key_exchange_timeout_ms: u64, - pub listen: SocketAddr, - pub key_exchange_servers: Vec, + /// Timeout + key_exchange_timeout: u64, + /// Address for the server to listen on. + listen: SocketAddr, + /// Which upstream servers to use. + key_exchange_servers: Box<[KeyExchangeServer]>, } fn default_nts_ke_timeout() -> u64 { 1000 } +#[derive(Clone)] +pub struct NtsPoolKeConfig { + pub server_tls: TlsAcceptor, + pub upstream_tls: TlsConnector, + pub listen: SocketAddr, + pub key_exchange_servers: Box<[KeyExchangeServer]>, + pub key_exchange_timeout: Duration, +} + +fn load_certificates( + path: impl AsRef, +) -> Result>, rustls::pki_types::pem::Error> { + rustls::pki_types::CertificateDer::pem_file_iter(path)?.collect() +} + +impl<'de> Deserialize<'de> for NtsPoolKeConfig { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let bare = BareNtsPoolKeConfig::deserialize(deserializer)?; + + let upstream_cas = bare + .upstream_cas + .map(|path| { + load_certificates(&path).map_err(|e| { + serde::de::Error::custom(format!( + "error reading additional upstream ca certificates from `{:?}`: {:?}", + path, e + )) + }) + }) + .transpose()?; + + let certificate_chain = load_certificates(&bare.certificate_chain).map_err(|e| { + serde::de::Error::custom(format!( + "error reading server's certificate chain from `{:?}`: {:?}", + bare.certificate_chain, e + )) + })?; + + let private_key = rustls::pki_types::PrivateKeyDer::from_pem_file(&bare.private_key) + .map_err(|e| { + serde::de::Error::custom(format!( + "error reading server's private key from `{:?}`: {:?}", + bare.private_key, e + )) + })?; + + let mut server_config = rustls::ServerConfig::builder_with_protocol_versions(&[&TLS13]) + .with_no_client_auth() + .with_single_cert(certificate_chain.clone(), private_key.clone_key()) + .map_err(serde::de::Error::custom)?; + server_config.alpn_protocols.clear(); + server_config.alpn_protocols.push(b"ntske/1".to_vec()); + + let server_tls = TlsAcceptor::from(Arc::new(server_config)); + + let upstream_config_builder = + rustls::ClientConfig::builder_with_protocol_versions(&[&TLS13]); + let provider = upstream_config_builder.crypto_provider().clone(); + let verifier = match upstream_cas { + Some(upstream_cas) => Verifier::new_with_extra_roots(upstream_cas.iter().cloned()) + .map_err(serde::de::Error::custom)? + .with_provider(provider), + None => Verifier::new(), + }; + + let upstream_config = upstream_config_builder + .dangerous() + .with_custom_certificate_verifier(Arc::new(verifier)) + .with_client_auth_cert(certificate_chain, private_key) + .map_err(serde::de::Error::custom)?; + let upstream_tls = TlsConnector::from(Arc::new(upstream_config)); + + Ok(NtsPoolKeConfig { + server_tls, + upstream_tls, + listen: bare.listen, + key_exchange_servers: bare.key_exchange_servers, + key_exchange_timeout: std::time::Duration::from_millis(bare.key_exchange_timeout), + }) + } +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct KeyExchangeServer { pub domain: String, @@ -135,17 +234,18 @@ impl<'de> Deserialize<'de> for KeyExchangeServer { #[cfg(test)] mod tests { + use std::ops::Deref; + use super::*; #[test] - fn test_deserialize_nts_pool_ke() { - let test: Config = toml::from_str( + fn test_deserialize_bare_config() { + let test: BareNtsPoolKeConfig = toml::from_str( r#" - [nts-pool-ke-server] listen = "0.0.0.0:4460" - certificate-authority-path = "/foo/bar/ca.pem" - certificate-chain-path = "/foo/bar/baz.pem" - private-key-path = "spam.der" + upstream-cas = "/foo/bar/ca.pem" + certificate-chain = "/foo/bar/baz.pem" + private-key = "spam.der" key-exchange-servers = [ { domain = "foo.bar", port = 1234 }, { domain = "bar.foo", port = 4321 }, @@ -155,23 +255,59 @@ mod tests { .unwrap(); let ca = PathBuf::from("/foo/bar/ca.pem"); - assert_eq!(test.nts_pool_ke_server.certificate_authority_path, ca); + assert_eq!(test.upstream_cas, Some(ca)); let chain = PathBuf::from("/foo/bar/baz.pem"); - assert_eq!(test.nts_pool_ke_server.certificate_chain_path, chain); + assert_eq!(test.certificate_chain, chain); let private_key = PathBuf::from("spam.der"); - assert_eq!(test.nts_pool_ke_server.private_key_path, private_key); + assert_eq!(test.private_key, private_key); + + assert_eq!(test.key_exchange_timeout, 1000,); + assert_eq!(test.listen, "0.0.0.0:4460".parse().unwrap(),); - assert_eq!(test.nts_pool_ke_server.key_exchange_timeout_ms, 1000,); assert_eq!( - test.nts_pool_ke_server.listen, - "0.0.0.0:4460".parse().unwrap(), + test.key_exchange_servers.deref(), + [ + KeyExchangeServer { + domain: String::from("foo.bar"), + server_name: ServerName::try_from("foo.bar").unwrap(), + port: 1234 + }, + KeyExchangeServer { + domain: String::from("bar.foo"), + server_name: ServerName::try_from("bar.foo").unwrap(), + port: 4321 + }, + ] + .as_slice() ); + } + + #[test] + fn test_deserialize_config() { + let test: Config = toml::from_str( + r#" + [server] + listen = "0.0.0.0:4460" + key-exchange-timeout = 500 + upstream-cas = "testdata/testca.pem" + certificate-chain = "testdata/end.fullchain.pem" + private-key = "testdata/end.key" + key-exchange-servers = [ + { domain = "foo.bar", port = 1234 }, + { domain = "bar.foo", port = 4321 }, + ] + "#, + ) + .unwrap(); + + assert_eq!(test.server.key_exchange_timeout, Duration::from_millis(500)); + assert_eq!(test.server.listen, "0.0.0.0:4460".parse().unwrap(),); assert_eq!( - test.nts_pool_ke_server.key_exchange_servers, - vec![ + test.server.key_exchange_servers.deref(), + [ KeyExchangeServer { domain: String::from("foo.bar"), server_name: ServerName::try_from("foo.bar").unwrap(), @@ -183,6 +319,7 @@ mod tests { port: 4321 }, ] + .as_slice() ); } } diff --git a/src/lib.rs b/src/lib.rs index 95936268..26b16032 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,7 +99,7 @@ async fn run(options: NtsPoolKeOptions) -> Result<(), Box // tracing setup to ensure logging is fully configured. config.check(); - let result = run_nts_pool_ke(config.nts_pool_ke_server).await; + let result = run_nts_pool_ke(config.server).await; match result { Ok(v) => Ok(v), diff --git a/src/pool_ke.rs b/src/pool_ke.rs index ec1436c2..6cd20e3e 100644 --- a/src/pool_ke.rs +++ b/src/pool_ke.rs @@ -3,10 +3,8 @@ use std::{ sync::Arc, }; -use rustls::{pki_types::pem::PemObject, version::TLS13, ServerConnection}; -use rustls_platform_verifier::Verifier; +use rustls::ServerConnection; use tokio::{io::AsyncWriteExt, net::TcpListener}; -use tokio_rustls::{TlsAcceptor, TlsConnector}; use tracing::{debug, info}; use crate::{ @@ -63,95 +61,11 @@ pub async fn run_nts_pool_ke(nts_pool_ke_config: NtsPoolKeConfig) -> std::io::Re struct NtsPoolKe { config: NtsPoolKeConfig, - upstream_tls: TlsConnector, - server_tls: TlsAcceptor, } impl NtsPoolKe { fn new(config: NtsPoolKeConfig) -> std::io::Result { - let certificate_authority_file = std::fs::File::open(&config.certificate_authority_path) - .map_err(|e| { - std::io::Error::other(format!( - "error reading certificate_authority_path at `{:?}`: {:?}", - config.certificate_authority_path, e - )) - })?; - - let certificate_chain_file = - std::fs::File::open(&config.certificate_chain_path).map_err(|e| { - std::io::Error::other(format!( - "error reading certificate_chain_path at `{:?}`: {:?}", - config.certificate_chain_path, e - )) - })?; - - let private_key_file = std::fs::File::open(&config.private_key_path).map_err(|e| { - std::io::Error::other(format!( - "error reading key_der_path at `{:?}`: {:?}", - config.private_key_path, e - )) - })?; - - let certificate_authority: Arc<[rustls::pki_types::CertificateDer]> = - rustls::pki_types::CertificateDer::pem_reader_iter(&mut std::io::BufReader::new( - certificate_authority_file, - )) - .map(|item| { - item.map_err(|err| match err { - rustls::pki_types::pem::Error::Io(error) => error, - _ => std::io::Error::new(std::io::ErrorKind::InvalidInput, err.to_string()), - }) - }) - .collect::>>()?; - - let certificate_chain: Vec = - rustls::pki_types::CertificateDer::pem_reader_iter(&mut std::io::BufReader::new( - certificate_chain_file, - )) - .map(|item| { - item.map_err(|err| match err { - rustls::pki_types::pem::Error::Io(error) => error, - _ => std::io::Error::new(std::io::ErrorKind::InvalidInput, err.to_string()), - }) - }) - .collect::>>()?; - - let private_key = rustls::pki_types::PrivateKeyDer::from_pem_reader( - &mut std::io::BufReader::new(private_key_file), - ) - .map_err(|err| match err { - rustls::pki_types::pem::Error::Io(error) => error, - _ => std::io::Error::new(std::io::ErrorKind::InvalidInput, err.to_string()), - })?; - - let mut server_config = rustls::ServerConfig::builder_with_protocol_versions(&[&TLS13]) - .with_no_client_auth() - .with_single_cert(certificate_chain.clone(), private_key.clone_key()) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?; - server_config.alpn_protocols.clear(); - server_config.alpn_protocols.push(b"ntske/1".to_vec()); - - let server_tls = TlsAcceptor::from(Arc::new(server_config)); - - let upstream_config_builder = - rustls::ClientConfig::builder_with_protocol_versions(&[&TLS13]); - let provider = upstream_config_builder.crypto_provider().clone(); - let verifier = Verifier::new_with_extra_roots(certificate_authority.iter().cloned()) - .map_err(std::io::Error::other)? - .with_provider(provider); - - let upstream_config = upstream_config_builder - .dangerous() - .with_custom_certificate_verifier(Arc::new(verifier)) - .with_client_auth_cert(certificate_chain, private_key) - .map_err(std::io::Error::other)?; - let upstream_tls = TlsConnector::from(Arc::new(upstream_config)); - - Ok(NtsPoolKe { - config, - upstream_tls, - server_tls, - }) + Ok(NtsPoolKe { config }) } async fn serve(self: Arc) -> std::io::Result<()> { @@ -164,9 +78,12 @@ impl NtsPoolKe { let self_clone = self.clone(); tokio::spawn(async move { - let timeout = - std::time::Duration::from_millis(self_clone.config.key_exchange_timeout_ms); - match tokio::time::timeout(timeout, self_clone.handle_client(client_stream)).await { + match tokio::time::timeout( + self_clone.config.key_exchange_timeout, + self_clone.handle_client(client_stream), + ) + .await + { Err(_) => ::tracing::debug!(?source_address, "NTS Pool KE timed out"), Ok(Err(err)) => ::tracing::debug!(?err, ?source_address, "NTS Pool KE failed"), Ok(Ok(())) => ::tracing::debug!(?source_address, "NTS Pool KE completed"), @@ -177,7 +94,7 @@ impl NtsPoolKe { async fn handle_client(&self, client_stream: tokio::net::TcpStream) -> Result<(), PoolError> { // handle the initial client to pool - let mut client_stream = self.server_tls.accept(client_stream).await?; + let mut client_stream = self.config.server_tls.accept(client_stream).await?; let client_request = match ClientRequest::parse(&mut client_stream).await { Ok(client_request) => client_request, @@ -322,6 +239,7 @@ impl NtsPoolKe { let server_stream = tokio::net::TcpStream::connect((server.domain.as_str(), server.port)).await?; let mut server_stream = self + .config .upstream_tls .connect(server.server_name.clone(), server_stream) .await?; @@ -365,6 +283,7 @@ impl NtsPoolKe { let server_stream = tokio::net::TcpStream::connect((server.domain.as_str(), server.port)).await?; let mut server_stream = self + .config .upstream_tls .connect(server.server_name.clone(), server_stream) .await?; diff --git a/testdata/end.fullchain.pem b/testdata/end.fullchain.pem new file mode 100644 index 00000000..85f04636 --- /dev/null +++ b/testdata/end.fullchain.pem @@ -0,0 +1,44 @@ +-----BEGIN CERTIFICATE----- +MIIDsTCCApmgAwIBAgIUaNuir1ru01VEHIHC8baug66nkbQwDQYJKoZIhvcNAQEL +BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAeFw0y +NTAyMjcwOTA3MTJaFw0yNjAyMjcwOTA3MTJaMEUxCzAJBgNVBAYTAkFVMRMwEQYD +VQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM +dGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDd0nhS+SWqtQMyIMuX +/WMopeUH6u+WljlUEXpxZQKa3KL0+3r4byo51D8R6OF05zG3ANw4NCSMKfRBpK/+ +wb/QvVFi4Ib8wmrNJI019UE/gzbnDfg5QaMvztusAHZF2wkELRjgX/DdVBWXkQ1W +jA9052XyPZs+zTbVg6Am6n3GOmKoCI2n0TIY9sKG+ZCJFfE+TzQU0z7r9OnvnT0Z +BZ4poOgG8GbxTCr3dRfM+tLh8MLLMOZ3CKunGaMHD4zdeDm4l7fYZ6/jXVoZrbio +2/uj9+KjhhKi+xTIBc8zug91piotN0uCuxdawgt0EtjaO4czQoLl3D/WNNSez4rl +HLeVAgMBAAGjgYYwgYMwHwYDVR0jBBgwFoAUd1WulbCt/dtDVY+7a5EIrbXIbaUw +CQYDVR0TBAIwADALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwFAYD +VR0RBA0wC4IJbG9jYWxob3N0MB0GA1UdDgQWBBT18h+AQlYckl0KMVOGK14oPlsM +NDANBgkqhkiG9w0BAQsFAAOCAQEAm6ZnJcT3IfF+1Y8P0NjkqG/U5CyPmEstwyFX +zxnRP9ILmtQ2l+9V10KQ+STNKqyQWsfJ/+F71nKjOBzkS8cHDidVDZ1Y/3JoLByf +sIbdA6XQVMLCNKDgLCJ33h8r0yDiucu1RRKQUIdMyLHnhNbPQtMpdFq8B2CjOi36 +tD36Ah/nAzVDCxUg2wvcc/aLqmMyZVmFqjjDtOqLlPQIJ4iiUT2MYw7avqVWq8br +t0+3ezAGkMuTqjsBiTM/ov6l7OS12hFL/u+kA4lG38UuCkLoDjjG5QEu9d4q347l +Y3C1v7K1YDXkXmX28sRQgAqzKVfTIRcbcvKgu4jx4EIhSjaNug== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDkTCCAnmgAwIBAgIUSJ4RLbU532cpXBrIPM0dgLjFoRowDQYJKoZIhvcNAQEL +BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0y +MzAxMjAwOTQzMzdaGA80NzYwMTIxNzA5NDMzN1owVzELMAkGA1UEBhMCQVUxEzAR +BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 +IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALzqkvECUcCFlg4cldjWKD1/X2e+FPrMBesmUCDExAtGYIjJy2YFovFL +20eNFa4K3QK61MfsmnbhC97Q3Nrm2tFiDXdM1XjnnbGk/GKtTH/cS/v5FQt+8kbj +YPKkxfwo02Nhgf8r0Ttsg439tuT+qpw3CymVzEZDllhYFL0EDq5JHAx9Sz5RiXm4 +1+4E0ahWpWbTagiG/Ldgk/sXCTZvxsCw7gbULKSVEbaN+cW+pXqkD3YSvrnYCPtk +/8OK7llBCtDC9puDIntrd5z6tIxCbj3jnfb9Ek/Pb/AmK04NF5OPw+eUgEwteSde +lNInFgNnlEPikNrkDAmBydLuEX7yCO8CAwEAAaNTMFEwHQYDVR0OBBYEFHdVrpWw +rf3bQ1WPu2uRCK21yG2lMB8GA1UdIwQYMBaAFHdVrpWwrf3bQ1WPu2uRCK21yG2l +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFHWNTDdy9BbCoX5 +RRvP0S4V0g8HcaWohYuI7uNsDwW/xvOsJ7u+1rjv/Hx3lOCtnEHCAS5peJQenf6Y +uQSXbt2BVX7U01TzGKC9y47yxgovpdKJDiJodWSGs6sZP/4x3M5AbGmhmdfSBFAZ +/fchAzZPWd5FdYBEaT5J1nnXDCe3G5Aa43zvZzN8i/YCJ376yB7Vt6qUW8L70o9X +++snpnom2bvIKwkO4Z9jBY6njrpYjE212N1OY+eYRLknOdJlFuy6kGO2ipEoPKt/ ++vur95a6fTo8WiU2kYQc649XiPNW53v1epWNFJCRoOFietIVrKANWuqQB7xVYuIG +Yo0A3Sw= +-----END CERTIFICATE----- diff --git a/testdata/end.key b/testdata/end.key new file mode 100644 index 00000000..fa93b1da --- /dev/null +++ b/testdata/end.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDd0nhS+SWqtQMy +IMuX/WMopeUH6u+WljlUEXpxZQKa3KL0+3r4byo51D8R6OF05zG3ANw4NCSMKfRB +pK/+wb/QvVFi4Ib8wmrNJI019UE/gzbnDfg5QaMvztusAHZF2wkELRjgX/DdVBWX +kQ1WjA9052XyPZs+zTbVg6Am6n3GOmKoCI2n0TIY9sKG+ZCJFfE+TzQU0z7r9Onv +nT0ZBZ4poOgG8GbxTCr3dRfM+tLh8MLLMOZ3CKunGaMHD4zdeDm4l7fYZ6/jXVoZ +rbio2/uj9+KjhhKi+xTIBc8zug91piotN0uCuxdawgt0EtjaO4czQoLl3D/WNNSe +z4rlHLeVAgMBAAECggEAQ3Y8sONkEMA/ahHuSVm/PAAEIT3SwuYKJmawaecx/R4o +E0CeXAsW+QJzcgN0+gRMKt+AmjlFejlSN1qaSezr5NSG+X7Wnu2T5LL+nU/rGaFS +479sZCFxu1r6lRuI3OLqIZKDk82p5+4oKPHs8ArlsoSjjSIuYlGwIQyIev1q5guP +sfzi2cYAHc6rySDBCtFmP9yIxwdhkYRIrDqGWGbtrGIsguyuOUjQHbkidX5FaWjs +wj4ApcrYsFQcS/aeEWKqn0wjYTbm+MXXjfao5mAe+1jrPYXyvYs0GpkC3pt+rjS9 +XO4pohuFEnAvrxZ9JX0DEsnvUoi5C38TB2A/LRboewKBgQD0Z2ZTvTwk+fUb9IRD +MRNCWuB8+eiHNZwTRx4v9ZHJQ9blfXirDV0thzV2loYvW1uI91iL4SIWLH1d/O5Z +WtwrrTBtzKjiQaeIqopzJH/a1enm8vSTDuazb/n2nmfe49ZBkfgdCnBEEGu4HuZZ +viPAdLTWLjimsiXOrBtzJBCFXwKBgQDoWMkoj+Lkx9ZGe3x5KqPMHI8UkEolsLXd +dyC8qLLtQJKIGbJj+uk2I0cYnyTfVNi+nOu+Rt2EK187wkMid1encnxqUyDsKoBJ +XGiSs9mqyc32DvGOH9X2heQ0FrnbNlaYozdW5jjXafFlV8dnpoX7wQnjMg329qDB +2zVSainTiwKBgBNSPU+vbRrLO+pa2T3qmkgroQWgSBawUUdg3u0Rr9XGbC22TpzP +MKeRwdM/MRp7UXAxhamBQc2Y9MxCW6Fqwm8dgO+dN1izsgfm240gvI7TTGt6l4Us +r2ZOGue5PCLtxhlm7cN1+MwYtDtZDgLYOkFTuJwaCVZ8TOraxkzC9B9nAoGATPbk +I4COKzSbIRvUnppmSb2IE8q8FQIVLDhC6tuC8Z47K8Q/WGkMCXfkHB7TavtDFNkM +Kip1REvNrxDphig8K+Z7mgjRVgm6FxL6POZAixdwFzrZ/zdCe/fcIPkKNbgpNUST +l0CJwamBYg2Sqx35Mey+5rh08cK+e5iucA9krYMCgYBe+4fUD9GC+GUjnsyzkjDT +oNKbsFMcYrjLld9nQdeX2oViWudqU7cGlk3mwpWyX81UkEc1LRcnE3/FSdd4Pj1t +xMUjq+fMXF2Au4w1NTZ4Exp6Vk8mz9gmsNuFfLKOKnr8x/MT89kYr7+959WlB0jE +0ayKuXuHxFpY1rDFSJabaw== +-----END PRIVATE KEY----- diff --git a/testdata/end.pem b/testdata/end.pem new file mode 100644 index 00000000..7bc7641c --- /dev/null +++ b/testdata/end.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDsTCCApmgAwIBAgIUaNuir1ru01VEHIHC8baug66nkbQwDQYJKoZIhvcNAQEL +BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAeFw0y +NTAyMjcwOTA3MTJaFw0yNjAyMjcwOTA3MTJaMEUxCzAJBgNVBAYTAkFVMRMwEQYD +VQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM +dGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDd0nhS+SWqtQMyIMuX +/WMopeUH6u+WljlUEXpxZQKa3KL0+3r4byo51D8R6OF05zG3ANw4NCSMKfRBpK/+ +wb/QvVFi4Ib8wmrNJI019UE/gzbnDfg5QaMvztusAHZF2wkELRjgX/DdVBWXkQ1W +jA9052XyPZs+zTbVg6Am6n3GOmKoCI2n0TIY9sKG+ZCJFfE+TzQU0z7r9OnvnT0Z +BZ4poOgG8GbxTCr3dRfM+tLh8MLLMOZ3CKunGaMHD4zdeDm4l7fYZ6/jXVoZrbio +2/uj9+KjhhKi+xTIBc8zug91piotN0uCuxdawgt0EtjaO4czQoLl3D/WNNSez4rl +HLeVAgMBAAGjgYYwgYMwHwYDVR0jBBgwFoAUd1WulbCt/dtDVY+7a5EIrbXIbaUw +CQYDVR0TBAIwADALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwFAYD +VR0RBA0wC4IJbG9jYWxob3N0MB0GA1UdDgQWBBT18h+AQlYckl0KMVOGK14oPlsM +NDANBgkqhkiG9w0BAQsFAAOCAQEAm6ZnJcT3IfF+1Y8P0NjkqG/U5CyPmEstwyFX +zxnRP9ILmtQ2l+9V10KQ+STNKqyQWsfJ/+F71nKjOBzkS8cHDidVDZ1Y/3JoLByf +sIbdA6XQVMLCNKDgLCJ33h8r0yDiucu1RRKQUIdMyLHnhNbPQtMpdFq8B2CjOi36 +tD36Ah/nAzVDCxUg2wvcc/aLqmMyZVmFqjjDtOqLlPQIJ4iiUT2MYw7avqVWq8br +t0+3ezAGkMuTqjsBiTM/ov6l7OS12hFL/u+kA4lG38UuCkLoDjjG5QEu9d4q347l +Y3C1v7K1YDXkXmX28sRQgAqzKVfTIRcbcvKgu4jx4EIhSjaNug== +-----END CERTIFICATE----- diff --git a/testdata/testca.key b/testdata/testca.key new file mode 100644 index 00000000..4dd5aea2 --- /dev/null +++ b/testdata/testca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC86pLxAlHAhZYO +HJXY1ig9f19nvhT6zAXrJlAgxMQLRmCIyctmBaLxS9tHjRWuCt0CutTH7Jp24Qve +0Nza5trRYg13TNV4552xpPxirUx/3Ev7+RULfvJG42DypMX8KNNjYYH/K9E7bION +/bbk/qqcNwsplcxGQ5ZYWBS9BA6uSRwMfUs+UYl5uNfuBNGoVqVm02oIhvy3YJP7 +Fwk2b8bAsO4G1CyklRG2jfnFvqV6pA92Er652Aj7ZP/Diu5ZQQrQwvabgyJ7a3ec ++rSMQm494532/RJPz2/wJitODReTj8PnlIBMLXknXpTSJxYDZ5RD4pDa5AwJgcnS +7hF+8gjvAgMBAAECggEAAZrFvgbSoSHLqN7lSP7ZLtfkTwpuA7RZeIUQNQmgGW0P +3BFQZA0v8kaImiM8gdb2TC7dKJSGBKImQTW4CXmejxSX7l1H7bsYWHBgHKsYifQw +q95QccSuZHJ0zYIGtcMA8e2Zk4Qa/GVzbT7+0QMb1IKuh+mRrbN9hLWsXJTTuYvf +GppDVqMdDPy5NibudiZPKdpnMyDCJ/Wxl1+1PX18anifzBHw/G8ZPnLU3OKDqL2T +OtEivvk9ZFDiRKKEsHksr+aLcUGhXFswk0zEQJwMj6rFwcDEExTQkMar+xaxshpf +qo6AC88SDT9qEffSHHGJzTi73NIGgLNPO1aON4/pwQKBgQDUPo+ZJymo9IunaXWi +HywqLLVZJSvqo2x9SrlqqYe3Yz0bROGBoHSMaGQzxiDApeOabdyg24wrU1P24jrC +jPt94TWdu8bZKAkZAGOUPvdSGA/5yQkxVSMUK5zZwQxyLWfb77+B+WSvzhxI17Bt +bX6od5pcdFSC5OczJ64DjLeHlQKBgQDj3NjsbLnxFu88A121kPD4AdpoMAtgrA5R +AWwc7mWzKvL1RZlZCn861QMaRoUThQW4+dxTdoOoL68PXK3L8zuU3imKOBOe33lh +j7B+M0gjdWnkcTag5q56qk1VA4YZ0R30LhUw44JxFHXhtuTR00CattI1pOQr6OdK +By3kj4NdcwKBgQChOxko1eg+0e6Y8XMMAjQxoZ7tpmAzMYxDrZUm4rwXYsrTwUKx +jyuaUd70uai90AcTlCuLAtz7OKTLIlZS3nhZytBJD5Fh+5jVpkb/IcoNUfwo20Ah +erRYKT1Q6ebDgZypJfpMCSEksCUqbLc4mXojDiBz5WchvDOp15XIWog89QKBgE3c +Vxtig58IETNWixzRrCVyrKjRUfH0mOfBLqosJAA2+tIouB+e4J6/ztGZqztiRvRQ +HKNAafh8YrtDFfgM4x0ZVORwCPROtHFL4ikdaNcE9ewja2FLse8kZkxYaehEdpHL +dV5BP39YWHeKQWIZZ4f2VJoUAAupB+9ZyKrDB0ZVAoGBALJ0KzHlAizbZyXRtfk+ +ThnegTgjbTd6drMTsRlyHdL1Zet0tdx2nhn2keMQVSDep5KEwTvm+Wy41s9EmzZx +RyehNaq9hMljLGR6mtr4Em5RtxtkPTwoJcOttHXQXnTgplDbePb8zQ8N084fScek +0dIjCbVBt5X7akmgHaaizIDl +-----END PRIVATE KEY----- diff --git a/testdata/testca.pem b/testdata/testca.pem new file mode 100644 index 00000000..9d94020b --- /dev/null +++ b/testdata/testca.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkTCCAnmgAwIBAgIUSJ4RLbU532cpXBrIPM0dgLjFoRowDQYJKoZIhvcNAQEL +BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0y +MzAxMjAwOTQzMzdaGA80NzYwMTIxNzA5NDMzN1owVzELMAkGA1UEBhMCQVUxEzAR +BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 +IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALzqkvECUcCFlg4cldjWKD1/X2e+FPrMBesmUCDExAtGYIjJy2YFovFL +20eNFa4K3QK61MfsmnbhC97Q3Nrm2tFiDXdM1XjnnbGk/GKtTH/cS/v5FQt+8kbj +YPKkxfwo02Nhgf8r0Ttsg439tuT+qpw3CymVzEZDllhYFL0EDq5JHAx9Sz5RiXm4 +1+4E0ahWpWbTagiG/Ldgk/sXCTZvxsCw7gbULKSVEbaN+cW+pXqkD3YSvrnYCPtk +/8OK7llBCtDC9puDIntrd5z6tIxCbj3jnfb9Ek/Pb/AmK04NF5OPw+eUgEwteSde +lNInFgNnlEPikNrkDAmBydLuEX7yCO8CAwEAAaNTMFEwHQYDVR0OBBYEFHdVrpWw +rf3bQ1WPu2uRCK21yG2lMB8GA1UdIwQYMBaAFHdVrpWwrf3bQ1WPu2uRCK21yG2l +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFHWNTDdy9BbCoX5 +RRvP0S4V0g8HcaWohYuI7uNsDwW/xvOsJ7u+1rjv/Hx3lOCtnEHCAS5peJQenf6Y +uQSXbt2BVX7U01TzGKC9y47yxgovpdKJDiJodWSGs6sZP/4x3M5AbGmhmdfSBFAZ +/fchAzZPWd5FdYBEaT5J1nnXDCe3G5Aa43zvZzN8i/YCJ376yB7Vt6qUW8L70o9X +++snpnom2bvIKwkO4Z9jBY6njrpYjE212N1OY+eYRLknOdJlFuy6kGO2ipEoPKt/ ++vur95a6fTo8WiU2kYQc649XiPNW53v1epWNFJCRoOFietIVrKANWuqQB7xVYuIG +Yo0A3Sw= +-----END CERTIFICATE-----