Make it possible to disable certificate verification
This commit is contained in:
parent
3f27c90489
commit
c68a7cbe0a
|
@ -755,12 +755,15 @@ dependencies = [
|
|||
"jitsi-xmpp-parsers",
|
||||
"libc",
|
||||
"maplit",
|
||||
"native-tls",
|
||||
"nice-gst-meet",
|
||||
"once_cell",
|
||||
"pem",
|
||||
"rand",
|
||||
"rcgen",
|
||||
"ring",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
|
@ -769,6 +772,7 @@ dependencies = [
|
|||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
"webpki-roots",
|
||||
"xmpp-parsers",
|
||||
]
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ tracing = { version = "0.1", default-features = false, features = ["attributes",
|
|||
cocoa = { version = "0.24", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["tls-native"]
|
||||
default = ["tls-rustls-native-roots"]
|
||||
tls-insecure = ["lib-gst-meet/tls-insecure"]
|
||||
tls-native = ["lib-gst-meet/tls-native"]
|
||||
tls-native-vendored = ["lib-gst-meet/tls-native-vendored"]
|
||||
tls-rustls-native-roots = ["lib-gst-meet/tls-rustls-native-roots"]
|
||||
|
|
|
@ -45,13 +45,16 @@ struct Opt {
|
|||
#[structopt(long)]
|
||||
select_endpoints: Option<String>,
|
||||
#[structopt(long)]
|
||||
last_n: Option<i32>,
|
||||
last_n: Option<u16>,
|
||||
#[structopt(long)]
|
||||
recv_video_height: Option<i32>,
|
||||
recv_video_height: Option<u16>,
|
||||
#[structopt(long)]
|
||||
video_type: Option<String>,
|
||||
#[structopt(short, long, parse(from_occurrences))]
|
||||
verbose: u8,
|
||||
#[cfg(feature = "tls-insecure")]
|
||||
#[structopt(long, help = "Disable TLS certificate verification (use with extreme caution)")]
|
||||
tls_insecure: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
|
@ -117,9 +120,13 @@ async fn main_inner() -> Result<()> {
|
|||
&opt.web_socket_url,
|
||||
&opt.xmpp_domain,
|
||||
Authentication::Anonymous,
|
||||
#[cfg(feature = "tls-insecure")]
|
||||
opt.tls_insecure,
|
||||
#[cfg(not(feature = "tls-insecure"))]
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.context("failed to connect")?;
|
||||
.context("failed to build connection")?;
|
||||
|
||||
tokio::spawn(background);
|
||||
|
||||
|
@ -165,13 +172,13 @@ async fn main_inner() -> Result<()> {
|
|||
if opt.select_endpoints.is_some() || opt.last_n.is_some() || opt.recv_video_height.is_some() {
|
||||
conference
|
||||
.send_colibri_message(ColibriMessage::ReceiverVideoConstraints {
|
||||
last_n: opt.last_n,
|
||||
last_n: Some(opt.last_n.map(i32::from).unwrap_or(-1)),
|
||||
selected_endpoints: opt
|
||||
.select_endpoints
|
||||
.map(|endpoints| endpoints.split(',').map(ToOwned::to_owned).collect()),
|
||||
on_stage_endpoints: None,
|
||||
default_constraints: opt.recv_video_height.map(|height| Constraints {
|
||||
max_height: Some(height),
|
||||
max_height: Some(height.into()),
|
||||
ideal_height: None,
|
||||
}),
|
||||
constraints: None,
|
||||
|
|
|
@ -39,7 +39,8 @@ void gstmeet_deinit(struct Context *context);
|
|||
|
||||
JitsiConnection *gstmeet_connection_new(struct Context *context,
|
||||
const char *websocket_url,
|
||||
const char *xmpp_domain);
|
||||
const char *xmpp_domain,
|
||||
bool tls_insecure);
|
||||
|
||||
void gstmeet_connection_free(JitsiConnection *connection);
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ pub unsafe extern "C" fn gstmeet_connection_new(
|
|||
context: *mut Context,
|
||||
websocket_url: *const c_char,
|
||||
xmpp_domain: *const c_char,
|
||||
tls_insecure: bool,
|
||||
) -> *mut Connection {
|
||||
let websocket_url = CStr::from_ptr(websocket_url);
|
||||
let xmpp_domain = CStr::from_ptr(xmpp_domain);
|
||||
|
@ -89,6 +90,7 @@ pub unsafe extern "C" fn gstmeet_connection_new(
|
|||
&websocket_url.to_string_lossy(),
|
||||
&xmpp_domain.to_string_lossy(),
|
||||
Authentication::Anonymous,
|
||||
tls_insecure,
|
||||
))
|
||||
.map(|(connection, background)| {
|
||||
(*context).runtime.spawn(background);
|
||||
|
|
|
@ -25,12 +25,15 @@ itertools = { version = "0.10", default-features = false, features = ["use_std"]
|
|||
jitsi-xmpp-parsers = { version = "0.1", path = "../jitsi-xmpp-parsers", default-features = false }
|
||||
libc = { version = "0.2", default-features = false }
|
||||
maplit = { version = "1", default-features = false }
|
||||
native-tls = { version = "0.2", default-features = false, optional = true }
|
||||
nice-gst-meet = { version = "0.1", path = "../nice-gst-meet", default-features = false, features = ["v0_1_18"] }
|
||||
once_cell = { version = "1", default-features = false, features = ["std"] }
|
||||
pem = { version = "1", default-features = false }
|
||||
rand = { version = "0.8", default-features = false, features = ["std", "std_rng"] }
|
||||
rcgen = { version = "0.9", default-features = false }
|
||||
ring = { version = "0.16", default-features = false }
|
||||
rustls = { version = "0.20", default-features = false, features = ["logging", "tls12"], optional = true }
|
||||
rustls-native-certs = { version = "0.6", default-features = false, optional = true }
|
||||
serde = { version = "1", default-features = false, features = ["derive"] }
|
||||
serde_json = { version = "1", default-features = false, features = ["std"] }
|
||||
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "macros", "sync", "time"] }
|
||||
|
@ -45,11 +48,15 @@ tracing-subscriber = { version = "0.3", optional = true, default-features = fals
|
|||
"tracing-log",
|
||||
] }
|
||||
uuid = { version = "0.8", default-features = false, features = ["v4"] }
|
||||
webpki-roots = { version = "0.22", default-features = false, optional = true }
|
||||
xmpp-parsers = { git = "https://gitlab.com/xmpp-rs/xmpp-rs.git", default-features = false, features = ["disable-validation"] }
|
||||
|
||||
[features]
|
||||
default = ["tls-native"]
|
||||
tls-native = ["tokio-tungstenite/native-tls"]
|
||||
tls-native-vendored = ["tokio-tungstenite/native-tls-vendored"]
|
||||
tls-rustls-native-roots = ["tokio-tungstenite/rustls-tls-native-roots"]
|
||||
tls-rustls-webpki-roots = ["tokio-tungstenite/rustls-tls-webpki-roots"]
|
||||
# Ideally we would enable rustls/dangerous_configuration only when tls-insecure is enabled, but until weak-dep-features is stabilised, that
|
||||
# would cause rustls to always be pulled in.
|
||||
default = ["tls-rustls-native-roots"]
|
||||
tls-insecure = []
|
||||
tls-native = ["tokio-tungstenite/native-tls", "native-tls"]
|
||||
tls-native-vendored = ["tokio-tungstenite/native-tls-vendored", "native-tls/vendored"]
|
||||
tls-rustls-native-roots = ["tokio-tungstenite/rustls-tls-native-roots", "rustls", "rustls-native-certs", "rustls/dangerous_configuration"]
|
||||
tls-rustls-webpki-roots = ["tokio-tungstenite/rustls-tls-webpki-roots", "rustls", "webpki-roots", "rustls/dangerous_configuration"]
|
||||
|
|
|
@ -18,6 +18,8 @@ use tokio_tungstenite::tungstenite::{
|
|||
};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use crate::tls::wss_connector;
|
||||
|
||||
const MAX_CONNECT_RETRIES: u8 = 3;
|
||||
const CONNECT_RETRY_SLEEP: Duration = Duration::from_secs(3);
|
||||
|
||||
|
@ -27,7 +29,7 @@ pub(crate) struct ColibriChannel {
|
|||
}
|
||||
|
||||
impl ColibriChannel {
|
||||
pub(crate) async fn new(uri: &str) -> Result<Self> {
|
||||
pub(crate) async fn new(uri: &str, tls_insecure: bool) -> Result<Self> {
|
||||
let uri: Uri = uri.parse()?;
|
||||
let host = uri.host().context("invalid WebSocket URL: missing host")?;
|
||||
|
||||
|
@ -44,7 +46,7 @@ impl ColibriChannel {
|
|||
.header("connection", "Upgrade")
|
||||
.header("upgrade", "websocket")
|
||||
.body(())?;
|
||||
match tokio_tungstenite::connect_async(request).await {
|
||||
match tokio_tungstenite::connect_async_tls_with_config(request, None, Some(wss_connector(tls_insecure)?)).await {
|
||||
Ok((websocket, _)) => break websocket,
|
||||
Err(e) => {
|
||||
if retries < MAX_CONNECT_RETRIES {
|
||||
|
|
|
@ -40,8 +40,12 @@ use crate::{
|
|||
|
||||
const DISCO_NODE: &str = "https://github.com/avstack/gst-meet";
|
||||
|
||||
static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| {
|
||||
let mut features = vec![
|
||||
static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| DiscoInfoResult {
|
||||
node: None,
|
||||
identities: vec![
|
||||
Identity::new("client", "bot", "en", "gst-meet"),
|
||||
],
|
||||
features: vec![
|
||||
Feature::new(ns::DISCO_INFO),
|
||||
Feature::new(ns::JINGLE_RTP_AUDIO),
|
||||
Feature::new(ns::JINGLE_RTP_VIDEO),
|
||||
|
@ -50,26 +54,9 @@ static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| {
|
|||
Feature::new("urn:ietf:rfc:5888"), // BUNDLE
|
||||
Feature::new("urn:ietf:rfc:5761"), // RTCP-MUX
|
||||
Feature::new("urn:ietf:rfc:4588"), // RTX
|
||||
];
|
||||
let gst_version = gstreamer::version();
|
||||
if gst_version.0 >= 1 && gst_version.1 >= 19 {
|
||||
// RTP header extensions are supported on GStreamer 1.19+
|
||||
features.push(Feature::new("http://jitsi.org/tcc"));
|
||||
}
|
||||
else {
|
||||
warn!("Upgrade GStreamer to 1.19 or later to enable RTP header extensions");
|
||||
}
|
||||
let identities = vec![
|
||||
Identity::new("client", "bot", "en", "gst-meet"),
|
||||
];
|
||||
// Not supported yet:
|
||||
// Feature::new("http://jitsi.org/opus-red")
|
||||
DiscoInfoResult {
|
||||
node: None,
|
||||
identities,
|
||||
features,
|
||||
extensions: vec![],
|
||||
}
|
||||
Feature::new("http://jitsi.org/tcc"),
|
||||
],
|
||||
extensions: vec![],
|
||||
});
|
||||
|
||||
static COMPUTED_CAPS_HASH: Lazy<Hash> = Lazy::new(|| {
|
||||
|
@ -102,6 +89,7 @@ pub struct JitsiConference {
|
|||
pub(crate) external_services: Vec<xmpp::extdisco::Service>,
|
||||
pub(crate) jingle_session: Arc<Mutex<Option<JingleSession>>>,
|
||||
pub(crate) inner: Arc<Mutex<JitsiConferenceInner>>,
|
||||
pub(crate) tls_insecure: bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for JitsiConference {
|
||||
|
@ -220,6 +208,7 @@ impl JitsiConference {
|
|||
on_colibri_message: None,
|
||||
connected_tx: Some(tx),
|
||||
})),
|
||||
tls_insecure: xmpp_connection.tls_insecure,
|
||||
};
|
||||
|
||||
xmpp_connection.add_stanza_filter(conference.clone()).await;
|
||||
|
@ -590,7 +579,7 @@ impl StanzaFilter for JitsiConference {
|
|||
|
||||
if let Some(colibri_url) = colibri_url {
|
||||
info!("Connecting Colibri WebSocket to {}", colibri_url);
|
||||
let colibri_channel = ColibriChannel::new(&colibri_url).await?;
|
||||
let colibri_channel = ColibriChannel::new(&colibri_url, self.tls_insecure).await?;
|
||||
let (tx, rx) = mpsc::channel(8);
|
||||
colibri_channel.subscribe(tx).await;
|
||||
jingle_session.colibri_channel = Some(colibri_channel);
|
||||
|
@ -599,6 +588,14 @@ impl StanzaFilter for JitsiConference {
|
|||
tokio::spawn(async move {
|
||||
let mut stream = ReceiverStream::new(rx);
|
||||
while let Some(msg) = stream.next().await {
|
||||
// Some message types are handled internally rather than passed to the on_colibri_message handler.
|
||||
|
||||
// End-to-end ping
|
||||
if let ColibriMessage::EndpointMessage { to, .. } = &msg {
|
||||
// if to ==
|
||||
|
||||
}
|
||||
|
||||
let locked_inner = self_.inner.lock().await;
|
||||
if let Some(f) = &locked_inner.on_colibri_message {
|
||||
if let Err(e) = f(self_.clone(), msg).await {
|
||||
|
|
|
@ -4,6 +4,7 @@ mod jingle;
|
|||
mod pinger;
|
||||
mod source;
|
||||
mod stanza_filter;
|
||||
mod tls;
|
||||
mod util;
|
||||
mod xmpp;
|
||||
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
#[cfg(any(feature = "tls-rustls-native-roots", feature = "tls-rustls-webpki-roots"))]
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(not(feature = "tls-insecure"))]
|
||||
use anyhow::bail;
|
||||
use anyhow::Result;
|
||||
use tokio_tungstenite::Connector;
|
||||
|
||||
#[cfg(feature = "tls-rustls-native-roots")]
|
||||
pub(crate) fn wss_connector(insecure: bool) -> Result<tokio_tungstenite::Connector> {
|
||||
let mut roots = rustls::RootCertStore::empty();
|
||||
for cert in rustls_native_certs::load_native_certs()? {
|
||||
roots.add(&rustls::Certificate(cert.0))?;
|
||||
}
|
||||
|
||||
let mut config = rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_root_certificates(roots)
|
||||
.with_no_client_auth();
|
||||
#[cfg(feature = "tls-insecure")]
|
||||
if insecure {
|
||||
config.dangerous().set_certificate_verifier(Arc::new(InsecureServerCertVerifier));
|
||||
}
|
||||
#[cfg(not(feature = "tls-insecure"))]
|
||||
if insecure {
|
||||
bail!("Insecure TLS mode can only be enabled if the tls-insecure feature was enabled at compile time.")
|
||||
}
|
||||
Ok(Connector::Rustls(Arc::new(config)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "tls-rustls-webpki-roots")]
|
||||
pub(crate) fn wss_connector(insecure: bool) -> Result<tokio_tungstenite::Connector> {
|
||||
let mut roots = rustls::RootCertStore::empty();
|
||||
roots.add_server_trust_anchors(
|
||||
webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
|
||||
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
|
||||
ta.subject,
|
||||
ta.spki,
|
||||
ta.name_constraints,
|
||||
)
|
||||
})
|
||||
);
|
||||
|
||||
let config = rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_root_certificates(roots)
|
||||
.with_no_client_auth();
|
||||
#[cfg(feature = "tls-insecure")]
|
||||
if insecure {
|
||||
config.dangerous().set_certificate_verifier(Arc::new(InsecureServerCertVerifier));
|
||||
}
|
||||
#[cfg(not(feature = "tls-insecure"))]
|
||||
if insecure {
|
||||
bail!("Insecure TLS mode can only be enabled if the tls-insecure feature was enabled at compile time.")
|
||||
}
|
||||
Ok(Connector::Rustls(Arc::new(config)))
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "tls-native", feature = "tls-native-vendored"))]
|
||||
pub(crate) fn wss_connector(insecure: bool) -> Result<tokio_tungstenite::Connector> {
|
||||
let mut builder = native_tls::TlsConnector::builder();
|
||||
builder.min_protocol_version(Some(native_tls::Protocol::Tlsv12));
|
||||
#[cfg(feature = "tls-insecure")]
|
||||
if insecure {
|
||||
builder.danger_accept_invalid_certs(true);
|
||||
builder.danger_accept_invalid_hostnames(true);
|
||||
}
|
||||
#[cfg(not(feature = "tls-insecure"))]
|
||||
if insecure {
|
||||
bail!("Insecure TLS mode can only be enabled if the tls-insecure feature was enabled at compile time.")
|
||||
}
|
||||
Ok(Connector::NativeTls(builder.build()?))
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "tls-insecure", any(feature = "tls-rustls-native-roots", feature = "tls-rustls-webpki-roots")))]
|
||||
struct InsecureServerCertVerifier;
|
||||
|
||||
#[cfg(all(feature = "tls-insecure", any(feature = "tls-rustls-native-roots", feature = "tls-rustls-webpki-roots")))]
|
||||
impl rustls::client::ServerCertVerifier for InsecureServerCertVerifier {
|
||||
fn verify_server_cert(&self, _end_entity: &rustls::Certificate, _intermediates: &[rustls::Certificate], _server_name: &rustls::ServerName, _scts: &mut dyn Iterator<Item = &[u8]>, _ocsp_response: &[u8], _now: std::time::SystemTime) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
|
||||
Ok(rustls::client::ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ use xmpp_parsers::{
|
|||
BareJid, Element, FullJid, Jid,
|
||||
};
|
||||
|
||||
use crate::{pinger::Pinger, stanza_filter::StanzaFilter, util::generate_id, xmpp};
|
||||
use crate::{pinger::Pinger, stanza_filter::StanzaFilter, tls::wss_connector, util::generate_id, xmpp};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum ConnectionState {
|
||||
|
@ -60,6 +60,7 @@ impl fmt::Debug for ConnectionInner {
|
|||
pub struct Connection {
|
||||
pub(crate) tx: mpsc::Sender<Element>,
|
||||
inner: Arc<Mutex<ConnectionInner>>,
|
||||
pub(crate) tls_insecure: bool,
|
||||
}
|
||||
|
||||
pub enum Authentication {
|
||||
|
@ -72,6 +73,7 @@ impl Connection {
|
|||
websocket_url: &str,
|
||||
xmpp_domain: &str,
|
||||
authentication: Authentication,
|
||||
tls_insecure: bool,
|
||||
) -> Result<(Self, impl Future<Output = ()>)> {
|
||||
let websocket_url: Uri = websocket_url.parse().context("invalid WebSocket URL")?;
|
||||
let xmpp_domain: BareJid = xmpp_domain.parse().context("invalid XMPP domain")?;
|
||||
|
@ -88,7 +90,7 @@ impl Connection {
|
|||
.header("upgrade", "websocket")
|
||||
.body(())
|
||||
.context("failed to build WebSocket request")?;
|
||||
let (websocket, _response) = tokio_tungstenite::connect_async(request)
|
||||
let (websocket, _response) = tokio_tungstenite::connect_async_tls_with_config(request, None, Some(wss_connector(tls_insecure)?))
|
||||
.await
|
||||
.context("failed to connect XMPP WebSocket")?;
|
||||
let (sink, stream) = websocket.split();
|
||||
|
@ -107,6 +109,7 @@ impl Connection {
|
|||
let connection = Self {
|
||||
tx: tx.clone(),
|
||||
inner: inner.clone(),
|
||||
tls_insecure,
|
||||
};
|
||||
|
||||
let writer = Connection::write_loop(rx, sink);
|
||||
|
|
Loading…
Reference in New Issue