diff --git a/.gitignore b/.gitignore index 5ee368e..4bb447b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,11 @@ Cargo.lock **/*.iml .idea +.vscode .*.swp + +flake.nix +flake.lock +.envrc +.direnv/ diff --git a/api-test/Cargo.toml b/api-test/Cargo.toml index 9172c5f..0440c31 100644 --- a/api-test/Cargo.toml +++ b/api-test/Cargo.toml @@ -17,12 +17,11 @@ travis-ci = { repository = "https://github.com/stepancheg/rust-tls-api/", branch [dependencies] tls-api = { path = "../api", version = "=0.10.0-pre", default-features = false } log = "0.4" -env_logger = "0.5" +env_logger = "0.11.2" anyhow = "1.0.44" -pem = "0.8.3" +pem = "3.0.4" webpki = "0.22.0" -untrusted = "0.6.*" tokio = { version = "1.2.0", features = ["net", "io-util", "rt", "rt-multi-thread"], optional = true } async-std = { version = "1.9.0", features = ["attributes"], optional = true } diff --git a/api/Cargo.toml b/api/Cargo.toml index f769453..67f4292 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -16,7 +16,7 @@ bench = false travis-ci = { repository = "https://github.com/stepancheg/rust-tls-api/", branch = "master" } [dependencies] -pem = "0.8.3" +pem = "3.0.4" tempfile = "3.3.0" anyhow = "1.0.44" thiserror = "1.0.30" diff --git a/api/src/openssl.rs b/api/src/openssl.rs index 794bed4..e47ff51 100644 --- a/api/src/openssl.rs +++ b/api/src/openssl.rs @@ -17,15 +17,10 @@ pub(crate) fn der_to_pkcs12(cert: &[u8], key: &[u8]) -> anyhow::Result<(Vec, let passphrase = "tls-api-123"; let pem_data = pem::encode_many(&[ - pem::Pem { - tag: "CERTIFICATE".to_owned(), - contents: cert.to_owned(), - }, - pem::Pem { - // Technically it can be non-RSA PRIVATE KEY - tag: "RSA PRIVATE KEY".to_owned(), - contents: key.to_owned(), - }, + pem::Pem::new("CERTIFICATE", cert.to_vec()), + + // Technically it can be non-RSA PRIVATE KEY + pem::Pem::new("RSA PRIVATE KEY", key.to_vec()), ]); fs::write(&cert_file, pem_data)?; @@ -84,25 +79,25 @@ pub(crate) fn pkcs12_to_der(pkcs12: &[u8], passphrase: &str) -> anyhow::Result<( } let cert_pem = fs::read_to_string(cert_pem_file)?; - let pems = pem::parse_many(cert_pem); + let pems = pem::parse_many(cert_pem)?; let mut certificates: Vec> = pems .iter() - .flat_map(|p| match p.tag.as_str() { - "CERTIFICATE" => Some(p.contents.clone()), + .flat_map(|p| match p.tag() { + "CERTIFICATE" => Some(p.contents().to_vec()), _ => None, }) .collect(); let mut keys: Vec> = pems .iter() - .flat_map(|p| match p.tag.as_str() { - "PRIVATE KEY" | "RSA PRIVATE KEY" => Some(p.contents.clone()), + .flat_map(|p| match p.tag() { + "PRIVATE KEY" | "RSA PRIVATE KEY" => Some(p.contents().to_vec()), _ => None, }) .collect(); if keys.len() != 1 || certificates.len() != 1 { return Err( crate::CommonError::PemFromPkcs12ContainsNotSingleCertKeyPair( - pems.iter().map(|p| p.tag.clone()).collect(), + pems.iter().map(|p| p.tag().to_string()).collect(), ) .into(), ); diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d0e7854..993a93e 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -42,8 +42,8 @@ runtime-tokio = [ ] [dev-dependencies] -env_logger = { version = "0.5", default-features = false } -cfg-if = "0.1" +env_logger = { version = "0.11.2", default-features = false } +cfg-if = "1.0.0" tokio = { version = "1.2.0", features = ["net"] } [target.'cfg(all(not(target_os = "macos"), not(windows), not(target_os = "ios")))'.dev-dependencies] @@ -58,4 +58,4 @@ advapi32-sys = "0.2" crypt32-sys = "0.2" kernel32-sys = "0.2" schannel = "0.1" -winapi = "0.2" +winapi = "0.3.9" diff --git a/impl-rustls/Cargo.toml b/impl-rustls/Cargo.toml index 979ab07..da2c3f9 100644 --- a/impl-rustls/Cargo.toml +++ b/impl-rustls/Cargo.toml @@ -17,7 +17,7 @@ travis-ci = { repository = "https://github.com/stepancheg/rust-tls-api/", branch [dependencies] rustls = { version = "0.20.0", features = ["dangerous_configuration"] } webpki = "0.22.0" -webpki-roots = "0.22.0" +webpki-roots = "0.26.1" tokio = { version = "1.2.0", features = [], optional = true } async-std = { version = "1.9.0", features = ["attributes"], optional = true } anyhow = "1.0.44" diff --git a/impl-rustls/examples/server.rs b/impl-rustls/examples/server.rs index 759138f..6f48469 100644 --- a/impl-rustls/examples/server.rs +++ b/impl-rustls/examples/server.rs @@ -12,7 +12,7 @@ use test_cert_gen::pem_to_cert_key_pair; use tls_api::runtime::AsyncWriteExt; async fn run() { - let (cert, key) = pem_to_cert_key_pair(fs::read_to_string("server.pem").unwrap().as_bytes()); + let (cert, key) = pem_to_cert_key_pair(fs::read_to_string("server.pem").unwrap().as_bytes()).unwrap(); let builder = tls_api_rustls::TlsAcceptor::builder_from_der_key(cert.get_der(), key.get_der()).unwrap(); diff --git a/impl-rustls/src/connector.rs b/impl-rustls/src/connector.rs index 9c9b24c..9881a4d 100644 --- a/impl-rustls/src/connector.rs +++ b/impl-rustls/src/connector.rs @@ -145,11 +145,11 @@ impl tls_api::TlsConnector for TlsConnector { fn builder() -> anyhow::Result { let mut roots = rustls::RootCertStore::empty(); - roots.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { + roots.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| { rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( - ta.subject, - ta.spki, - ta.name_constraints, + ta.subject.as_ref(), + ta.subject_public_key_info.as_ref(), + ta.name_constraints.as_ref().map(|x| x.as_ref()), ) })); let config = rustls::ClientConfig::builder() diff --git a/test-cert-gen/Cargo.toml b/test-cert-gen/Cargo.toml index 57c3bad..f72477c 100644 --- a/test-cert-gen/Cargo.toml +++ b/test-cert-gen/Cargo.toml @@ -11,5 +11,5 @@ bench = false [dependencies] tempfile = "3.3.0" -pem = "0.8.3" +pem = "3.0.4" once_cell = "1.10.0" diff --git a/test-cert-gen/src/cert.rs b/test-cert-gen/src/cert.rs index b3f661c..5435c0e 100644 --- a/test-cert-gen/src/cert.rs +++ b/test-cert-gen/src/cert.rs @@ -26,18 +26,18 @@ impl Cert { } /// Construct from PEM-DER-encoded. - pub fn from_pem(cert_der_pem: impl AsRef<[u8]>) -> Cert { - let pem = pem::parse_many(cert_der_pem.as_ref()); + pub fn from_pem(cert_der_pem: impl AsRef<[u8]>) -> Result { + let pem = pem::parse_many(cert_der_pem.as_ref())?; let count = pem.len(); let mut certs: Vec = pem .into_iter() - .flat_map(|p| match p.tag == "CERTIFICATE" { - true => Some(Self::from_der(p.contents)), + .flat_map(|p| match p.tag() == "CERTIFICATE" { + true => Some(Self::from_der(p.contents())), false => None, }) .collect(); if certs.len() == 1 { - return certs.swap_remove(0); + return Ok(certs.swap_remove(0)); } else if certs.len() > 1 { panic!("PEM file contains {} certificates", certs.len()); } else if count != 0 { @@ -59,10 +59,7 @@ impl Cert { /// Convert a certificate to PEM format. pub fn to_pem(&self) -> String { - pem::encode(&pem::Pem { - tag: "CERTIFICATE".to_owned(), - contents: self.0.clone(), - }) + pem::encode(&pem::Pem::new("CERTIFICATE", self.0.to_vec())) } } @@ -89,18 +86,18 @@ impl PrivateKey { /// Construct a private key from PEM text file. /// /// This operation returns an error if PEM file contains zero or more than one certificate. - pub fn from_pem(key_pem: impl AsRef<[u8]>) -> PrivateKey { - let pem = pem::parse_many(key_pem.as_ref()); + pub fn from_pem(key_pem: impl AsRef<[u8]>) -> Result { + let pem = pem::parse_many(key_pem.as_ref())?; let count = pem.len(); let mut keys: Vec = pem .into_iter() - .flat_map(|p| match p.tag.as_ref() { - "PRIVATE KEY" | "RSA PRIVATE KEY" => Some(Self::from_der(p.contents)), + .flat_map(|p| match p.tag() { + "PRIVATE KEY" | "RSA PRIVATE KEY" => Some(Self::from_der(p.contents())), _ => None, }) .collect(); if keys.len() == 1 { - return keys.swap_remove(0); + return Ok(keys.swap_remove(0)); } else if keys.len() > 1 { panic!("PEM file contains {} private keys", keys.len()); } else if count != 0 { @@ -121,25 +118,22 @@ impl PrivateKey { /// without verifying that the private key is actually RSA. #[doc(hidden)] pub fn to_pem_incorrect(&self) -> String { - pem::encode(&pem::Pem { - tag: "RSA PRIVATE KEY".to_owned(), - contents: self.0.clone(), - }) + pem::encode(&pem::Pem::new("RSA PRIVATE KEY", self.0.clone())) } } /// Parse PEM file into a pair of certificate and private key. -pub fn pem_to_cert_key_pair(pem: &[u8]) -> (Cert, PrivateKey) { - let entries = pem::parse_many(pem); +pub fn pem_to_cert_key_pair(pem: &[u8]) -> Result<(Cert, PrivateKey), pem::PemError> { + let entries = pem::parse_many(pem)?; if entries.len() != 2 { panic!( "PEM file should contain certificate and private key entries, got {} entries", entries.len() ); } - let cert = Cert::from_pem(pem); - let key = PrivateKey::from_pem(pem); - (cert, key) + let cert = Cert::from_pem(pem)?; + let key = PrivateKey::from_pem(pem)?; + Ok((cert, key)) } /// DER-encoded diff --git a/test-cert-gen/src/lib.rs b/test-cert-gen/src/lib.rs index af99da9..23897e2 100644 --- a/test-cert-gen/src/lib.rs +++ b/test-cert-gen/src/lib.rs @@ -107,12 +107,12 @@ fn gen_root_ca() -> CertAndPrivateKey { let cert = fs::read_to_string(&certfile).unwrap(); let key = fs::read_to_string(&keyfile).unwrap(); - assert_eq!(1, pem::parse_many(cert.as_bytes()).len()); - assert_eq!(1, pem::parse_many(key.as_bytes()).len()); + assert_eq!(1, pem::parse_many(cert.as_bytes()).unwrap().len()); + assert_eq!(1, pem::parse_many(key.as_bytes()).unwrap().len()); CertAndPrivateKey { - cert: Cert::from_pem(&cert), - key: PrivateKey::from_pem(&key), + cert: Cert::from_pem(&cert).unwrap(), + key: PrivateKey::from_pem(&key).unwrap(), } } @@ -220,12 +220,12 @@ fn gen_cert_for_domain(domain: &str, ca: &CertAndPrivateKey) -> CertAndPrivateKe let cert = fs::read_to_string(&cert_path).unwrap(); // verify - assert_eq!(1, pem::parse_many(cert.as_bytes()).len()); - assert_eq!(1, pem::parse_many(key.as_bytes()).len()); + assert_eq!(1, pem::parse_many(cert.as_bytes()).unwrap().len()); + assert_eq!(1, pem::parse_many(key.as_bytes()).unwrap().len()); CertAndPrivateKey { - cert: Cert::from_pem(&cert), - key: PrivateKey::from_pem(&key), + cert: Cert::from_pem(&cert).unwrap(), + key: PrivateKey::from_pem(&key).unwrap(), } }