Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RSDK-9433] - Store TLS certs in DER format to save space #360

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ reqwless = "0.13.0"
ringbuf = "~0.3"
# TODO(RSDK-8995): Upgrade to latest `rustls` infrastructure
rustls = { version = "~0.21", features = ["logging", "tls12"] }
rustls-pemfile = { version = "2.2" }
rustls-pki-types = "1.10.0"
scopeguard = "1.2.0"
sctp-proto = "0.3.0"
sdp = "0.6.2"
Expand Down
4 changes: 2 additions & 2 deletions micro-rdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ libstart = ["esp-idf-svc/libstart"]
builtin-components = []
camera = []
esp32 = ["dep:esp-idf-svc", "dep:embedded-svc", "dep:embedded-hal", "esp-idf-svc/std", "esp-idf-svc/alloc", "dep:printf-compat"]
native = ["dep:rustls", "dep:webpki-roots", "dep:rustls-pemfile", "dep:mdns-sd", "dep:local-ip-address", "dep:openssl", "dep:rcgen", "dep:async-std-openssl"]
native = ["dep:rustls", "dep:webpki-roots", "dep:mdns-sd", "dep:local-ip-address", "dep:openssl", "dep:rcgen", "dep:async-std-openssl"]
data-upload-hook-unstable = ["data", "esp32"]
data = []
qemu = []
Expand All @@ -42,7 +42,6 @@ mdns-sd = { workspace = true, optional = true }
openssl = { workspace = true, optional = true }
rcgen = { workspace = true, optional = true }
rustls = { workspace = true, optional = true }
rustls-pemfile = { workspace = true, optional = true }
webpki-roots = { workspace = true, optional = true }
bincode = "2.0.0-rc.3"

Expand Down Expand Up @@ -77,6 +76,7 @@ printf-compat = { workspace = true, optional = true }
prost.workspace = true
rand.workspace = true
ringbuf.workspace = true
rustls-pki-types.workspace = true
scopeguard.workspace = true
sctp-proto.workspace = true
sdp.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions micro-rdk/src/common/app_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub enum AppClientError {
AppClientEmptyBody,
#[error(transparent)]
AppClientIoError(#[from] std::io::Error),
#[error("tls certificate parsing error: {0}")]
AppTlsCertParseError(String),
}

impl AppClientError {
Expand Down
30 changes: 16 additions & 14 deletions micro-rdk/src/common/conn/viam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,19 +591,22 @@ where
let certs = if let Some(app) = app_client.as_ref() {
app.get_certificates()
.await
.map(|cert_resp| {
let cert: TlsCertificate = cert_resp.into();
match self.storage.store_tls_certificate(cert.clone()) {
Ok(_) => {
log::debug!("stored TLS certificate received by app");
}
Err(err) => {
log::error!("error storing TLS cert: {:?}", err);
}
}
// even if we fail to store the certificate, proceed
// with the valid certificate obtained by app
Some(cert)
.and_then(|cert_resp| {
TlsCertificate::try_from(cert_resp)
.map(|cert| {
match self.storage.store_tls_certificate(cert.clone()) {
Ok(_) => {
log::debug!("stored TLS certificate received by app");
}
Err(err) => {
log::error!("error storing TLS cert: {:?}", err);
}
}
// even if we fail to store the certificate, proceed
// with the valid certificate obtained by app
Some(cert)
})
.map_err(|err| AppClientError::AppTlsCertParseError(err.to_string()))
})
.ok()
} else {
Expand Down Expand Up @@ -1461,7 +1464,6 @@ mod tests {
Err("timeout".into())
})
.await;

assert!(record.is_ok());
let record = record.unwrap();

Expand Down
20 changes: 14 additions & 6 deletions micro-rdk/src/common/credentials_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::str::FromStr;
use std::{convert::Infallible, error::Error, fmt::Debug, rc::Rc, sync::Mutex};

use hyper::Uri;
use rustls_pki_types::pem::PemObject;
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
Comment on lines +6 to +7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: join these


use crate::{common::grpc::ServerError, proto::app::v1::RobotConfig};

Expand Down Expand Up @@ -90,12 +92,18 @@ pub struct TlsCertificate {
pub(crate) private_key: Vec<u8>,
}

impl From<CertificateResponse> for TlsCertificate {
fn from(resp: CertificateResponse) -> Self {
Self {
certificate: resp.tls_certificate.into_bytes(),
private_key: resp.tls_private_key.into_bytes(),
}
impl TryFrom<CertificateResponse> for TlsCertificate {
type Error = rustls_pki_types::pem::Error;
fn try_from(resp: CertificateResponse) -> Result<Self, Self::Error> {
// we convert the certificate and private key from PEM to DER format to save space
let private_key_bytes = resp.tls_private_key.into_bytes();
let private_key = PrivateKeyDer::from_pem_slice(&private_key_bytes[0..])?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this range should just work with [..] right? also, maybe check if the range is needed or if as_slice is available.
L102 does the same

let cert_bytes = resp.tls_certificate.into_bytes();
let cert = CertificateDer::from_pem_slice(&cert_bytes[0..])?;
Ok(Self {
certificate: cert.to_vec(),
private_key: private_key.secret_der().to_vec(),
})
}
}

Expand Down
14 changes: 7 additions & 7 deletions micro-rdk/src/esp32/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl Esp32ServerConfig {
cacert_bytes: 0,
},
__bindgen_anon_3: crate::esp32::esp_idf_svc::sys::esp_tls_cfg_server__bindgen_ty_3 {
// This is the server certificates in the PEM format
// This is the server certificates in the DER format
servercert_buf: srv_cert.as_ptr(),
},
__bindgen_anon_4: crate::esp32::esp_idf_svc::sys::esp_tls_cfg_server__bindgen_ty_4 {
Expand Down Expand Up @@ -439,23 +439,23 @@ impl<IO> From<Esp32ClientTlsStream<IO>> for Esp32TlsStream<IO> {

#[derive(Default)]
pub struct Esp32H2Connector {
srv_cert: Option<CString>,
srv_key: Option<CString>,
srv_cert: Option<Vec<u8>>,
srv_key: Option<Vec<u8>>,
}

impl ViamH2Connector for Esp32H2Connector {
fn set_server_certificates(&mut self, srv_cert: Vec<u8>, srv_key: Vec<u8>) {
let _ = self.srv_cert.replace(CString::new(srv_cert).unwrap());
let _ = self.srv_key.replace(CString::new(srv_key).unwrap());
let _ = self.srv_cert.replace(srv_cert);
let _ = self.srv_key.replace(srv_key);
Comment on lines +448 to +449
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

}
fn accept_connection(
&self,
connection: Async<TcpStream>,
) -> Result<std::pin::Pin<Box<dyn IntoHttp2Stream>>, std::io::Error> {
if self.srv_cert.is_some() && self.srv_key.is_some() {
let cfg = Esp32ServerConfig::new(
self.srv_cert.as_ref().unwrap().to_bytes_with_nul(),
self.srv_key.as_ref().unwrap().to_bytes_with_nul(),
&self.srv_cert.as_ref().unwrap(),
&self.srv_key.as_ref().unwrap(),
Comment on lines +457 to +458
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ? instead of unwrap since the return signature is compatible

);
let conn = Esp32Accept::new(connection, cfg)?;
Ok(Box::pin(Esp32StreamAcceptor(conn)))
Expand Down
14 changes: 3 additions & 11 deletions micro-rdk/src/native/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,15 @@ impl ViamH2Connector for NativeH2Connector {
connection: Async<TcpStream>,
) -> Result<std::pin::Pin<Box<dyn IntoHttp2Stream>>, std::io::Error> {
if self.srv_cert.is_some() && self.srv_key.is_some() {
let cert_chain = rustls_pemfile::certs(&mut BufReader::new(
self.srv_cert.as_ref().unwrap().as_slice(),
))
.map(|c| rustls::Certificate(c.unwrap().to_vec()))
.collect();
let priv_keys = rustls_pemfile::private_key(&mut BufReader::new(
self.srv_key.as_ref().unwrap().as_slice(),
))
.unwrap()
.map(|k| rustls::PrivateKey(k.secret_der().to_vec()));
let priv_keys = rustls::PrivateKey(self.srv_key.clone().unwrap());
let cert_chain = vec![rustls::Certificate(self.srv_cert.clone().unwrap())];
Comment on lines +31 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here with unwraps

let mut cfg = ServerConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&rustls::version::TLS12])
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?
.with_no_client_auth()
.with_single_cert(cert_chain, priv_keys.unwrap())
.with_single_cert(cert_chain, priv_keys)
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
cfg.alpn_protocols = vec!["h2".as_bytes().to_vec()];
Ok(Box::pin(NativeStreamAcceptor(
Expand Down
Loading