Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions upki-cli/tests/data/verify_non_existent_dir/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ cache-dir = "not-exist/"

[revocation]
fetch-url = ""

[intermediates]
enabled = false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of enabled, I think we should make intermediates (and revocation) Option in the top-level Config?

fetch-url = ""
6 changes: 5 additions & 1 deletion upki-cli/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn config_unknown_fields() {
|
1 | cache_dir = "tests/data/config_unknown_fields/"
| ^^^^^^^^^
unknown field `cache_dir`, expected `cache-dir` or `revocation`
unknown field `cache_dir`, expected one of `cache-dir`, `revocation`, `intermediates`


Location:
Expand Down Expand Up @@ -92,6 +92,10 @@ fn show_config_fixpoint() {
[revocation]
fetch-url = ""

[intermediates]
enabled = false
fetch-url = ""

----- stderr -----
"#);
}
Expand Down
2 changes: 1 addition & 1 deletion upki-mirror/src/bin/intermediates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use eyre::{Context, Report, anyhow};
use rustls_pki_types::CertificateDer;
use rustls_pki_types::pem::PemObject;
use serde::Deserialize;
use upki::revocation::{Manifest, ManifestFile};
use upki::data::{Manifest, ManifestFile};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Report> {
Expand Down
2 changes: 1 addition & 1 deletion upki-mirror/src/bin/mozilla-crlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::time::SystemTime;
use aws_lc_rs::digest::{SHA256, digest};
use clap::{Parser, ValueEnum};
use eyre::{Context, Report, anyhow};
use upki::revocation::{Manifest, ManifestFile};
use upki::data::{Manifest, ManifestFile};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Report> {
Expand Down
76 changes: 76 additions & 0 deletions upki/src/data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#[cfg(feature = "__fetch")]
use std::{fs::File, io::BufReader, path::PathBuf};

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use tracing::info;

use crate::revocation::Error;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: this seems a little wrong?


/// The structure contained in a manifest.json
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Manifest {
/// When this file was generated.
///
/// UNIX timestamp in seconds.
pub generated_at: u64,

/// Some human-readable text.
pub comment: String,

/// List of required files.
#[serde(alias = "filters")]
pub files: Vec<ManifestFile>,
}

impl Manifest {
#[cfg(feature = "__fetch")]
pub(crate) fn from_file(file_name: PathBuf) -> Result<Self, Error> {
let file = match File::open(&file_name) {
Ok(f) => f,
Err(error) => {
return Err(Error::FileRead {
error,
path: Some(file_name),
});
}
};

serde_json::from_reader(BufReader::new(file)).map_err(|error| Error::FileDecode {
error: Box::new(error),
path: Some(file_name),
})
}

/// Logs metadata fields in this manifest.
pub fn introduce(&self) -> Result<(), Error> {
let dt = match DateTime::<Utc>::from_timestamp(self.generated_at as i64, 0) {
Some(dt) => dt.to_rfc3339(),
None => {
return Err(Error::InvalidTimestamp {
input: self.generated_at.to_string(),
context: "manifest generated (in s)",
});
}
};

info!(comment = self.comment, date = dt, "parsed manifest");
Ok(())
}
}

/// Manifest data for a single manifest file.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ManifestFile {
/// Relative filename.
///
/// This is also the suggested local filename.
pub filename: String,

/// File size, indicative. Allows a fetcher to predict data usage.
pub size: usize,

/// SHA256 hash of file contents.
#[serde(with = "hex::serde")]
pub hash: Vec<u8>,
}
20 changes: 20 additions & 0 deletions upki/src/intermediates.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use serde::{Deserialize, Serialize};

/// Details about intermediate preloading.
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case", deny_unknown_fields, default)]
pub struct IntermediatesConfig {
/// Whether to fetch things at all.
pub enabled: bool,
/// Where to fetch intermediate certificates.
pub fetch_url: String,
}

impl Default for IntermediatesConfig {
fn default() -> Self {
Self {
enabled: false,
fetch_url: "https://upki.rustls.dev/intermediates/".into(),
}
}
}
13 changes: 13 additions & 0 deletions upki/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ pub(crate) mod sha256;

/// Determining revocation status of publicly trusted certificates.
pub mod revocation;

/// Fetching intermediate certificates to assist chain building.
pub mod intermediates;

/// Common data storage formats.
pub mod data;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think the revocation mod declaration and the import from it should be kept together.


use crate::intermediates::IntermediatesConfig;
use crate::revocation::RevocationConfig;

/// Foreign function interface.
Expand All @@ -29,6 +37,10 @@ pub struct Config {

/// Configuration for crlite-style revocation.
pub revocation: RevocationConfig,

/// Configuration for intermediate preloading.
#[serde(default)]
pub intermediates: IntermediatesConfig,
}

impl Config {
Expand Down Expand Up @@ -71,6 +83,7 @@ impl Config {
}
},
revocation: RevocationConfig::default(),
intermediates: IntermediatesConfig::default(),
})
}

Expand Down
Loading