net/quinn: Use separate property for certificate & private key file

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1036>
This commit is contained in:
Sanchayan Maity 2024-05-01 19:08:46 +05:30
parent 0d2f054c15
commit 150ad7a545
3 changed files with 109 additions and 56 deletions

View file

@ -68,7 +68,8 @@ struct Settings {
timeout: u32, timeout: u32,
secure_conn: bool, secure_conn: bool,
use_datagram: bool, use_datagram: bool,
certificate_path: Option<PathBuf>, certificate_file: Option<PathBuf>,
private_key_file: Option<PathBuf>,
} }
impl Default for Settings { impl Default for Settings {
@ -83,7 +84,8 @@ impl Default for Settings {
timeout: DEFAULT_TIMEOUT, timeout: DEFAULT_TIMEOUT,
secure_conn: DEFAULT_SECURE_CONNECTION, secure_conn: DEFAULT_SECURE_CONNECTION,
use_datagram: false, use_datagram: false,
certificate_path: None, certificate_file: None,
private_key_file: None,
} }
} }
} }
@ -146,11 +148,13 @@ impl ElementImpl for QuinnQuicSink {
* Fail the state change if a secure connection was requested but * Fail the state change if a secure connection was requested but
* no certificate path was provided. * no certificate path was provided.
*/ */
if settings.secure_conn && settings.certificate_path.is_none() { if settings.secure_conn
&& (settings.certificate_file.is_none() || settings.private_key_file.is_none())
{
gst::error!( gst::error!(
CAT, CAT,
imp: self, imp: self,
"Certificate path not provided for secure connection" "Certificate or private key file not provided for secure connection"
); );
return Err(gst::StateChangeError); return Err(gst::StateChangeError);
} }
@ -211,9 +215,13 @@ impl ObjectImpl for QuinnQuicSink {
.blurb("Use certificates for QUIC connection. False: Insecure connection, True: Secure connection.") .blurb("Use certificates for QUIC connection. False: Insecure connection, True: Secure connection.")
.default_value(DEFAULT_SECURE_CONNECTION) .default_value(DEFAULT_SECURE_CONNECTION)
.build(), .build(),
glib::ParamSpecString::builder("certificate-path") glib::ParamSpecString::builder("certificate-file")
.nick("Certificate Path") .nick("Certificate file")
.blurb("Path where the certificate files cert.pem and privkey.pem are stored") .blurb("Path to certificate chain in single file")
.build(),
glib::ParamSpecString::builder("private-key-file")
.nick("Private key file")
.blurb("Path to a PKCS8 or RSA private key file")
.build(), .build(),
glib::ParamSpecBoolean::builder("use-datagram") glib::ParamSpecBoolean::builder("use-datagram")
.nick("Use datagram") .nick("Use datagram")
@ -264,9 +272,13 @@ impl ObjectImpl for QuinnQuicSink {
"secure-connection" => { "secure-connection" => {
settings.secure_conn = value.get().expect("type checked upstream"); settings.secure_conn = value.get().expect("type checked upstream");
} }
"certificate-path" => { "certificate-file" => {
let value: String = value.get().unwrap(); let value: String = value.get().unwrap();
settings.certificate_path = Some(value.into()); settings.certificate_file = Some(value.into());
}
"private-key-file" => {
let value: String = value.get().unwrap();
settings.private_key_file = Some(value.into());
} }
"use-datagram" => { "use-datagram" => {
settings.use_datagram = value.get().expect("type checked upstream"); settings.use_datagram = value.get().expect("type checked upstream");
@ -296,9 +308,13 @@ impl ObjectImpl for QuinnQuicSink {
} }
"timeout" => settings.timeout.to_value(), "timeout" => settings.timeout.to_value(),
"secure-connection" => settings.secure_conn.to_value(), "secure-connection" => settings.secure_conn.to_value(),
"certificate-path" => { "certificate-file" => {
let certpath = settings.certificate_path.as_ref(); let certfile = settings.certificate_file.as_ref();
certpath.and_then(|file| file.to_str()).to_value() certfile.and_then(|file| file.to_str()).to_value()
}
"private-key-file" => {
let privkey = settings.private_key_file.as_ref();
privkey.and_then(|file| file.to_str()).to_value()
} }
"use-datagram" => settings.use_datagram.to_value(), "use-datagram" => settings.use_datagram.to_value(),
_ => unimplemented!(), _ => unimplemented!(),
@ -495,7 +511,8 @@ impl QuinnQuicSink {
let alpns; let alpns;
let use_datagram; let use_datagram;
let secure_conn; let secure_conn;
let cert_path; let cert_file;
let private_key_file;
{ {
let settings = self.settings.lock().unwrap(); let settings = self.settings.lock().unwrap();
@ -511,16 +528,19 @@ impl QuinnQuicSink {
alpns = settings.alpns.clone(); alpns = settings.alpns.clone();
use_datagram = settings.use_datagram; use_datagram = settings.use_datagram;
secure_conn = settings.secure_conn; secure_conn = settings.secure_conn;
cert_path = settings.certificate_path.clone(); cert_file = settings.certificate_file.clone();
private_key_file = settings.private_key_file.clone();
} }
let endpoint = let endpoint =
client_endpoint(client_addr, secure_conn, alpns, cert_path).map_err(|err| { client_endpoint(client_addr, secure_conn, alpns, cert_file, private_key_file).map_err(
WaitError::FutureError(gst::error_msg!( |err| {
gst::ResourceError::Failed, WaitError::FutureError(gst::error_msg!(
["Failed to configure endpoint: {}", err] gst::ResourceError::Failed,
)) ["Failed to configure endpoint: {}", err]
})?; ))
},
)?;
let connection = endpoint let connection = endpoint
.connect(server_addr, &server_name) .connect(server_addr, &server_name)

View file

@ -67,7 +67,8 @@ struct Settings {
secure_conn: bool, secure_conn: bool,
caps: gst::Caps, caps: gst::Caps,
use_datagram: bool, use_datagram: bool,
certificate_path: Option<PathBuf>, certificate_file: Option<PathBuf>,
private_key_file: Option<PathBuf>,
} }
impl Default for Settings { impl Default for Settings {
@ -81,7 +82,8 @@ impl Default for Settings {
secure_conn: DEFAULT_SECURE_CONNECTION, secure_conn: DEFAULT_SECURE_CONNECTION,
caps: gst::Caps::new_any(), caps: gst::Caps::new_any(),
use_datagram: false, use_datagram: false,
certificate_path: None, certificate_file: None,
private_key_file: None,
} }
} }
} }
@ -144,11 +146,13 @@ impl ElementImpl for QuinnQuicSrc {
* Fail the state change if a secure connection was requested but * Fail the state change if a secure connection was requested but
* no certificate path was provided. * no certificate path was provided.
*/ */
if settings.secure_conn && settings.certificate_path.is_none() { if settings.secure_conn
&& (settings.certificate_file.is_none() || settings.private_key_file.is_none())
{
gst::error!( gst::error!(
CAT, CAT,
imp: self, imp: self,
"Certificate path not provided for secure connection" "Certificate or private key file not provided for secure connection"
); );
return Err(gst::StateChangeError); return Err(gst::StateChangeError);
} }
@ -199,9 +203,13 @@ impl ObjectImpl for QuinnQuicSrc {
.blurb("Use certificates for QUIC connection. False: Insecure connection, True: Secure connection.") .blurb("Use certificates for QUIC connection. False: Insecure connection, True: Secure connection.")
.default_value(DEFAULT_SECURE_CONNECTION) .default_value(DEFAULT_SECURE_CONNECTION)
.build(), .build(),
glib::ParamSpecString::builder("certificate-path") glib::ParamSpecString::builder("certificate-file")
.nick("Certificate Path") .nick("Certificate file")
.blurb("Path where the certificate files cert.pem and privkey.pem are stored") .blurb("Path to certificate chain in single file")
.build(),
glib::ParamSpecString::builder("private-key-file")
.nick("Private key file")
.blurb("Path to a PKCS8 or RSA private key file")
.build(), .build(),
glib::ParamSpecBoxed::builder::<gst::Caps>("caps") glib::ParamSpecBoxed::builder::<gst::Caps>("caps")
.nick("caps") .nick("caps")
@ -259,9 +267,13 @@ impl ObjectImpl for QuinnQuicSrc {
"secure-connection" => { "secure-connection" => {
settings.secure_conn = value.get().expect("type checked upstream"); settings.secure_conn = value.get().expect("type checked upstream");
} }
"certificate-path" => { "certificate-file" => {
let value: String = value.get().unwrap(); let value: String = value.get().unwrap();
settings.certificate_path = Some(value.into()); settings.certificate_file = Some(value.into());
}
"private-key-file" => {
let value: String = value.get().unwrap();
settings.private_key_file = Some(value.into());
} }
"use-datagram" => { "use-datagram" => {
settings.use_datagram = value.get().expect("type checked upstream"); settings.use_datagram = value.get().expect("type checked upstream");
@ -287,9 +299,13 @@ impl ObjectImpl for QuinnQuicSrc {
"caps" => settings.caps.to_value(), "caps" => settings.caps.to_value(),
"timeout" => settings.timeout.to_value(), "timeout" => settings.timeout.to_value(),
"secure-connection" => settings.secure_conn.to_value(), "secure-connection" => settings.secure_conn.to_value(),
"certificate-path" => { "certificate-file" => {
let certpath = settings.certificate_path.as_ref(); let certfile = settings.certificate_file.as_ref();
certpath.and_then(|file| file.to_str()).to_value() certfile.and_then(|file| file.to_str()).to_value()
}
"private-key-file" => {
let privkey = settings.private_key_file.as_ref();
privkey.and_then(|file| file.to_str()).to_value()
} }
"use-datagram" => settings.use_datagram.to_value(), "use-datagram" => settings.use_datagram.to_value(),
_ => unimplemented!(), _ => unimplemented!(),
@ -520,7 +536,8 @@ impl QuinnQuicSrc {
let alpns; let alpns;
let use_datagram; let use_datagram;
let secure_conn; let secure_conn;
let cert_path; let cert_file;
let private_key_file;
{ {
let settings = self.settings.lock().unwrap(); let settings = self.settings.lock().unwrap();
@ -533,16 +550,24 @@ impl QuinnQuicSrc {
alpns = settings.alpns.clone(); alpns = settings.alpns.clone();
use_datagram = settings.use_datagram; use_datagram = settings.use_datagram;
secure_conn = settings.secure_conn; secure_conn = settings.secure_conn;
cert_path = settings.certificate_path.clone(); cert_file = settings.certificate_file.clone();
private_key_file = settings.private_key_file.clone();
} }
let endpoint = server_endpoint(server_addr, &server_name, secure_conn, alpns, cert_path) let endpoint = server_endpoint(
.map_err(|err| { server_addr,
WaitError::FutureError(gst::error_msg!( &server_name,
gst::ResourceError::Failed, secure_conn,
["Failed to configure endpoint: {}", err] alpns,
)) cert_file,
})?; private_key_file,
)
.map_err(|err| {
WaitError::FutureError(gst::error_msg!(
gst::ResourceError::Failed,
["Failed to configure endpoint: {}", err]
))
})?;
let incoming_conn = endpoint.accept().await.unwrap(); let incoming_conn = endpoint.accept().await.unwrap();

View file

@ -138,11 +138,12 @@ impl rustls::client::ServerCertVerifier for SkipServerVerification {
fn configure_client( fn configure_client(
secure_conn: bool, secure_conn: bool,
certificate_path: Option<PathBuf>, certificate_file: Option<PathBuf>,
private_key_file: Option<PathBuf>,
alpns: Vec<String>, alpns: Vec<String>,
) -> Result<ClientConfig, Box<dyn Error>> { ) -> Result<ClientConfig, Box<dyn Error>> {
let mut crypto = if secure_conn { let mut crypto = if secure_conn {
let (certs, key) = read_certs_from_file(certificate_path)?; let (certs, key) = read_certs_from_file(certificate_file, private_key_file)?;
let mut cert_store = rustls::RootCertStore::empty(); let mut cert_store = rustls::RootCertStore::empty();
for cert in &certs { for cert in &certs {
@ -171,7 +172,8 @@ fn configure_client(
} }
fn read_certs_from_file( fn read_certs_from_file(
certificate_path: Option<PathBuf>, certificate_file: Option<PathBuf>,
private_key_file: Option<PathBuf>,
) -> Result<(Vec<rustls::Certificate>, rustls::PrivateKey), Box<dyn Error>> { ) -> Result<(Vec<rustls::Certificate>, rustls::PrivateKey), Box<dyn Error>> {
/* /*
* NOTE: * NOTE:
@ -187,13 +189,10 @@ fn read_certs_from_file(
* chain in a single file. For example, this is the case of modern day * chain in a single file. For example, this is the case of modern day
* Apache and nginx. * Apache and nginx.
*/ */
let cert_file = certificate_path let cert_file = certificate_file
.clone() .clone()
.expect("Expected path to certificates be valid") .expect("Expected path to certificates be valid");
.join("fullchain.pem"); let key_file = private_key_file.expect("Expected path to certificates be valid");
let key_file = certificate_path
.expect("Expected path to certificates be valid")
.join("privkey.pem");
let certs: Vec<rustls::Certificate> = { let certs: Vec<rustls::Certificate> = {
let cert_file = File::open(cert_file.as_path())?; let cert_file = File::open(cert_file.as_path())?;
@ -225,11 +224,12 @@ fn read_certs_from_file(
fn configure_server( fn configure_server(
server_name: &str, server_name: &str,
secure_conn: bool, secure_conn: bool,
certificate_path: Option<PathBuf>, certificate_file: Option<PathBuf>,
private_key_file: Option<PathBuf>,
alpns: Vec<String>, alpns: Vec<String>,
) -> Result<(ServerConfig, Vec<rustls::Certificate>), Box<dyn Error>> { ) -> Result<(ServerConfig, Vec<rustls::Certificate>), Box<dyn Error>> {
let (certs, key) = if secure_conn { let (certs, key) = if secure_conn {
read_certs_from_file(certificate_path)? read_certs_from_file(certificate_file, private_key_file)?
} else { } else {
let cert = rcgen::generate_simple_self_signed(vec![server_name.into()]).unwrap(); let cert = rcgen::generate_simple_self_signed(vec![server_name.into()]).unwrap();
let cert_der = cert.serialize_der().unwrap(); let cert_der = cert.serialize_der().unwrap();
@ -279,9 +279,16 @@ pub fn server_endpoint(
server_name: &str, server_name: &str,
secure_conn: bool, secure_conn: bool,
alpns: Vec<String>, alpns: Vec<String>,
certificate_path: Option<PathBuf>, certificate_file: Option<PathBuf>,
private_key_file: Option<PathBuf>,
) -> Result<Endpoint, Box<dyn Error>> { ) -> Result<Endpoint, Box<dyn Error>> {
let (server_config, _) = configure_server(server_name, secure_conn, certificate_path, alpns)?; let (server_config, _) = configure_server(
server_name,
secure_conn,
certificate_file,
private_key_file,
alpns,
)?;
let endpoint = Endpoint::server(server_config, server_addr)?; let endpoint = Endpoint::server(server_config, server_addr)?;
Ok(endpoint) Ok(endpoint)
@ -291,9 +298,10 @@ pub fn client_endpoint(
client_addr: SocketAddr, client_addr: SocketAddr,
secure_conn: bool, secure_conn: bool,
alpns: Vec<String>, alpns: Vec<String>,
certificate_path: Option<PathBuf>, certificate_file: Option<PathBuf>,
private_key_file: Option<PathBuf>,
) -> Result<Endpoint, Box<dyn Error>> { ) -> Result<Endpoint, Box<dyn Error>> {
let client_cfg = configure_client(secure_conn, certificate_path, alpns)?; let client_cfg = configure_client(secure_conn, certificate_file, private_key_file, alpns)?;
let mut endpoint = Endpoint::client(client_addr)?; let mut endpoint = Endpoint::client(client_addr)?;
endpoint.set_default_client_config(client_cfg); endpoint.set_default_client_config(client_cfg);