diff --git a/Cargo.lock b/Cargo.lock index f1aaa07..e713111 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,11 +39,11 @@ dependencies = [ [[package]] name = "actix-codec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "bytes", "futures-core", "futures-sink", @@ -342,9 +342,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" [[package]] name = "anstyle-parse" @@ -422,7 +422,8 @@ dependencies = [ "rsa-magic-public-key", "ructe", "rustls", - "rustls-pemfile", + "rustls-channel-resolver", + "rustls-pemfile 2.0.0", "serde", "serde_json", "sled", @@ -431,7 +432,7 @@ dependencies = [ "thiserror", "time", "tokio", - "toml 0.8.8", + "toml 0.8.9", "tracing", "tracing-actix-web", "tracing-error", @@ -812,9 +813,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" dependencies = [ "num-traits", ] @@ -1488,7 +1489,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.1", "slab", "tokio", "tokio-util", @@ -1733,9 +1734,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1804,9 +1805,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -1854,9 +1855,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libm" @@ -1929,9 +1930,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7" +checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22" dependencies = [ "hashbrown 0.14.3", ] @@ -2080,7 +2081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "697a6b40dffdc5de10c0cbd709dc2bc2039cea9dab8aaa636eb9a49d6b411780" dependencies = [ "aho-corasick 0.7.20", - "itertools 0.12.0", + "itertools 0.12.1", "lazy_static", "memchr", "rustc-hash", @@ -2286,7 +2287,7 @@ checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" dependencies = [ "futures-core", "futures-sink", - "indexmap 2.1.0", + "indexmap 2.2.1", "js-sys", "once_cell", "pin-project-lite", @@ -2638,18 +2639,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", @@ -2739,9 +2740,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2949,13 +2950,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick 1.1.2", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.5", "regex-syntax 0.8.2", ] @@ -2970,9 +2971,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick 1.1.2", "memchr", @@ -3002,9 +3003,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ "base64 0.21.7", "bytes", @@ -3025,10 +3026,11 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-rustls", @@ -3060,9 +3062,9 @@ dependencies = [ [[package]] name = "reqwest-tracing" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b1e66540e0cac90acadaf7109bf99c90d95abcc94b4c096bfa16a2d7aa7a71" +checksum = "5a0152176687dd5cfe7f507ac1cb1a491c679cfe483afd133a7db7aaea818bb3" dependencies = [ "anyhow", "async-trait", @@ -3235,6 +3237,16 @@ dependencies = [ "sct", ] +[[package]] +name = "rustls-channel-resolver" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0a6bf546dc283b4c1413532d2bf53a64b3a006ee57f7ca0f4984f35841cacb" +dependencies = [ + "nanorand", + "rustls", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -3244,6 +3256,22 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +dependencies = [ + "base64 0.21.7", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -3296,18 +3324,18 @@ checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -3316,9 +3344,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", @@ -3462,9 +3490,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" @@ -3866,9 +3894,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" dependencies = [ "serde", "serde_spanned", @@ -3887,11 +3915,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.1", "serde", "serde_spanned", "toml_datetime", @@ -4184,9 +4212,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "atomic", "getrandom", @@ -4294,9 +4322,9 @@ checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wasm-streams" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" dependencies = [ "futures-util", "js-sys", @@ -4487,9 +4515,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.34" +version = "0.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "818ce546a11a9986bc24f93d0cdf38a8a1a400f1473ea8c82e59f6e0ffab9249" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 86e2d02..dbdcd63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ version = "0.3.106" authors = ["asonix "] license = "AGPL-3.0" readme = "README.md" -repository = "https://git.asonix.dog/asonix/ap-relay" +repository = "https://git.asonix.dog/asonix/relay" keywords = ["activitypub", "relay"] edition = "2021" build = "src/build.rs" @@ -58,10 +58,12 @@ ring = "0.17.5" rsa = { version = "0.9" } rsa-magic-public-key = "0.8.0" rustls = "0.21.0" -rustls-pemfile = "1.0.1" +rustls-channel-resolver = "0.1.0" +rustls-pemfile = "2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sled = "0.34.7" +streem = "0.2.0" teloxide = { version = "0.12.0", default-features = false, features = [ "ctrlc_handler", "macros", @@ -80,7 +82,6 @@ tracing-subscriber = { version = "0.3", features = [ ] } tokio = { version = "1", features = ["full", "tracing"] } uuid = { version = "1", features = ["v4", "serde"] } -streem = "0.2.0" [dependencies.background-jobs] version = "0.17.0" diff --git a/src/config.rs b/src/config.rs index 35520fd..49dcecd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,9 +12,8 @@ use activitystreams::{ }; use config::Environment; use http_signature_normalization_actix::{digest::ring::Sha256, prelude::VerifyDigest}; -use rustls::{Certificate, PrivateKey}; +use rustls::{sign::CertifiedKey, Certificate, PrivateKey}; use std::{ - io::BufReader, net::{IpAddr, SocketAddr}, path::PathBuf, }; @@ -312,7 +311,7 @@ impl Config { Some((config.addr, config.port).into()) } - pub(crate) fn open_keys(&self) -> Result, PrivateKey)>, Error> { + pub(crate) async fn open_keys(&self) -> Result, Error> { let tls = if let Some(tls) = &self.tls { tls } else { @@ -320,35 +319,29 @@ impl Config { return Ok(None); }; - let mut certs_reader = BufReader::new(std::fs::File::open(&tls.cert)?); - let certs = rustls_pemfile::certs(&mut certs_reader)?; + let certs_bytes = tokio::fs::read(&tls.cert).await?; + let certs = rustls_pemfile::certs(&mut certs_bytes.as_slice()) + .map(|res| res.map(|c| Certificate(c.to_vec()))) + .collect::, _>>()?; if certs.is_empty() { tracing::warn!("No certs read from certificate file"); return Ok(None); } - let mut key_reader = BufReader::new(std::fs::File::open(&tls.key)?); - let key = rustls_pemfile::read_one(&mut key_reader)?; - - let certs = certs.into_iter().map(Certificate).collect(); + let key_bytes = tokio::fs::read(&tls.key).await?; + let key = rustls_pemfile::private_key(&mut key_bytes.as_slice())?; let key = if let Some(key) = key { - match key { - rustls_pemfile::Item::RSAKey(der) => PrivateKey(der), - rustls_pemfile::Item::PKCS8Key(der) => PrivateKey(der), - rustls_pemfile::Item::ECKey(der) => PrivateKey(der), - _ => { - tracing::warn!("Unknown key format: {:?}", key); - return Ok(None); - } - } + PrivateKey(Vec::from(key.secret_der())) } else { tracing::warn!("Failed to read private key"); return Ok(None); }; - Ok(Some((certs, key))) + let key = rustls::sign::any_supported_type(&key)?; + + Ok(Some(CertifiedKey::new(certs, key))) } pub(crate) fn footer_blurb(&self) -> Option> { diff --git a/src/error.rs b/src/error.rs index f83d931..fd379f3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -114,6 +114,9 @@ pub(crate) enum ErrorKind { #[error("Couldn't sign digest")] Signature(#[from] rsa::signature::Error), + #[error("Couldn't prepare TLS private key")] + PrepareKey(#[from] rustls::sign::SignError), + #[error("Couldn't verify signature")] VerifySignature, diff --git a/src/main.rs b/src/main.rs index 4172e17..51e77c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -313,11 +313,15 @@ async fn server_main( telegram::start(admin_handle.to_owned(), db.clone(), token); } - let keys = config.open_keys()?; + let cert_resolver = config + .open_keys() + .await? + .map(rustls_channel_resolver::channel::<32>); let bind_address = config.bind_address(); let sign_spawner2 = sign_spawner.clone(); let verify_spawner2 = verify_spawner.clone(); + let config2 = config.clone(); let server = HttpServer::new(move || { let job_server = create_workers(state.clone(), actors.clone(), media.clone(), config.clone()) @@ -387,18 +391,36 @@ async fn server_main( ) }); - if let Some((certs, key)) = keys { + if let Some((cert_tx, cert_rx)) = cert_resolver { + let handle = tokio::spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(30)); + interval.tick().await; + + loop { + interval.tick().await; + + match config2.open_keys().await { + Ok(Some(key)) => cert_tx.update(key), + Ok(None) => tracing::warn!("Missing TLS keys"), + Err(e) => tracing::error!("Failed to read TLS keys {e}"), + } + } + }); + tracing::warn!("Binding to {}:{} with TLS", bind_address.0, bind_address.1); let server_config = ServerConfig::builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_safe_default_protocol_versions()? .with_no_client_auth() - .with_single_cert(certs, key)?; + .with_cert_resolver(cert_rx); server .bind_rustls_021(bind_address, server_config)? .run() .await?; + + handle.abort(); + let _ = handle.await; } else { tracing::warn!("Binding to {}:{}", bind_address.0, bind_address.1); server.bind(bind_address)?.run().await?;