From af48d1f2e64ac353511c079855951c9cdc51177a Mon Sep 17 00:00:00 2001 From: Abdullah Alyan Date: Mon, 8 Mar 2021 12:39:36 +0300 Subject: [PATCH] Support more TLS key types in PKCS format. Closes #1449. Resolves #1461. --- core/http/src/tls.rs | 45 ++++++++++- examples/tls/Rocket.toml | 29 +++++-- .../private/ecdsa_nistp256_sha256_cert.pem | 20 +++++ .../ecdsa_nistp256_sha256_key_pkcs8.pem | 5 ++ .../private/ecdsa_nistp384_sha384_cert.pem | 21 +++++ .../ecdsa_nistp384_sha384_key_pkcs8.pem | 6 ++ examples/tls/private/ed25519_cert.pem | 20 +++++ examples/tls/private/ed25519_key.pem | 3 + examples/tls/private/gen_ca.sh | 6 ++ examples/tls/private/gen_cert.sh | 21 ----- examples/tls/private/gen_certs.sh | 80 +++++++++++++++++++ .../private/{cert.pem => rsa_sha256_cert.pem} | 0 .../private/{key.pem => rsa_sha256_key.pem} | 0 13 files changed, 227 insertions(+), 29 deletions(-) create mode 100644 examples/tls/private/ecdsa_nistp256_sha256_cert.pem create mode 100644 examples/tls/private/ecdsa_nistp256_sha256_key_pkcs8.pem create mode 100644 examples/tls/private/ecdsa_nistp384_sha384_cert.pem create mode 100644 examples/tls/private/ecdsa_nistp384_sha384_key_pkcs8.pem create mode 100644 examples/tls/private/ed25519_cert.pem create mode 100644 examples/tls/private/ed25519_key.pem create mode 100755 examples/tls/private/gen_ca.sh delete mode 100755 examples/tls/private/gen_cert.sh create mode 100755 examples/tls/private/gen_certs.sh rename examples/tls/private/{cert.pem => rsa_sha256_cert.pem} (100%) rename examples/tls/private/{key.pem => rsa_sha256_key.pem} (100%) diff --git a/core/http/src/tls.rs b/core/http/src/tls.rs index 90f8eca1..4c4567e7 100644 --- a/core/http/src/tls.rs +++ b/core/http/src/tls.rs @@ -41,7 +41,7 @@ fn load_private_key(reader: &mut dyn io::BufRead) -> io::Result { })?; // Ensure we can use the key. - rustls::sign::RSASigningKey::new(&key) + rustls::sign::any_supported_type(&key) .map_err(|_| Error::new(Other, "key parsed but is unusable")) .map(|_| key) } @@ -126,3 +126,46 @@ impl Connection for TlsStream { self.get_ref().0.remote_addr() } } + +#[cfg(test)] +mod test { + use super::*; + + use std::io::Cursor; + + macro_rules! tls_example_key { + ($k:expr) => { + include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../examples/tls/private/", $k)) + } + } + + #[test] + fn verify_load_private_keys_of_different_types() -> io::Result<()> { + let rsa_sha256_key = tls_example_key!("rsa_sha256_key.pem"); + let ecdsa_nistp256_sha256_key = tls_example_key!("ecdsa_nistp256_sha256_key_pkcs8.pem"); + let ecdsa_nistp384_sha384_key = tls_example_key!("ecdsa_nistp384_sha384_key_pkcs8.pem"); + let ed2551_key = tls_example_key!("ed25519_key.pem"); + + load_private_key(&mut Cursor::new(rsa_sha256_key))?; + load_private_key(&mut Cursor::new(ecdsa_nistp256_sha256_key))?; + load_private_key(&mut Cursor::new(ecdsa_nistp384_sha384_key))?; + load_private_key(&mut Cursor::new(ed2551_key))?; + + Ok(()) + } + + #[test] + fn verify_load_certs_of_different_types() -> io::Result<()> { + let rsa_sha256_cert = tls_example_key!("rsa_sha256_cert.pem"); + let ecdsa_nistp256_sha256_cert = tls_example_key!("ecdsa_nistp256_sha256_cert.pem"); + let ecdsa_nistp384_sha384_cert = tls_example_key!("ecdsa_nistp384_sha384_cert.pem"); + let ed2551_cert = tls_example_key!("ed25519_cert.pem"); + + load_certs(&mut Cursor::new(rsa_sha256_cert))?; + load_certs(&mut Cursor::new(ecdsa_nistp256_sha256_cert))?; + load_certs(&mut Cursor::new(ecdsa_nistp384_sha384_cert))?; + load_certs(&mut Cursor::new(ed2551_cert))?; + + Ok(()) + } +} diff --git a/examples/tls/Rocket.toml b/examples/tls/Rocket.toml index 4077d1cf..a0f61691 100644 --- a/examples/tls/Rocket.toml +++ b/examples/tls/Rocket.toml @@ -1,9 +1,24 @@ -# The certificate/private key pair used here was generated via openssl using the -# `gen_cert.sh` script located in the `private/` subdirectory. +# The certificate/private key pairs used here was generated via openssl using the +# scripts 'gen_ca.sh' and 'gen_certs.sh' located in the `private/` subdirectory. # -# The certificate is self-signed. As such, you will need to trust it directly +# The certificates are self-signed. As such, you will need to trust them directly # for your browser to refer to the connection as secure. You should NEVER use -# this certificate/key pair. It is here for DEMONSTRATION PURPOSES ONLY. -[global.tls] -certs = "private/cert.pem" -key = "private/key.pem" +# these certificate/key pairs. They are here for DEMONSTRATION PURPOSES ONLY. +[default.tls] +certs = "private/rsa_sha256_cert.pem" +key = "private/rsa_sha256_key.pem" + +[rsa_sha256.tls] +certs = "private/rsa_sha256_cert.pem" +key = "private/rsa_sha256_key.pem" +[ecdsa_nistp256_sha256.tls] +certs = "private/ecdsa_nistp256_sha256_cert.pem" +key = "private/ecdsa_nistp256_sha256_key_pkcs8.pem" + +[ecdsa_nistp384_sha384.tls] +certs = "private/ecdsa_nistp384_sha384_cert.pem" +key = "private/ecdsa_nistp384_sha384_key_pkcs8.pem" + +[ed25519.tls] +certs = "private/ed25519_cert.pem" +key = "private/ed25519_key.pem" diff --git a/examples/tls/private/ecdsa_nistp256_sha256_cert.pem b/examples/tls/private/ecdsa_nistp256_sha256_cert.pem new file mode 100644 index 00000000..802e5cec --- /dev/null +++ b/examples/tls/private/ecdsa_nistp256_sha256_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVjCCAT6gAwIBAgIJAI9jdPcCsa4EMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV +BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEChMJUm9ja2V0IENBMRcwFQYDVQQD +Ew5Sb2NrZXQgUm9vdCBDQTAeFw0yMTAzMTAxNjAwMjNaFw0zMTAzMDgxNjAwMjNa +MD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UECgwGUm9ja2V0MRIw +EAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQzqFmE +N1a7P/mKHJHGgKOpLTFf3KFuhzC5aUsz3vXSgclet6DxTwGeew5MRxBE9Wom8gS4 +UHlZL5eVaUyQeKoroxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcN +AQELBQADggIBAESn9PwlB0mws6CY+w507HqeSAbHXaT+m5YtinHDx4II3V5Q61YD +ew37FAaeey+2IJ6f73K0NqRXIMQL5cFD1eK9b32fDoMO/XtJA9eFue3MSgDuqZaY +sLNtg/MWSvWFYXHzc3bFynX9tr4+1VwYs7oC3dwHAl0rbhyOKKdsZeBzfluIvzjg +BHR5I1P16RQubG7BDFBQTQQ21+oN3Zp0EXjTvqy5g1qfIEvPozqT4hlTHVvY/fcv +kStjUNbhMmZ3WxLbVkiICp1SMXP4UjNDvzUgr4W5F/MuqKAWabuAg9veMu9l1kMf +RjQLyl2srtFKG6tInNmLHQrCx6nW+LPYxVH/JmiBbkfYURowaNPRiWCAi7b8pZ+s +WBAGHwSMYvpVIDWSBSYWcBQvomb+kdp2mF1+PilgDliLttfCO+OByMUSBjdZLXUI +nxBxWVgh9jUxyLM47eaNiH0Y5t79b6e+wlPwgMIz6naEs82cdJKBzfLJJ7lvAKOH +9aAobrDzlJD3N1YffdRlIaOxyUqobgyqBszDiZkq4+mXg4+OhOcqP/qck2A56bu+ +e8E+4o17FHQMOoHcJ11tBW3nl6DyPU4jzT2VOJvq0Yu/9flai5lo0HZ3uIP4x0ZJ +iNml6X97ARlipNpjerbkuzRNHdxVhSh4LllPlXV4w4iGxjeONVkj69OB +-----END CERTIFICATE----- diff --git a/examples/tls/private/ecdsa_nistp256_sha256_key_pkcs8.pem b/examples/tls/private/ecdsa_nistp256_sha256_key_pkcs8.pem new file mode 100644 index 00000000..13a007ea --- /dev/null +++ b/examples/tls/private/ecdsa_nistp256_sha256_key_pkcs8.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyomM+167aYfudwIs +7T9VyM7FGJr2cYfpKOOOaeBIzyuhRANCAAQzqFmEN1a7P/mKHJHGgKOpLTFf3KFu +hzC5aUsz3vXSgclet6DxTwGeew5MRxBE9Wom8gS4UHlZL5eVaUyQeKor +-----END PRIVATE KEY----- diff --git a/examples/tls/private/ecdsa_nistp384_sha384_cert.pem b/examples/tls/private/ecdsa_nistp384_sha384_cert.pem new file mode 100644 index 00000000..c5754305 --- /dev/null +++ b/examples/tls/private/ecdsa_nistp384_sha384_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDczCCAVugAwIBAgIJAOIfNU0ricf5MA0GCSqGSIb3DQEBDAUAMEcxCzAJBgNV +BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEChMJUm9ja2V0IENBMRcwFQYDVQQD +Ew5Sb2NrZXQgUm9vdCBDQTAeFw0yMTAzMTAxNjA4MThaFw0zMTAzMDgxNjA4MTha +MD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UECgwGUm9ja2V0MRIw +EAYDVQQDDAlsb2NhbGhvc3QwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR69JeIdYW8 +x2qkkOAWZSOQYy2Y1S3biBmalAmJdaH+76mfmkMKTlcGyT5Pxns85sp9sZbBiBxm +Odnh3uMZbqh5ej4zNfIP27NjsnmrQzm1HQqgmgU16e3FZ1Sn4Mbi6kCjGDAWMBQG +A1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQwFAAOCAgEAg/XC/unGAtLZ +1OOKQcBrCRcHWyw9MpnXL7MnmM1yRWsoSbrYzueU1rpEh/i9wa/hkyVhtdYJ5USf +UFjqUW8OV+sElLMdm8VWxT61DxYxUdZIZB3BtWhI/tQXDhIwv9L2UbFMZHoYiTUA +bgPflpNtZtsPabX0PsusUber/GhkSCnwGADmbnPtre2m9ODvSxYfLVcbDn5kF9rE +/c2lnJMROYlNaAb9+P9hH+k8X++MT0xfbB26y/c3dJsp0JKGajT6ki9NlfitnWvy +csmgIo4QdVOTsbUIrfZX6khOCk18fiqYfHRjg6MnbTiRTncC9iuYYdsRH7Q6/q36 +wUMyh7XOto3R+ejERDTpS0V34SBL9Q+998LNQMAKpU/gUyU9whD/zhTn2GD2uYe8 +8hlYjUy9nSU8qzybPEQUQotgd7AcvMat12ZcQqoUdB/2Rwqw/KQvqtwkcDz1N4Dt ++oJ3jCH6DnC4Ov1Qeyu/PWnc92DRxTmynOv11P/quDoQGrXPKZ+PxEEHktC1yyGi +nff8EPTRzRqLYe+sFPS12MvrWhg7CoMLKxXhqezAH0gmf++bRrOrnkGkmMDbyFFh +YraGkqZaG6X6dK7JyLIXndXv3rx7EfVdEmicIwQ04l7XsirxvYs1ei/wlSzn63k4 +uNj+AnJ0PNOmktTAHzfgHLv+fVgIlcM= +-----END CERTIFICATE----- diff --git a/examples/tls/private/ecdsa_nistp384_sha384_key_pkcs8.pem b/examples/tls/private/ecdsa_nistp384_sha384_key_pkcs8.pem new file mode 100644 index 00000000..2ab68ff3 --- /dev/null +++ b/examples/tls/private/ecdsa_nistp384_sha384_key_pkcs8.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDUm43VOrG74fBAQT7y +CqoKnDbOotrUHGbm/NR5KE3axbiccbQx349ZmvDUqOaZZNChZANiAAR69JeIdYW8 +x2qkkOAWZSOQYy2Y1S3biBmalAmJdaH+76mfmkMKTlcGyT5Pxns85sp9sZbBiBxm +Odnh3uMZbqh5ej4zNfIP27NjsnmrQzm1HQqgmgU16e3FZ1Sn4Mbi6kA= +-----END PRIVATE KEY----- diff --git a/examples/tls/private/ed25519_cert.pem b/examples/tls/private/ed25519_cert.pem new file mode 100644 index 00000000..0c294cbb --- /dev/null +++ b/examples/tls/private/ed25519_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMjCCARqgAwIBAgIUNAiGpJKcWHB80qLj99td7IXO6QcwDQYJKoZIhvcNAQEL +BQAwRzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQKEwlSb2NrZXQg +Q0ExFzAVBgNVBAMTDlJvY2tldCBSb290IENBMB4XDTIxMDMxMDE5NDg1MVoXDTMx +MDMwODE5NDg1MVowPzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQK +DAZSb2NrZXQxEjAQBgNVBAMMCWxvY2FsaG9zdDAqMAUGAytlcAMhAAnWZ6qQExvf +pIrjevFoIX8Yo+VCqPq69fhF93GNNU7PoxgwFjAUBgNVHREEDTALgglsb2NhbGhv +c3QwDQYJKoZIhvcNAQELBQADggIBAJQz+xaTgQ9J8tKLMIGWgK7b8W9YbaXFfKvi +zGUrrP9YKTOVuYF38u99B+mMsDKEEpreFz53viKrN3CK6RgfETMPMWloDdS3yI3z +z+FsJM5jsv2AVdGH0RLZyD8lkZfElzHfSjE3tvAQFe43AWnOliRqjze2Vf8JmJfv +TLJGMUNERI8BKvhdd+q9nubi4SlurRjmPVMDUhJChB7eupOe4OSHEfAwEE3JYEBH +U0xfoGi7LbxE61Ew7GFCgzNKllOgkY5RqrfvjVPjwj5Bl9bleuqqhLfaPyJaftVH +LS9FgK8fCLKqmU7XA98qeAXKy+t17OXteDMV+NuT5Us2b/xGECm9J1+NJDQPRHCT +RMYbh4B/6mzR7Jjw87ByJOjzWnl6XWJ2kvf3ZI2Y3uQeUV7mjZbg2YGfEZFirr9T ++C85BivcN+XLLVYbonqK/sD2dUjh4s9jIELkrcFm9XydGBVRvcrZCFu661Fg8Ro+ +QOBMUH+T0/45s4VKf14S3d7wZAXE1w5yJdz7/yXw1zpeGojgMZrGBZzFRDI9eh9J +1+MrtLKbvxQcQHni696PJ1BkIMX6f8Wjp6gIr4m+MWoJrNi2VIfTQldVbQVhqVmF +URikFHfMDxMpJxsZ45fAwSfHRO5+jwMyB6KOmaSQhS6y4YpLb6Y3j6QG1KL6+kjf +/IPYS11c +-----END CERTIFICATE----- diff --git a/examples/tls/private/ed25519_key.pem b/examples/tls/private/ed25519_key.pem new file mode 100644 index 00000000..b66c30ff --- /dev/null +++ b/examples/tls/private/ed25519_key.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIBkz65y9k4wYXTNXgNDhKfJnCiEosnD95sFoVIxWmOzL +-----END PRIVATE KEY----- diff --git a/examples/tls/private/gen_ca.sh b/examples/tls/private/gen_ca.sh new file mode 100755 index 00000000..406727a5 --- /dev/null +++ b/examples/tls/private/gen_ca.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +CA_SUBJECT="/C=US/ST=CA/O=Rocket CA/CN=Rocket Root CA" + +openssl genrsa -out ca_key.pem 4096 +openssl req -new -x509 -days 3650 -key ca_key.pem -subj "${CA_SUBJECT}" -out ca_cert.pem diff --git a/examples/tls/private/gen_cert.sh b/examples/tls/private/gen_cert.sh deleted file mode 100755 index a2f25cfe..00000000 --- a/examples/tls/private/gen_cert.sh +++ /dev/null @@ -1,21 +0,0 @@ -#! /bin/bash - -# TODO: `rustls` (really, `webpki`) doesn't currently use the CN in the subject -# to check if a certificate is valid for a server name sent via SNI. It's not -# clear if this is intended, since certificates _should_ have a `subjectAltName` -# with a DNS name, or if it simply hasn't been implemented yet. See -# https://bugzilla.mozilla.org/show_bug.cgi?id=552346 for a bit more info. - -CA_SUBJECT="/C=US/ST=CA/O=Rocket CA/CN=Rocket Root CA" -SUBJECT="/C=US/ST=CA/O=Rocket/CN=localhost" -ALT="DNS:localhost" - -openssl genrsa -out ca_key.pem 4096 -openssl req -new -x509 -days 3650 -key ca_key.pem -subj "${CA_SUBJECT}" -out ca_cert.pem - -openssl req -newkey rsa:4096 -nodes -sha256 -keyout key.pem -subj "${SUBJECT}" -out server.csr -openssl x509 -req -sha256 -extfile <(printf "subjectAltName=${ALT}") -days 3650 \ - -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ - -in server.csr -out cert.pem - -rm ca_cert.srl server.csr diff --git a/examples/tls/private/gen_certs.sh b/examples/tls/private/gen_certs.sh new file mode 100755 index 00000000..0927c99b --- /dev/null +++ b/examples/tls/private/gen_certs.sh @@ -0,0 +1,80 @@ +#! /bin/bash + +# Should use gen_ca.sh first to generate the CA. + +# To generate certificates of specific private key type, pass any of the following arguements: +# 'ed25519', 'rsa_sha256', 'ecdsa_nistp256_sha256' or 'ecdsa_nistp384_sha384' +# +# If no argument is passed all supported certificates types will be generated. +# + +# TODO: `rustls` (really, `webpki`) doesn't currently use the CN in the subject +# to check if a certificate is valid for a server name sent via SNI. It's not +# clear if this is intended, since certificates _should_ have a `subjectAltName` +# with a DNS name, or if it simply hasn't been implemented yet. See +# https://bugzilla.mozilla.org/show_bug.cgi?id=552346 for a bit more info. + +SUBJECT="/C=US/ST=CA/O=Rocket/CN=localhost" +ALT="DNS:localhost" + +function gen_rsa_sha256() { + openssl req -newkey rsa:4096 -nodes -sha256 -keyout rsa_sha256_key.pem -subj "${SUBJECT}" -out server.csr + openssl x509 -req -sha256 -extfile <(printf "subjectAltName=${ALT}") -days 3650 \ + -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ + -in server.csr -out rsa_sha256_cert.pem + + rm ca_cert.srl server.csr +} + +function gen_ed25519() { + openssl genpkey -algorithm ED25519 > ed25519_key.pem + + openssl req -new -key ed25519_key.pem -subj "${SUBJECT}" -out server.csr + openssl x509 -req -extfile <(printf "subjectAltName=${ALT}") -days 3650 \ + -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ + -in server.csr -out ed25519_cert.pem + + rm ca_cert.srl server.csr +} + +function gen_ecdsa_nistp256_sha256() { + openssl ecparam -out ecdsa_nistp256_sha256_key.pem -name prime256v1 -genkey + + # Convert to pkcs8 format supported by rustls + openssl pkcs8 -topk8 -nocrypt -in ecdsa_nistp256_sha256_key.pem -out ecdsa_nistp256_sha256_key_pkcs8.pem + + openssl req -new -nodes -sha256 -key ecdsa_nistp256_sha256_key_pkcs8.pem -subj "${SUBJECT}" -out server.csr + openssl x509 -req -sha256 -extfile <(printf "subjectAltName=${ALT}") -days 3650 \ + -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ + -in server.csr -out ecdsa_nistp256_sha256_cert.pem + + rm ca_cert.srl server.csr ecdsa_nistp256_sha256_key.pem +} + + +function gen_ecdsa_nistp384_sha384() { + openssl ecparam -out ecdsa_nistp384_sha384_key.pem -name secp384r1 -genkey + + # Convert to pkcs8 format supported by rustls + openssl pkcs8 -topk8 -nocrypt -in ecdsa_nistp384_sha384_key.pem -out ecdsa_nistp384_sha384_key_pkcs8.pem + + openssl req -new -nodes -sha384 -key ecdsa_nistp384_sha384_key_pkcs8.pem -subj "${SUBJECT}" -out server.csr + openssl x509 -req -sha384 -extfile <(printf "subjectAltName=${ALT}") -days 3650 \ + -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ + -in server.csr -out ecdsa_nistp384_sha384_cert.pem + + rm ca_cert.srl server.csr ecdsa_nistp384_sha384_key.pem +} + +case $1 in + ed25519) gen_ed25519 ;; + rsa_sha256) gen_rsa_sha256 ;; + ecdsa_nistp256_sha256) gen_ecdsa_nistp256_sha256 ;; + ecdsa_nistp384_sha384) gen_ecdsa_nistp384_sha384 ;; + *) + gen_ed25519 + gen_rsa_sha256 + gen_ecdsa_nistp256_sha256 + gen_ecdsa_nistp384_sha384 + ;; +esac diff --git a/examples/tls/private/cert.pem b/examples/tls/private/rsa_sha256_cert.pem similarity index 100% rename from examples/tls/private/cert.pem rename to examples/tls/private/rsa_sha256_cert.pem diff --git a/examples/tls/private/key.pem b/examples/tls/private/rsa_sha256_key.pem similarity index 100% rename from examples/tls/private/key.pem rename to examples/tls/private/rsa_sha256_key.pem