mumble_server_runtime_gateway/
tls.rs

1//! Server-side TLS setup.
2//!
3//! The control channel is TLS, like Murmur. We pin TLS 1.2 for the same reason
4//! the P2 proxy does: the macOS Qt/OpenSSL Mumble client segfaults in its
5//! post-handshake introspection when handed a TLS 1.3 session, and Murmur itself
6//! negotiates 1.2 by default. See `docs/STATUS.md` (macOS client trap).
7
8use std::sync::Arc;
9
10use anyhow::{Context, Result};
11use rustls::crypto::{WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature};
12use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, UnixTime};
13use rustls::server::ParsedCertificate;
14use rustls::server::danger::{ClientCertVerified, ClientCertVerifier};
15use rustls::{
16    DigitallySignedStruct, DistinguishedName, Error as TlsError, ServerConfig, SignatureScheme,
17};
18use tokio::net::TcpStream;
19use tokio_rustls::server::TlsStream;
20
21/// Requests a client certificate for identity while accepting anonymous clients.
22///
23/// A self-signed certificate is an identity proof, not an authorization proof.
24/// The TLS CertificateVerify signature still proves possession of its private
25/// key. Authentication and principal binding remain outside Phase 6.
26///
27/// REF: references/mumble/src/murmur/Server.cpp:Server::sslError
28/// REF: references/mumble/src/murmur/Server.cpp:Server::encrypted
29#[derive(Debug)]
30struct MumbleClientCertificateVerifier {
31    algorithms: WebPkiSupportedAlgorithms,
32}
33
34impl ClientCertVerifier for MumbleClientCertificateVerifier {
35    fn client_auth_mandatory(&self) -> bool {
36        false
37    }
38
39    fn root_hint_subjects(&self) -> &[DistinguishedName] {
40        &[]
41    }
42
43    fn verify_client_cert(
44        &self,
45        end_entity: &CertificateDer<'_>,
46        _intermediates: &[CertificateDer<'_>],
47        _now: UnixTime,
48    ) -> Result<ClientCertVerified, TlsError> {
49        ParsedCertificate::try_from(end_entity).map(|_| ClientCertVerified::assertion())
50    }
51
52    fn verify_tls12_signature(
53        &self,
54        message: &[u8],
55        certificate: &CertificateDer<'_>,
56        signature: &DigitallySignedStruct,
57    ) -> Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {
58        verify_tls12_signature(message, certificate, signature, &self.algorithms)
59    }
60
61    fn verify_tls13_signature(
62        &self,
63        message: &[u8],
64        certificate: &CertificateDer<'_>,
65        signature: &DigitallySignedStruct,
66    ) -> Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {
67        verify_tls13_signature(message, certificate, signature, &self.algorithms)
68    }
69
70    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
71        self.algorithms.supported_schemes()
72    }
73}
74
75/// Install the ring crypto provider as the process default. Idempotent.
76pub fn install_crypto_provider() {
77    let _ignored = rustls::crypto::ring::default_provider().install_default();
78}
79
80/// A TLS certificate and its private key, in DER.
81pub struct Identity {
82    pub cert: CertificateDer<'static>,
83    pub key: PrivateKeyDer<'static>,
84}
85
86impl Identity {
87    /// Generate a fresh self-signed certificate for the given DNS names. Enough
88    /// for local development and the in-process integration tests; a real
89    /// deployment supplies a persistent certificate so the client's per-server
90    /// certificate hash (spec ยง21.2) stays stable.
91    pub fn self_signed(names: Vec<String>) -> Result<Self> {
92        let certified = rcgen::generate_simple_self_signed(names)
93            .context("generating self-signed certificate")?;
94        let cert = certified.cert.der().clone();
95        let key =
96            PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(certified.key_pair.serialize_der()));
97        Ok(Self { cert, key })
98    }
99}
100
101/// Build the server TLS config from an identity, pinned to TLS 1.2.
102///
103/// REF: references/mumble/src/mumble/ServerHandler.cpp:ServerHandler::ServerHandler
104/// REF: references/mumble/src/murmur/Server.cpp:Server::encrypted
105pub fn server_config(identity: Identity) -> Result<Arc<ServerConfig>> {
106    let algorithms = rustls::crypto::ring::default_provider().signature_verification_algorithms;
107    let verifier = Arc::new(MumbleClientCertificateVerifier { algorithms });
108    let config = ServerConfig::builder_with_protocol_versions(&[&rustls::version::TLS12])
109        .with_client_cert_verifier(verifier)
110        .with_single_cert(vec![identity.cert], identity.key)
111        .context("building server TLS config")?;
112    Ok(Arc::new(config))
113}
114
115/// Return Murmur's lowercase SHA-1 digest of the immediate client certificate.
116///
117/// This value is only presented in `UserState.hash` so the official client can
118/// retain local preferences. It does not grant permissions.
119///
120/// REF: references/vendored/Mumble.proto:UserState.hash
121/// REF: references/mumble/src/murmur/Server.cpp:Server::encrypted
122pub fn client_certificate_hash(stream: &TlsStream<TcpStream>) -> Option<String> {
123    const HEX: &[u8; 16] = b"0123456789abcdef";
124
125    let certificate = stream.get_ref().1.peer_certificates()?.first()?;
126    let digest = ring::digest::digest(
127        &ring::digest::SHA1_FOR_LEGACY_USE_ONLY,
128        certificate.as_ref(),
129    );
130    let mut encoded = String::with_capacity(digest.as_ref().len().checked_mul(2)?);
131    for byte in digest.as_ref() {
132        let high = HEX.get(usize::from(byte >> 4)).copied()?;
133        let low = HEX.get(usize::from(byte & 0x0f)).copied()?;
134        encoded.push(char::from(high));
135        encoded.push(char::from(low));
136    }
137    Some(encoded)
138}