From 0f66443c2f90bb6f1eccd9e7af32107364c81c72 Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Sun, 28 May 2023 23:00:39 +0200 Subject: [PATCH] feat: ecc private key for tls feature (#208) it adds support for ECC private keys when enabling the --tls feature. this is particularly useful when generating private keys for example using clients like Lego ACME which defaults to EC256 keys. it resolves #207 --- src/tls.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++----------------------- tests/tls/local.dev_cert.ecc.pem | 12 ++++++++++++ tests/tls/local.dev_key.ecc.pem | 5 +++++ 3 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 tests/tls/local.dev_cert.ecc.pem create mode 100644 tests/tls/local.dev_key.ecc.pem diff --git a/src/tls.rs b/src/tls.rs index 195141e..72d8878 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -185,32 +185,35 @@ impl TlsConfigBuilder { .map(Certificate) .collect(); - let key = { - // convert it to Vec to allow reading it again if key is RSA - let mut key_vec = Vec::new(); - self.key - .read_to_end(&mut key_vec) - .map_err(TlsConfigError::Io)?; - - if key_vec.is_empty() { - return Err(TlsConfigError::EmptyKey); - } - - let mut pkcs8 = rustls_pemfile::pkcs8_private_keys(&mut key_vec.as_slice()) - .map_err(|_e| TlsConfigError::Pkcs8ParseError)?; - - if !pkcs8.is_empty() { - PrivateKey(pkcs8.remove(0)) - } else { - let mut rsa = rustls_pemfile::rsa_private_keys(&mut key_vec.as_slice()) - .map_err(|_e| TlsConfigError::RsaParseError)?; + // convert it to Vec to allow reading it again if key is RSA + let mut key_vec = Vec::new(); + self.key + .read_to_end(&mut key_vec) + .map_err(TlsConfigError::Io)?; + + if key_vec.is_empty() { + return Err(TlsConfigError::EmptyKey); + } - if !rsa.is_empty() { - PrivateKey(rsa.remove(0)) - } else { - return Err(TlsConfigError::EmptyKey); + let mut key = None; + let mut reader = std::io::Cursor::new(key_vec); + for item in + rustls_pemfile::read_all(&mut reader).map_err(|_e| TlsConfigError::Pkcs8ParseError)? + { + match item { + rustls_pemfile::Item::RSAKey(k) => key = Some(PrivateKey(k)), + rustls_pemfile::Item::PKCS8Key(k) => key = Some(PrivateKey(k)), + rustls_pemfile::Item::ECKey(k) => key = Some(PrivateKey(k)), + _ => { + return Err(TlsConfigError::InvalidKey( + TlsError::InvalidCertificateData("unknown private key format".to_owned()), + )) } } + } + let key = match key { + Some(k) => k, + _ => return Err(TlsConfigError::EmptyKey), }; fn read_trust_anchor( @@ -426,4 +429,25 @@ mod tests { .build() .unwrap(); } + + #[test] + fn file_cert_key_ecc() { + TlsConfigBuilder::new() + .cert_path("tests/tls/local.dev_cert.ecc.pem") + .key_path("tests/tls/local.dev_key.ecc.pem") + .build() + .unwrap(); + } + + #[test] + fn bytes_cert_key_ecc() { + let cert = include_str!("../tests/tls/local.dev_cert.ecc.pem"); + let key = include_str!("../tests/tls/local.dev_key.ecc.pem"); + + TlsConfigBuilder::new() + .key(key.as_bytes()) + .cert(cert.as_bytes()) + .build() + .unwrap(); + } } diff --git a/tests/tls/local.dev_cert.ecc.pem b/tests/tls/local.dev_cert.ecc.pem new file mode 100644 index 0000000..f661a63 --- /dev/null +++ b/tests/tls/local.dev_cert.ecc.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBtDCCAVoCCQDFz95/8CeJaDAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJERTEQ +MA4GA1UECAwHR2VybWFueTEQMA4GA1UEBwwHTGVpcHppZzESMBAGA1UEAwwJbG9j +YWwuZGV2MRswGQYJKoZIhvcNAQkBFgxoaUBsb2NhbC5kZXYwHhcNMjMwNTI4MTk0 +NzA4WhcNMjYwNTI3MTk0NzA4WjBiMQswCQYDVQQGEwJERTEQMA4GA1UECAwHR2Vy +bWFueTEQMA4GA1UEBwwHTGVpcHppZzESMBAGA1UEAwwJbG9jYWwuZGV2MRswGQYJ +KoZIhvcNAQkBFgxoaUBsb2NhbC5kZXYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC +AATZR4F60X+iHjeD6kySZfXljNckDb22QYQ76Ts4GFYWkdDstU6yehxyER+MZWsm +UnTE/Gy3mnpSmMzoSBfoKRmHMAoGCCqGSM49BAMCA0gAMEUCIQChOTwbAYlx6zg0 +yc3Oc+zrNY8Yd8oRUD+cG/wdz+gN/wIgP199zXAPXiYUFFd1CnIYmWJSglaOUbYj +ZP/ixZR9HQs= +-----END CERTIFICATE----- diff --git a/tests/tls/local.dev_key.ecc.pem b/tests/tls/local.dev_key.ecc.pem new file mode 100644 index 0000000..9287db7 --- /dev/null +++ b/tests/tls/local.dev_key.ecc.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIPwp3LAnLEyWe2lLz66Y3QCCJ/BEMJheTM0shZnnSw6toAoGCCqGSM49 +AwEHoUQDQgAE2UeBetF/oh43g+pMkmX15YzXJA29tkGEO+k7OBhWFpHQ7LVOsnoc +chEfjGVrJlJ0xPxst5p6UpjM6EgX6CkZhw== +-----END EC PRIVATE KEY----- -- libgit2 1.7.2