Support multiple TLS certificates. (#95)
This commit is contained in:
parent
1749989dc5
commit
9a25143694
|
@ -23,3 +23,6 @@ jobs:
|
||||||
- run: cargo test --verbose
|
- run: cargo test --verbose
|
||||||
- run: cargo clippy --no-deps
|
- run: cargo clippy --no-deps
|
||||||
- run: cargo fmt --check
|
- run: cargo fmt --check
|
||||||
|
|
||||||
|
# Check for unused dependencies
|
||||||
|
- uses: bnjbvr/cargo-machete@main
|
||||||
|
|
|
@ -273,6 +273,26 @@ dependencies = [
|
||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-server"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "447f28c85900215cc1bea282f32d4a2f22d55c5a300afdfbc661c8d6a632e063"
|
||||||
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pemfile",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.69"
|
version = "0.3.69"
|
||||||
|
@ -306,15 +326,6 @@ version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "block-buffer"
|
|
||||||
version = "0.10.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blocking"
|
name = "blocking"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
@ -458,15 +469,6 @@ version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cpufeatures"
|
|
||||||
version = "0.2.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.16"
|
version = "0.8.16"
|
||||||
|
@ -476,32 +478,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crypto-common"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "data-encoding"
|
|
||||||
version = "2.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "digest"
|
|
||||||
version = "0.10.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|
||||||
dependencies = [
|
|
||||||
"block-buffer",
|
|
||||||
"crypto-common",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.33"
|
version = "0.8.33"
|
||||||
|
@ -712,16 +688,6 @@ dependencies = [
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "generic-array"
|
|
||||||
version = "0.14.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
|
||||||
dependencies = [
|
|
||||||
"typenum",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
@ -782,30 +748,6 @@ version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "headers"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"bytes",
|
|
||||||
"headers-core",
|
|
||||||
"http",
|
|
||||||
"httpdate",
|
|
||||||
"mime",
|
|
||||||
"sha1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "headers-core"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
|
|
||||||
dependencies = [
|
|
||||||
"http",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -855,6 +797,12 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-range-header"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -1065,16 +1013,6 @@ version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mime_guess"
|
|
||||||
version = "2.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
|
||||||
dependencies = [
|
|
||||||
"mime",
|
|
||||||
"unicase",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -1110,7 +1048,6 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower",
|
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1127,10 +1064,8 @@ dependencies = [
|
||||||
"mp4",
|
"mp4",
|
||||||
"quinn",
|
"quinn",
|
||||||
"rfc6381-codec",
|
"rfc6381-codec",
|
||||||
"ring",
|
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
"rustls-pemfile",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
|
@ -1142,6 +1077,8 @@ name = "moq-relay"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"axum",
|
||||||
|
"axum-server",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"hex",
|
"hex",
|
||||||
|
@ -1149,16 +1086,17 @@ dependencies = [
|
||||||
"moq-api",
|
"moq-api",
|
||||||
"moq-transport",
|
"moq-transport",
|
||||||
"quinn",
|
"quinn",
|
||||||
"ring",
|
"ring 0.16.20",
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
"rustls-pemfile",
|
"rustls-pemfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tower-http",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"url",
|
"url",
|
||||||
"warp",
|
"webpki",
|
||||||
"webtransport-quinn",
|
"webtransport-quinn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1204,24 +1142,6 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96a1fe2275b68991faded2c80aa4a33dba398b77d276038b8f50701a22e55918"
|
checksum = "96a1fe2275b68991faded2c80aa4a33dba398b77d276038b8f50701a22e55918"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "multer"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"encoding_rs",
|
|
||||||
"futures-util",
|
|
||||||
"http",
|
|
||||||
"httparse",
|
|
||||||
"log",
|
|
||||||
"memchr",
|
|
||||||
"mime",
|
|
||||||
"spin 0.9.8",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
|
@ -1497,7 +1417,7 @@ checksum = "e13f81c9a9d574310b8351f8666f5a93ac3b0069c45c28ad52c10291389a7cf9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"rand",
|
"rand",
|
||||||
"ring",
|
"ring 0.16.20",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
|
@ -1688,11 +1608,25 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"spin 0.5.2",
|
"spin 0.5.2",
|
||||||
"untrusted",
|
"untrusted 0.7.1",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"getrandom",
|
||||||
|
"libc",
|
||||||
|
"spin 0.9.8",
|
||||||
|
"untrusted 0.9.0",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roff"
|
name = "roff"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1745,7 +1679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8"
|
checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"ring",
|
"ring 0.16.20",
|
||||||
"rustls-webpki",
|
"rustls-webpki",
|
||||||
"sct",
|
"sct",
|
||||||
]
|
]
|
||||||
|
@ -1777,8 +1711,8 @@ version = "0.101.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d"
|
checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring 0.16.20",
|
||||||
"untrusted",
|
"untrusted 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1802,12 +1736,6 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scoped-tls"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -1820,8 +1748,8 @@ version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring 0.16.20",
|
||||||
"untrusted",
|
"untrusted 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1900,17 +1828,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha1"
|
|
||||||
version = "0.10.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cpufeatures",
|
|
||||||
"digest",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1_smol"
|
name = "sha1_smol"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -2154,29 +2071,6 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-stream"
|
|
||||||
version = "0.1.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-tungstenite"
|
|
||||||
version = "0.20.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c"
|
|
||||||
dependencies = [
|
|
||||||
"futures-util",
|
|
||||||
"log",
|
|
||||||
"tokio",
|
|
||||||
"tungstenite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.8"
|
version = "0.7.8"
|
||||||
|
@ -2207,6 +2101,24 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-http"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.0",
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-range-header",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-layer"
|
name = "tower-layer"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -2284,40 +2196,6 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tungstenite"
|
|
||||||
version = "0.20.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"bytes",
|
|
||||||
"data-encoding",
|
|
||||||
"http",
|
|
||||||
"httparse",
|
|
||||||
"log",
|
|
||||||
"rand",
|
|
||||||
"sha1",
|
|
||||||
"thiserror",
|
|
||||||
"url",
|
|
||||||
"utf-8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicase"
|
|
||||||
version = "2.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
|
||||||
dependencies = [
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.13"
|
version = "0.3.13"
|
||||||
|
@ -2345,6 +2223,12 @@ version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
|
@ -2357,12 +2241,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "utf-8"
|
|
||||||
version = "0.7.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -2387,12 +2265,6 @@ version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waker-fn"
|
name = "waker-fn"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -2408,38 +2280,6 @@ dependencies = [
|
||||||
"try-lock",
|
"try-lock",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "warp"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"futures-channel",
|
|
||||||
"futures-util",
|
|
||||||
"headers",
|
|
||||||
"http",
|
|
||||||
"hyper",
|
|
||||||
"log",
|
|
||||||
"mime",
|
|
||||||
"mime_guess",
|
|
||||||
"multer",
|
|
||||||
"percent-encoding",
|
|
||||||
"pin-project",
|
|
||||||
"rustls-pemfile",
|
|
||||||
"scoped-tls",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_urlencoded",
|
|
||||||
"tokio",
|
|
||||||
"tokio-rustls",
|
|
||||||
"tokio-stream",
|
|
||||||
"tokio-tungstenite",
|
|
||||||
"tokio-util",
|
|
||||||
"tower-service",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -2522,6 +2362,16 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53"
|
||||||
|
dependencies = [
|
||||||
|
"ring 0.17.3",
|
||||||
|
"untrusted 0.9.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.25.2"
|
version = "0.25.2"
|
||||||
|
|
|
@ -19,7 +19,6 @@ categories = ["multimedia", "network-programming", "web-programming"]
|
||||||
axum = "0.6"
|
axum = "0.6"
|
||||||
hyper = { version = "0.14", features = ["full"] }
|
hyper = { version = "0.14", features = ["full"] }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tower = "0.4"
|
|
||||||
|
|
||||||
# HTTP client
|
# HTTP client
|
||||||
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
|
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
|
||||||
|
|
|
@ -23,9 +23,7 @@ webtransport-quinn = "0.6"
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|
||||||
# Crypto
|
# Crypto
|
||||||
ring = "0.16"
|
|
||||||
rustls = "0.21"
|
rustls = "0.21"
|
||||||
rustls-pemfile = "1"
|
|
||||||
rustls-native-certs = "0.6"
|
rustls-native-certs = "0.6"
|
||||||
|
|
||||||
# Async stuff
|
# Async stuff
|
||||||
|
|
|
@ -26,13 +26,16 @@ ring = "0.16"
|
||||||
rustls = "0.21"
|
rustls = "0.21"
|
||||||
rustls-pemfile = "1"
|
rustls-pemfile = "1"
|
||||||
rustls-native-certs = "0.6"
|
rustls-native-certs = "0.6"
|
||||||
|
webpki = "0.22"
|
||||||
|
|
||||||
# Async stuff
|
# Async stuff
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
||||||
# Web server to serve the fingerprint
|
# Web server to serve the fingerprint
|
||||||
warp = { version = "0.3.6", features = ["tls"] }
|
axum = { version = "0.6", features = ["tokio"] }
|
||||||
|
axum-server = { version = "0.5", features = ["tls-rustls"] }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
tower-http = { version = "0.4", features = ["cors"] }
|
||||||
|
|
||||||
# Error handling
|
# Error handling
|
||||||
anyhow = { version = "1", features = ["backtrace"] }
|
anyhow = { version = "1", features = ["backtrace"] }
|
||||||
|
|
|
@ -10,13 +10,19 @@ pub struct Config {
|
||||||
#[arg(long, default_value = "[::]:4443")]
|
#[arg(long, default_value = "[::]:4443")]
|
||||||
pub listen: net::SocketAddr,
|
pub listen: net::SocketAddr,
|
||||||
|
|
||||||
/// Use the certificate file at this path
|
/// Use the certificates at this path, encoded as PEM.
|
||||||
|
///
|
||||||
|
/// You can use this option multiple times for multiple certificates.
|
||||||
|
/// The first match for the provided SNI will be used, otherwise the last cert will be used.
|
||||||
|
/// You also need to provide the private key multiple times via `key``.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub cert: path::PathBuf,
|
pub cert: Vec<path::PathBuf>,
|
||||||
|
|
||||||
/// Use the private key at this path
|
/// Use the private key at this path, encoded as PEM.
|
||||||
|
///
|
||||||
|
/// There must be a key for every certificate provided via `cert`.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub key: path::PathBuf,
|
pub key: Vec<path::PathBuf>,
|
||||||
|
|
||||||
/// Listen on HTTPS and serve /fingerprint, for self-signed certificates
|
/// Listen on HTTPS and serve /fingerprint, for self-signed certificates
|
||||||
#[arg(long, action)]
|
#[arg(long, action)]
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use std::{fs, io, sync};
|
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use ring::digest::{digest, SHA256};
|
|
||||||
use warp::Filter;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod error;
|
mod error;
|
||||||
mod origin;
|
mod origin;
|
||||||
mod server;
|
mod quic;
|
||||||
mod session;
|
mod session;
|
||||||
|
mod tls;
|
||||||
|
mod web;
|
||||||
|
|
||||||
pub use config::*;
|
pub use config::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use origin::*;
|
pub use origin::*;
|
||||||
pub use server::*;
|
pub use quic::*;
|
||||||
pub use session::*;
|
pub use session::*;
|
||||||
|
pub use tls::*;
|
||||||
|
pub use web::*;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
@ -28,47 +28,20 @@ async fn main() -> anyhow::Result<()> {
|
||||||
tracing::subscriber::set_global_default(tracer).unwrap();
|
tracing::subscriber::set_global_default(tracer).unwrap();
|
||||||
|
|
||||||
let config = Config::parse();
|
let config = Config::parse();
|
||||||
|
let tls = Tls::load(&config)?;
|
||||||
|
|
||||||
// Create a server to actually serve the media
|
// Create a QUIC server for media.
|
||||||
let server = Server::new(config.clone()).await.context("failed to create server")?;
|
let quic = Quic::new(config.clone(), tls.clone())
|
||||||
|
.await
|
||||||
|
.context("failed to create server")?;
|
||||||
|
|
||||||
|
// Create the web server if the --fingerprint flag was set.
|
||||||
|
// This is currently only useful in local development so it's not enabled by default.
|
||||||
|
let web = config.fingerprint.then(|| Web::new(config, tls));
|
||||||
|
|
||||||
// Run all of the above
|
// Run all of the above
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
res = server.run() => res.context("failed to run server"),
|
res = quic.serve() => res.context("failed to run server"),
|
||||||
res = serve_http(config), if config.fingerprint => res.context("failed to run HTTP server"),
|
res = web.unwrap().serve(), if web.is_some() => res.context("failed to run HTTP server"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a HTTP server using Warp
|
|
||||||
// TODO remove this when Chrome adds support for self-signed certificates using WebTransport
|
|
||||||
async fn serve_http(config: Config) -> anyhow::Result<()> {
|
|
||||||
// Read the PEM certificate file
|
|
||||||
let crt = fs::File::open(&config.cert)?;
|
|
||||||
let mut crt = io::BufReader::new(crt);
|
|
||||||
|
|
||||||
// Parse the DER certificate
|
|
||||||
let certs = rustls_pemfile::certs(&mut crt)?;
|
|
||||||
let cert = certs.first().expect("no certificate found");
|
|
||||||
|
|
||||||
// Compute the SHA-256 digest
|
|
||||||
let fingerprint = digest(&SHA256, cert.as_ref());
|
|
||||||
let fingerprint = hex::encode(fingerprint.as_ref());
|
|
||||||
let fingerprint = sync::Arc::new(fingerprint);
|
|
||||||
|
|
||||||
let cors = warp::cors().allow_any_origin();
|
|
||||||
|
|
||||||
// What an annoyingly complicated way to serve a static String
|
|
||||||
// I spent a long time trying to find the exact way of cloning and dereferencing the Arc.
|
|
||||||
let routes = warp::path!("fingerprint")
|
|
||||||
.map(move || (*(fingerprint.clone())).clone())
|
|
||||||
.with(cors);
|
|
||||||
|
|
||||||
warp::serve(routes)
|
|
||||||
.tls()
|
|
||||||
.cert_path(config.cert)
|
|
||||||
.key_path(config.key)
|
|
||||||
.run(config.listen)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
use std::{
|
use std::{sync::Arc, time};
|
||||||
fs,
|
|
||||||
io::{self, Read},
|
|
||||||
sync::Arc,
|
|
||||||
time,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
|
|
||||||
use crate::{Config, Origin, Session};
|
use crate::{Config, Origin, Session, Tls};
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Quic {
|
||||||
quic: quinn::Endpoint,
|
quic: quinn::Endpoint,
|
||||||
|
|
||||||
// The active connections.
|
// The active connections.
|
||||||
|
@ -21,65 +16,11 @@ pub struct Server {
|
||||||
origin: Origin,
|
origin: Origin,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Quic {
|
||||||
// Create a new server
|
// Create a QUIC endpoint that can be used for both clients and servers.
|
||||||
pub async fn new(config: Config) -> anyhow::Result<Self> {
|
pub async fn new(config: Config, tls: Tls) -> anyhow::Result<Self> {
|
||||||
// Read the PEM certificate chain
|
let mut client_config = tls.client();
|
||||||
let certs = fs::File::open(config.cert).context("failed to open cert file")?;
|
let mut server_config = tls.server();
|
||||||
let mut certs = io::BufReader::new(certs);
|
|
||||||
|
|
||||||
let certs: Vec<rustls::Certificate> = rustls_pemfile::certs(&mut certs)?
|
|
||||||
.into_iter()
|
|
||||||
.map(rustls::Certificate)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
anyhow::ensure!(!certs.is_empty(), "could not find certificate");
|
|
||||||
|
|
||||||
// Read the PEM private key
|
|
||||||
let mut keys = fs::File::open(config.key).context("failed to open key file")?;
|
|
||||||
|
|
||||||
// Read the keys into a Vec so we can try parsing it twice.
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
keys.read_to_end(&mut buf)?;
|
|
||||||
|
|
||||||
// Try to parse a PKCS#8 key
|
|
||||||
// -----BEGIN PRIVATE KEY-----
|
|
||||||
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut io::Cursor::new(&buf))?;
|
|
||||||
|
|
||||||
// Try again but with EC keys this time
|
|
||||||
// -----BEGIN EC PRIVATE KEY-----
|
|
||||||
if keys.is_empty() {
|
|
||||||
keys = rustls_pemfile::ec_private_keys(&mut io::Cursor::new(&buf))?
|
|
||||||
};
|
|
||||||
|
|
||||||
anyhow::ensure!(!keys.is_empty(), "could not find private key");
|
|
||||||
anyhow::ensure!(keys.len() < 2, "expected a single key");
|
|
||||||
|
|
||||||
let key = rustls::PrivateKey(keys.remove(0));
|
|
||||||
|
|
||||||
// Set up a QUIC endpoint that can act as both a client and server.
|
|
||||||
|
|
||||||
// Create a list of acceptable root certificates.
|
|
||||||
let mut client_roots = rustls::RootCertStore::empty();
|
|
||||||
|
|
||||||
// Add the platform's native root certificates.
|
|
||||||
for cert in rustls_native_certs::load_native_certs().context("could not load platform certs")? {
|
|
||||||
client_roots
|
|
||||||
.add(&rustls::Certificate(cert.0))
|
|
||||||
.context("failed to add root cert")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For local development, we'll accept our own certificate.
|
|
||||||
let mut client_config = rustls::ClientConfig::builder()
|
|
||||||
.with_safe_defaults()
|
|
||||||
.with_root_certificates(client_roots)
|
|
||||||
.with_no_client_auth();
|
|
||||||
|
|
||||||
let mut server_config = rustls::ServerConfig::builder()
|
|
||||||
.with_safe_defaults()
|
|
||||||
.with_no_client_auth()
|
|
||||||
.with_single_cert(certs, key)?;
|
|
||||||
|
|
||||||
client_config.alpn_protocols = vec![webtransport_quinn::ALPN.to_vec()];
|
client_config.alpn_protocols = vec![webtransport_quinn::ALPN.to_vec()];
|
||||||
server_config.alpn_protocols = vec![webtransport_quinn::ALPN.to_vec()];
|
server_config.alpn_protocols = vec![webtransport_quinn::ALPN.to_vec()];
|
||||||
|
|
||||||
|
@ -121,7 +62,7 @@ impl Server {
|
||||||
Ok(Self { quic, origin, conns })
|
Ok(Self { quic, origin, conns })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(mut self) -> anyhow::Result<()> {
|
pub async fn serve(mut self) -> anyhow::Result<()> {
|
||||||
log::info!("listening on {}", self.quic.local_addr()?);
|
log::info!("listening on {}", self.quic.local_addr()?);
|
||||||
|
|
||||||
loop {
|
loop {
|
|
@ -0,0 +1,152 @@
|
||||||
|
use anyhow::Context;
|
||||||
|
use ring::digest::{digest, SHA256};
|
||||||
|
use rustls::server::{ClientHello, ResolvesServerCert};
|
||||||
|
use rustls::sign::CertifiedKey;
|
||||||
|
use rustls::{Certificate, PrivateKey, RootCertStore};
|
||||||
|
use rustls::{ClientConfig, ServerConfig};
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{self, Cursor, Read};
|
||||||
|
use std::path;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use webpki::{DnsNameRef, EndEntityCert};
|
||||||
|
|
||||||
|
use crate::Config;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Tls {
|
||||||
|
// Support serving multiple certificates, choosing one that looks valid for the given SNI.
|
||||||
|
// We store the parsed certificate, and the certified cert/key that rustls expects
|
||||||
|
serve: Arc<ServeCerts>,
|
||||||
|
|
||||||
|
// Accept any cert that is trusted by the system's native trust store.
|
||||||
|
accept: Arc<RootCertStore>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tls {
|
||||||
|
pub fn load(config: &Config) -> anyhow::Result<Self> {
|
||||||
|
let mut serve = ServeCerts::default();
|
||||||
|
|
||||||
|
// Load the certificate and key files based on their index.
|
||||||
|
anyhow::ensure!(config.cert.len() == config.key.len(), "--cert and --key mismatch");
|
||||||
|
for (chain, key) in config.cert.iter().zip(config.key.iter()) {
|
||||||
|
serve.load(chain, key)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a list of acceptable root certificates.
|
||||||
|
let mut roots = RootCertStore::empty();
|
||||||
|
|
||||||
|
// Add the platform's native root certificates.
|
||||||
|
for cert in rustls_native_certs::load_native_certs().context("could not load platform certs")? {
|
||||||
|
roots.add(&Certificate(cert.0)).context("failed to add root cert")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let certs = Self {
|
||||||
|
serve: Arc::new(serve),
|
||||||
|
accept: Arc::new(roots),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(certs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn client(&self) -> ClientConfig {
|
||||||
|
rustls::ClientConfig::builder()
|
||||||
|
.with_safe_defaults()
|
||||||
|
.with_root_certificates(self.accept.clone())
|
||||||
|
.with_no_client_auth()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn server(&self) -> ServerConfig {
|
||||||
|
rustls::ServerConfig::builder()
|
||||||
|
.with_safe_defaults()
|
||||||
|
.with_no_client_auth()
|
||||||
|
.with_cert_resolver(self.serve.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the SHA256 fingerprint of our certificates.
|
||||||
|
pub fn fingerprints(&self) -> Vec<String> {
|
||||||
|
self.serve.fingerprints()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct ServeCerts {
|
||||||
|
list: Vec<Arc<CertifiedKey>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServeCerts {
|
||||||
|
// Load a certificate and cooresponding key from a file
|
||||||
|
pub fn load(&mut self, chain: &path::PathBuf, key: &path::PathBuf) -> anyhow::Result<()> {
|
||||||
|
// Read the PEM certificate chain
|
||||||
|
let chain = fs::File::open(chain).context("failed to open cert file")?;
|
||||||
|
let mut chain = io::BufReader::new(chain);
|
||||||
|
|
||||||
|
let chain: Vec<Certificate> = rustls_pemfile::certs(&mut chain)?
|
||||||
|
.into_iter()
|
||||||
|
.map(Certificate)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
anyhow::ensure!(!chain.is_empty(), "could not find certificate");
|
||||||
|
|
||||||
|
// Read the PEM private key
|
||||||
|
let mut keys = fs::File::open(key).context("failed to open key file")?;
|
||||||
|
|
||||||
|
// Read the keys into a Vec so we can parse it twice.
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
keys.read_to_end(&mut buf)?;
|
||||||
|
|
||||||
|
// Try to parse a PKCS#8 key
|
||||||
|
// -----BEGIN PRIVATE KEY-----
|
||||||
|
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut Cursor::new(&buf))?;
|
||||||
|
|
||||||
|
// Try again but with EC keys this time
|
||||||
|
// -----BEGIN EC PRIVATE KEY-----
|
||||||
|
if keys.is_empty() {
|
||||||
|
keys = rustls_pemfile::ec_private_keys(&mut Cursor::new(&buf))?
|
||||||
|
};
|
||||||
|
|
||||||
|
anyhow::ensure!(!keys.is_empty(), "could not find private key");
|
||||||
|
anyhow::ensure!(keys.len() < 2, "expected a single key");
|
||||||
|
|
||||||
|
let key = PrivateKey(keys.remove(0));
|
||||||
|
let key = rustls::sign::any_supported_type(&key)?;
|
||||||
|
|
||||||
|
let certified = Arc::new(CertifiedKey::new(chain, key));
|
||||||
|
self.list.push(certified);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the SHA256 fingerprint of our certificates.
|
||||||
|
pub fn fingerprints(&self) -> Vec<String> {
|
||||||
|
self.list
|
||||||
|
.iter()
|
||||||
|
.map(|ck| {
|
||||||
|
let fingerprint = digest(&SHA256, ck.cert[0].as_ref());
|
||||||
|
let fingerprint = hex::encode(fingerprint.as_ref());
|
||||||
|
fingerprint
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResolvesServerCert for ServeCerts {
|
||||||
|
fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
|
||||||
|
if let Some(name) = client_hello.server_name() {
|
||||||
|
if let Ok(dns_name) = DnsNameRef::try_from_ascii_str(name) {
|
||||||
|
for ck in &self.list {
|
||||||
|
// TODO I gave up on caching the parsed result because of lifetime hell.
|
||||||
|
// If this shows up on benchmarks, somebody should fix it.
|
||||||
|
let leaf = ck.cert.first().expect("missing certificate");
|
||||||
|
let parsed = EndEntityCert::try_from(leaf.0.as_ref()).expect("failed to parse certificate");
|
||||||
|
|
||||||
|
if parsed.verify_is_valid_for_dns_name(dns_name).is_ok() {
|
||||||
|
return Some(ck.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to the last certificate if we couldn't find one.
|
||||||
|
self.list.last().cloned()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use axum::{extract::State, http::Method, response::IntoResponse, routing::get, Router};
|
||||||
|
use axum_server::{tls_rustls::RustlsAcceptor, Server};
|
||||||
|
use tower_http::cors::{Any, CorsLayer};
|
||||||
|
|
||||||
|
use crate::{Config, Tls};
|
||||||
|
|
||||||
|
// Run a HTTP server using Axum
|
||||||
|
// TODO remove this when Chrome adds support for self-signed certificates using WebTransport
|
||||||
|
pub struct Web {
|
||||||
|
app: Router,
|
||||||
|
server: Server<RustlsAcceptor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Web {
|
||||||
|
pub fn new(config: Config, tls: Tls) -> Self {
|
||||||
|
// Get the first certificate's fingerprint.
|
||||||
|
// TODO serve all of them so we can support multiple signature algorithms.
|
||||||
|
let fingerprint = tls.fingerprints().first().expect("missing certificate").clone();
|
||||||
|
|
||||||
|
let mut tls_config = tls.server();
|
||||||
|
tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
||||||
|
let tls_config = axum_server::tls_rustls::RustlsConfig::from_config(Arc::new(tls_config));
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.route("/fingerprint", get(serve_fingerprint))
|
||||||
|
.layer(CorsLayer::new().allow_origin(Any).allow_methods([Method::GET]))
|
||||||
|
.with_state(fingerprint);
|
||||||
|
|
||||||
|
let server = axum_server::bind_rustls(config.listen, tls_config);
|
||||||
|
|
||||||
|
Self { app, server }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn serve(self) -> anyhow::Result<()> {
|
||||||
|
self.server.serve(self.app.into_make_service()).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn serve_fingerprint(State(fingerprint): State<String>) -> impl IntoResponse {
|
||||||
|
fingerprint
|
||||||
|
}
|
Loading…
Reference in New Issue