Skip to content

Commit

Permalink
Change root to ca_certs to support multiple CA certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
div-seungha committed Sep 25, 2024
1 parent 89a8e90 commit 3641a09
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 37 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).

### Changed

- Renamed the root field to ca_certs and updated it to support multiple CA
certificates.
- Apply Group imports by StdExternalCrate.
- Modify the code with this command:
- `cargo fmt -- --config group_imports=StdExternalCrate`.
Expand All @@ -32,7 +34,7 @@ Versioning](https://semver.org/spec/v2.0.0.html).
- `giganto_ingest_address` to `giganto_ingest_srv_addr`.
- `giganto_publish_address` to `giganto_publish_srv_addr`.
- `review_address` to `review_rpc_srv_addr`.
- Update giganto-client to version `0.17.0`. Updating to this version results
- Updated giganto-client to version `0.17.0`. Updating to this version results
in the following changes.
- Bump dependencies.
- Update quinn to version `0.11`.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The following is key values in the TOML configuration file.

* `key`: Crusher's private key file.
* `cert`: Crusher's certificate file.
* `root`: RootCA file. (for Giganto, Review)
* `ca_certs`: CA certificate files. (for Giganto, Review)
* `giganto_name`: the name of the Giganto. This must match with the DNS name in
the certificate.
* `giganto_ingest_srv_addr`: IP address and port number of `Giganto ingest`.
Expand All @@ -40,7 +40,7 @@ Example
```toml
key = "key.pem"
cert = "cert.pem"
root = "root.pem"
ca_certs = ["ca_cert_1.pem", "ca_cert_2.pem"]
giganto_name = "localhost"
giganto_ingest_srv_addr = "127.0.0.1:38370"
giganto_publish_srv_addr = "127.0.0.1:38371"
Expand Down
6 changes: 3 additions & 3 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ pub const SERVER_RETRY_INTERVAL: u64 = 3;
pub struct Certs {
pub certs: Vec<CertificateDer<'static>>,
pub key: PrivateKeyDer<'static>,
pub root: RootCertStore,
pub ca_certs: RootCertStore,
}

impl Clone for Certs {
fn clone(&self) -> Self {
Self {
certs: self.certs.clone(),
key: self.key.clone_key(),
root: self.root.clone(),
ca_certs: self.ca_certs.clone(),
}
}
}

pub fn config(certs: &Arc<Certs>) -> Result<Endpoint> {
let tls_config = rustls::ClientConfig::builder()
.with_root_certificates(certs.root.clone())
.with_root_certificates(certs.ca_certs.clone())
.with_client_auth_cert(certs.certs.clone(), certs.key.clone_key())?;

let mut transport = TransportConfig::default();
Expand Down
38 changes: 23 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ mod request;
mod settings;
mod subscribe;

use std::path::Path;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::{collections::HashMap, env, fs, process::exit, sync::Arc};

use anyhow::{anyhow, bail, Context, Result};
use client::Certs;
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use rustls_pemfile::Item;
use settings::Settings;
pub use settings::TEMP_TOML_POST_FIX;
use tokio::{
Expand Down Expand Up @@ -70,17 +72,12 @@ async fn main() -> Result<()> {
)
})?;
let key = to_private_key(&key_pem).context("cannot read private key")?;
let root_pem = fs::read(&settings.root).with_context(|| {
format!(
"failed to read root certificate file: {}",
settings.root.display()
)
})?;
let root_cert = to_root_cert(&root_pem)?;
let ca_cert_paths = settings.ca_certs.clone();
let ca_certs = to_ca_certs(&ca_cert_paths).context("failed to read CA certificates")?;
let certs = Arc::new(Certs {
certs: cert.clone(),
key: key.clone_key(),
root: root_cert.clone(),
ca_certs: ca_certs.clone(),
});

read_last_timestamp(&settings.last_timestamp_data).await?;
Expand Down Expand Up @@ -193,12 +190,23 @@ fn to_private_key(pem: &[u8]) -> Result<PrivateKeyDer<'static>> {
}
}

fn to_root_cert(pem: &[u8]) -> Result<rustls::RootCertStore> {
let mut root_store = rustls::RootCertStore::empty();
if let Some(Ok(cert)) = rustls_pemfile::certs(&mut &*pem).next() {
root_store.add(cert).context("failed to add root cert")?;
};
Ok(root_store)
fn to_ca_certs(root_cert_paths: &Vec<PathBuf>) -> Result<rustls::RootCertStore> {
let mut root_cert = rustls::RootCertStore::empty();

for root in root_cert_paths {
let file =
fs::File::open(root).with_context(|| format!("Failed to open file: {root:?}"))?;
let mut reader = BufReader::new(file);

while let Some(item) = rustls_pemfile::read_one(&mut reader)? {
if let Item::X509Certificate(cert) = item {
let cert_der = cert;
root_cert.add(cert_der).context("Failed to add root cert")?;
}
}
}

Ok(root_cert)
}

fn init_tracing(path: &Path) -> Result<WorkerGuard> {
Expand Down
2 changes: 1 addition & 1 deletion src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl Client {
request_send: Sender<RequestedPolicy>,
) -> Self {
let endpoint =
client::config(certs).expect("server configuration error with cert, key or root");
client::config(certs).expect("server configuration error with cert, key or ca_certs");
Client {
server_address,
server_name,
Expand Down
10 changes: 5 additions & 5 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ pub const TEMP_TOML_POST_FIX: &str = ".temp.toml";
/// The application settings.
#[derive(Clone, Debug, Deserialize)]
pub struct Settings {
pub cert: PathBuf, // Path to the certificate file
pub key: PathBuf, // Path to the private key file
pub root: PathBuf, // Path to the rootCA file
pub giganto_name: String, // host name to giganto
pub cert: PathBuf, // Path to the certificate file
pub key: PathBuf, // Path to the private key file
pub ca_certs: Vec<PathBuf>, // Path to the ca certificate file
pub giganto_name: String, // host name to giganto
#[serde(deserialize_with = "deserialize_socket_addr")]
pub giganto_ingest_srv_addr: SocketAddr, // IP address & port to giganto
#[serde(deserialize_with = "deserialize_socket_addr")]
pub giganto_publish_srv_addr: SocketAddr, // IP address & port to giganto
pub review_name: String, // host name to review
pub review_name: String, // host name to review
#[serde(deserialize_with = "deserialize_socket_addr")]
pub review_rpc_srv_addr: SocketAddr, // IP address & port to review
pub last_timestamp_data: PathBuf, // Path to the last series timestamp data file
Expand Down
2 changes: 1 addition & 1 deletion src/subscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl Client {
request_recv: Receiver<RequestedPolicy>,
) -> Self {
let endpoint =
client::config(certs).expect("Server configuration error with cert, key or root");
client::config(certs).expect("Server configuration error with cert, key or ca_certs");
Client {
ingest_addr,
publish_addr,
Expand Down
17 changes: 9 additions & 8 deletions src/subscribe/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ use super::{Client, Conn};
use crate::{
client::Certs,
model::{Interval, Period, Policy, TimeSeries},
to_cert_chain, to_private_key, to_root_cert,
to_ca_certs, to_cert_chain, to_private_key,
};

pub(crate) static TOKEN: LazyLock<Mutex<u32>> = LazyLock::new(|| Mutex::new(0));

const CERT_PATH: &str = "tests/cert.pem";
const KEY_PATH: &str = "tests/key.pem";
const CA_CERT_PATH: &str = "tests/root.pem";
const CA_CERT_PATH: &str = "tests/ca_certs.pem";
const HOST: &str = "localhost";
const TEST_INGEST_PORT: u16 = 60190;
const TEST_PUBLISH_PORT: u16 = 60191;
Expand Down Expand Up @@ -73,9 +73,10 @@ async fn handle_connection(conn: quinn::Incoming) {
fn config_server() -> ServerConfig {
let certs = cert_key();

let client_auth = rustls::server::WebPkiClientVerifier::builder(Arc::new(certs.root.clone()))
.build()
.expect("Failed to build client certificate verifier");
let client_auth =
rustls::server::WebPkiClientVerifier::builder(Arc::new(certs.ca_certs.clone()))
.build()
.expect("Failed to build client certificate verifier");

let server_crypto = rustls::ServerConfig::builder()
.with_client_cert_verifier(client_auth)
Expand Down Expand Up @@ -112,13 +113,13 @@ fn cert_key() -> Certs {
let cert = to_cert_chain(&cert_pem).unwrap();
let key_pem = fs::read(KEY_PATH).unwrap();
let key = to_private_key(&key_pem).unwrap();
let root_pem = fs::read(CA_CERT_PATH).unwrap();
let root_cert = to_root_cert(&root_pem).unwrap();
let ca_certs_paths = vec![PathBuf::from(CA_CERT_PATH)];
let ca_certs = to_ca_certs(&ca_certs_paths).unwrap();

Certs {
certs: cert.clone(),
key: key.clone_key(),
root: root_cert.clone(),
ca_certs: ca_certs.clone(),
}
}

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion tests/config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
key = "tests/key.pem"
cert = "tests/cert.pem"
root = "tests/root.pem"
ca_certs = ["tests/ca_certs.pem"]
giganto_name = "localhost"
giganto_ingest_srv_addr = "127.0.0.1:38370"
giganto_publish_srv_addr = "127.0.0.1:38371"
Expand Down

0 comments on commit 3641a09

Please sign in to comment.