diff --git a/core/http/Cargo.toml b/core/http/Cargo.toml index 88b2226f..f8198299 100644 --- a/core/http/Cargo.toml +++ b/core/http/Cargo.toml @@ -32,7 +32,7 @@ time = { version = "0.3", features = ["formatting", "macros"] } indexmap = { version = "1.5.2", features = ["std"] } rustls = { version = "0.20", optional = true } tokio-rustls = { version = "0.23.4", optional = true } -rustls-pemfile = { version = "1", optional = true } +rustls-pemfile = { version = "1.0.2", optional = true } tokio = { version = "1.6.1", features = ["net", "sync", "time"] } log = "0.4" ref-cast = "1.0" diff --git a/core/http/src/tls/util.rs b/core/http/src/tls/util.rs index a751ea18..8eb54c5d 100644 --- a/core/http/src/tls/util.rs +++ b/core/http/src/tls/util.rs @@ -20,12 +20,13 @@ pub fn load_private_key(reader: &mut dyn io::BufRead) -> io::Result let private_keys_fn = loop { header.clear(); if reader.read_line(&mut header)? == 0 { - return Err(err("failed to find key header; supported formats are: RSA, PKCS8")); + return Err(err("failed to find key header; supported formats are: RSA, PKCS8, SEC1")); } break match header.trim_end() { "-----BEGIN RSA PRIVATE KEY-----" => rustls_pemfile::rsa_private_keys, "-----BEGIN PRIVATE KEY-----" => rustls_pemfile::pkcs8_private_keys, + "-----BEGIN EC PRIVATE KEY-----" => rustls_pemfile::ec_private_keys, _ => continue, }; }; diff --git a/core/lib/src/config/tls.rs b/core/lib/src/config/tls.rs index bdf8403d..06755d7c 100644 --- a/core/lib/src/config/tls.rs +++ b/core/lib/src/config/tls.rs @@ -10,9 +10,10 @@ use indexmap::IndexSet; /// /// Both `certs` and `key` can be configured as a path or as raw bytes. /// `certs` must be a DER-encoded X.509 TLS certificate chain, while `key` -/// must be a DER-encoded ASN.1 key in either PKCS#8 or PKCS#1 format. -/// When a path is configured in a file, such as `Rocket.toml`, relative -/// paths are interpreted as relative to the source file's directory. +/// must be a DER-encoded ASN.1 key in either PKCS#8, PKCS#1, or SEC1 +/// format. When a path is configured in a file, such as `Rocket.toml`, +/// relative paths are interpreted as relative to the source file's +/// directory. /// /// * `ciphers` /// diff --git a/examples/tls/Rocket.toml b/examples/tls/Rocket.toml index 85f081ba..b7a538f9 100644 --- a/examples/tls/Rocket.toml +++ b/examples/tls/Rocket.toml @@ -17,14 +17,22 @@ mandatory = false certs = "private/rsa_sha256_cert.pem" key = "private/rsa_sha256_key.pem" -[ecdsa_nistp256_sha256.tls] +[ecdsa_nistp256_sha256_pkcs8.tls] certs = "private/ecdsa_nistp256_sha256_cert.pem" key = "private/ecdsa_nistp256_sha256_key_pkcs8.pem" -[ecdsa_nistp384_sha384.tls] +[ecdsa_nistp384_sha384_pkcs8.tls] certs = "private/ecdsa_nistp384_sha384_cert.pem" key = "private/ecdsa_nistp384_sha384_key_pkcs8.pem" +[ecdsa_nistp256_sha256_sec1.tls] +certs = "private/ecdsa_nistp256_sha256_cert.pem" +key = "private/ecdsa_nistp256_sha256_key_sec1.pem" + +[ecdsa_nistp384_sha384_sec1.tls] +certs = "private/ecdsa_nistp384_sha384_cert.pem" +key = "private/ecdsa_nistp384_sha384_key_sec1.pem" + [ed25519.tls] certs = "private/ed25519_cert.pem" key = "private/ed25519_key.pem" diff --git a/examples/tls/private/ecdsa_nistp256_sha256_key_sec1.pem b/examples/tls/private/ecdsa_nistp256_sha256_key_sec1.pem new file mode 100644 index 00000000..18236ad8 --- /dev/null +++ b/examples/tls/private/ecdsa_nistp256_sha256_key_sec1.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIM+futAjM1Au19lOdEvCiA2EOjB1LcDE7B3FK2w4S3y2oAoGCCqGSM49 +AwEHoUQDQgAEO0C+sMAtX9ka6tIl2hEUO8Hars+x2NZa/MVa9Ciu1TOZZe4U7jtA +ny+WqW4O1AoruAeY2bXQysOTajSKkySvNA== +-----END EC PRIVATE KEY----- diff --git a/examples/tls/private/ecdsa_nistp384_sha384_key_sec1.pem b/examples/tls/private/ecdsa_nistp384_sha384_key_sec1.pem new file mode 100644 index 00000000..844ebe28 --- /dev/null +++ b/examples/tls/private/ecdsa_nistp384_sha384_key_sec1.pem @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDClF5pKlKs9J5iaOAJEHe7v7RfcSt14yMjrp6y1jntK9j9jzTXAGtHC +yWwdW0GYTVmgBwYFK4EEACKhZANiAATZKfDYqkqFHPG8CatHyERcr3QzdI1E+PvT +HaCfwicih43lVQXDFlwSWyk5qKxW5CelnFGwVN9CtPik76l/bRS1zpqcFGQ8qppH +lO/FVewyawyksuR4Mc+YVyd9PZc/iq8= +-----END EC PRIVATE KEY----- diff --git a/examples/tls/src/tests.rs b/examples/tls/src/tests.rs index a4951f4d..ae0f12d7 100644 --- a/examples/tls/src/tests.rs +++ b/examples/tls/src/tests.rs @@ -2,7 +2,20 @@ use rocket::local::blocking::Client; #[test] fn hello_world() { - let client = Client::tracked(super::rocket()).unwrap(); - let response = client.get("/").dispatch(); - assert_eq!(response.into_string(), Some("Hello, world!".into())); + let profiles = [ + "rsa_sha256", + "ecdsa_nistp256_sha256_pkcs8", + "ecdsa_nistp384_sha384_pkcs8", + "ecdsa_nistp256_sha256_sec1", + "ecdsa_nistp384_sha384_sec1", + "ed25519", + ]; + + // TODO: Testing doesn't actually read keys since we don't do TLS locally. + for profile in profiles { + let config = rocket::Config::figment().select(profile); + let client = Client::tracked(super::rocket().configure(config)).unwrap(); + let response = client.get("/").dispatch(); + assert_eq!(response.into_string(), Some("Hello, world!".into())); + } } diff --git a/site/guide/9-configuration.md b/site/guide/9-configuration.md index 69797efb..b0712222 100644 --- a/site/guide/9-configuration.md +++ b/site/guide/9-configuration.md @@ -246,20 +246,20 @@ Security). To enable TLS support: ```toml,ignore [default.tls] - key = "path/to/key.pem" # Path or bytes to DER-encoded ASN.1 PKCS#1/#8 key. + key = "path/to/key.pem" # Path or bytes to DER-encoded ASN.1 PKCS#1/#8 or SEC1 key. certs = "path/to/certs.pem" # Path or bytes to DER-encoded X.509 TLS cert chain. ``` The `tls` parameter is expected to be a dictionary that deserializes into a [`TlsConfig`] structure: -| key | required | type | -|------------------------------|-----------|-------------------------------------------------------| -| `key` | **_yes_** | Path or bytes to DER-encoded ASN.1 PKCS#1/#8 key. | -| `certs` | **_yes_** | Path or bytes to DER-encoded X.509 TLS cert chain. | -| `ciphers` | no | Array of [`CipherSuite`]s to enable. | -| `prefer_server_cipher_order` | no | Boolean for whether to [prefer server cipher suites]. | -| `mutual` | no | A map with [mutual TLS] configuration. | +| key | required | type | +|------------------------------|-----------|---------------------------------------------------------------| +| `key` | **_yes_** | Path or bytes to DER-encoded ASN.1 PKCS#1/#8 or SEC1 key. | +| `certs` | **_yes_** | Path or bytes to DER-encoded X.509 TLS cert chain. | +| `ciphers` | no | Array of [`CipherSuite`]s to enable. | +| `prefer_server_cipher_order` | no | Boolean for whether to [prefer server cipher suites]. | +| `mutual` | no | A map with [mutual TLS] configuration. | [`CipherSuite`]: @api/rocket/config/enum.CipherSuite.html [prefer server cipher suites]: @api/rocket/config/struct.TlsConfig.html#method.with_preferred_server_cipher_order