Skip to content
Merged
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
17 changes: 16 additions & 1 deletion crates/mtc_api/src/subtree_cosignature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ed25519_dalek::{
};
use length_prefixed::WriteLengthPrefixedBytesExt;
use signed_note::{compute_key_id, KeyName, NoteError, NoteSignature, NoteVerifier, SignatureType};
use tlog_tiles::{CheckpointText, CheckpointSigner, Hash, LeafIndex, UnixTimestamp};
use tlog_tiles::{CheckpointSigner, CheckpointText, Hash, LeafIndex, UnixTimestamp};

#[derive(Clone)]
pub struct TrustAnchorID(pub Vec<u8>);
Expand Down Expand Up @@ -56,6 +56,21 @@ impl MTCSubtreeCosigner {

Ok(self.k.try_sign(&serialized)?.to_vec())
}

/// Return the log ID as bytes.
pub fn log_id(&self) -> &[u8] {
&self.v.log_id.0
}

/// Return the cosigner ID as bytes.
pub fn cosigner_id(&self) -> &[u8] {
&self.v.cosigner_id.0
}

/// Return the verifying key as bytes.
pub fn verifying_key(&self) -> &[u8] {
self.v.verifying_key.as_bytes()
}
}

/// Support signing tlog-checkpoint with the subtree cosigner.
Expand Down
3 changes: 2 additions & 1 deletion crates/mtc_worker/config.bootstrap-mtca.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"logs": {
"shard1": {
"description": "Cloudflare bootstrap MTCA shard 1",
"log_id": "13335.1",
"log_id": "44363.48.5",
"cosigner_id": "44363.48.6",
"submission_url": "https://bootstrap-mtca.cloudflareresearch.com/logs/shard1/",
"monitoring_url": "https://bootstrap-mtca-shard1.cloudflareresearch.com"
}
Expand Down
6 changes: 4 additions & 2 deletions crates/mtc_worker/config.dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
"logs": {
"dev1": {
"description": "MTCA Dev1",
"log_id": "13335.1",
"log_id": "44363.48.1",
"cosigner_id": "44363.48.2",
"submission_url": "http://localhost:8787/logs/dev1/",
"location_hint": "enam"
},
"dev2": {
"description": "MTCA Dev2",
"log_id": "13335.2",
"log_id": "44363.48.3",
"cosigner_id": "44363.48.4",
"submission_url": "http://localhost:8787/logs/dev2/",
"location_hint": "enam",
"max_certificate_lifetime_secs": 100,
Expand Down
6 changes: 5 additions & 1 deletion crates/mtc_worker/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
},
"log_id": {
"type": "string",
"description": "The log name (a trust anchor ID) in dotted decimal notation (e.g., 32473.1)."
"description": "The log ID (a trust anchor ID) in dotted decimal notation (e.g., 32473.1)."
},
"cosigner_id": {
"type": "string",
"description": "The cosigner's ID (a trust anchor ID) in dotted decimal notation (e.g., 32473.1)."
},
"max_certificate_lifetime_secs": {
"type": "integer",
Expand Down
1 change: 1 addition & 0 deletions crates/mtc_worker/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct AppConfig {
pub struct LogParams {
pub description: Option<String>,
pub log_id: String,
pub cosigner_id: String,
#[serde(default = "default_usize::<604_800>")]
pub max_certificate_lifetime_secs: usize,
#[serde(default = "default_usize::<3600>")]
Expand Down
11 changes: 3 additions & 8 deletions crates/mtc_worker/src/cleaner_do.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::time::Duration;

use crate::{load_checkpoint_signers, load_origin, CONFIG};
use crate::{load_cosigner, load_origin, CONFIG};
use generic_log_worker::{get_durable_object_name, CleanerConfig, GenericCleaner, CLEANER_BINDING};
use mtc_api::BootstrapMtcPendingLogEntry;
use signed_note::VerifierList;
use tlog_tiles::PendingLogEntry;
use tlog_tiles::{CheckpointSigner, PendingLogEntry};
#[allow(clippy::wildcard_imports)]
use worker::*;

Expand All @@ -26,12 +26,7 @@ impl DurableObject for Cleaner {
origin: load_origin(name),
data_path: BootstrapMtcPendingLogEntry::DATA_TILE_PATH,
aux_path: BootstrapMtcPendingLogEntry::AUX_TILE_PATH,
verifiers: VerifierList::new(
load_checkpoint_signers(&env, name)
.iter()
.map(|s| s.verifier())
.collect(),
),
verifiers: VerifierList::new(vec![load_cosigner(&env, name).verifier()]),
clean_interval: Duration::from_secs(params.clean_interval_secs),
};

Expand Down
32 changes: 14 additions & 18 deletions crates/mtc_worker/src/frontend_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

//! Entrypoint for the static CT submission APIs.

use crate::{
load_checkpoint_signers, load_origin, load_roots, load_signing_key, SequenceMetadata, CONFIG,
};
use crate::{load_cosigner, load_origin, load_roots, SequenceMetadata, CONFIG};
use der::{
asn1::{SetOfVec, UtcTime, Utf8StringRef},
Any, Encode, Tag,
Expand All @@ -24,13 +22,13 @@ use mtc_api::{
serialize_signatureless_cert, AddEntryRequest, AddEntryResponse, BootstrapMtcLogEntry,
GetRootsResponse, LandmarkSequence, ID_RDNA_TRUSTANCHOR_ID, LANDMARK_KEY,
};
use p256::pkcs8::EncodePublicKey;
use serde::{Deserialize, Serialize};
use serde_with::{base64::Base64, serde_as};
use signed_note::{NoteVerifier, VerifierList};
use signed_note::VerifierList;
use std::time::Duration;
use tlog_tiles::{
open_checkpoint, CheckpointText, LeafIndex, PendingLogEntry, PendingLogEntryBlob,
open_checkpoint, CheckpointSigner, CheckpointText, LeafIndex, PendingLogEntry,
PendingLogEntryBlob,
};
#[allow(clippy::wildcard_imports)]
use worker::*;
Expand All @@ -48,7 +46,11 @@ struct MetadataResponse<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
description: &'a Option<String>,
#[serde_as(as = "Base64")]
key: &'a [u8],
log_id: &'a [u8],
#[serde_as(as = "Base64")]
cosigner_id: &'a [u8],
#[serde_as(as = "Base64")]
cosigner_public_key: &'a [u8],
submission_url: &'a str,
monitoring_url: &'a str,
}
Expand Down Expand Up @@ -222,13 +224,12 @@ async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
.get("/logs/:log/metadata", |_req, ctx| {
let name = ctx.data;
let params = &CONFIG.logs[name];
let verifying_key = load_signing_key(&ctx.env, name)?.verifying_key();
let key = verifying_key
.to_public_key_der()
.map_err(|e| e.to_string())?;
let cosigner = load_cosigner(&ctx.env, name);
Response::from_json(&MetadataResponse {
description: &params.description,
key: key.as_bytes(),
log_id: cosigner.log_id(),
cosigner_id: cosigner.cosigner_id(),
cosigner_public_key: cosigner.verifying_key(),
submission_url: &params.submission_url,
monitoring_url: if params.monitoring_url.is_empty() {
&params.submission_url
Expand Down Expand Up @@ -461,12 +462,7 @@ async fn get_current_checkpoint(
.ok_or("no checkpoint in object storage".to_string())?;

let origin = &load_origin(name);
let verifiers = &VerifierList::new(
load_checkpoint_signers(env, name)
.iter()
.map(|s| s.verifier())
.collect::<Vec<Box<dyn NoteVerifier>>>(),
);
let verifiers = &VerifierList::new(vec![load_cosigner(env, name).verifier()]);
let (checkpoint, _timestamp) =
open_checkpoint(origin.as_str(), verifiers, now_millis(), &checkpoint_bytes)
.map_err(|e| e.to_string())?;
Expand Down
27 changes: 15 additions & 12 deletions crates/mtc_worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use signed_note::KeyName;
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::{LazyLock, OnceLock};
use tlog_tiles::{CheckpointSigner, SequenceMetadata};
use tlog_tiles::SequenceMetadata;
use tokio::sync::OnceCell;
#[allow(clippy::wildcard_imports)]
use worker::*;
Expand Down Expand Up @@ -59,23 +59,26 @@ pub(crate) fn load_ed25519_key(
}
}

pub(crate) fn load_checkpoint_signers(env: &Env, name: &str) -> Vec<Box<dyn CheckpointSigner>> {
pub(crate) fn load_cosigner(env: &Env, name: &str) -> MTCSubtreeCosigner {
let origin = load_origin(name);

// Parse the log ID, an ASN.1 `RELATIVE OID` in decimal-dotted string form.
let log_id_relative_oid = RelativeOid::from_str(&CONFIG.logs[name].log_id).unwrap();
let log_id = {
let relative_oid = RelativeOid::from_str(&CONFIG.logs[name].log_id).unwrap();
// Get the BER/DER serialization of the content bytes, as described in
// <https://datatracker.ietf.org/doc/html/draft-ietf-tls-trust-anchor-ids-01#name-trust-anchor-identifiers>.
TrustAnchorID(relative_oid.as_bytes().to_vec())
};

// Likewise for the cosigner ID.
let cosigner_id = {
let relative_oid = RelativeOid::from_str(&CONFIG.logs[name].cosigner_id).unwrap();
TrustAnchorID(relative_oid.as_bytes().to_vec())
};

// Get the BER/DER serialization of the content bytes, as described in <https://datatracker.ietf.org/doc/html/draft-ietf-tls-trust-anchor-ids-01#name-trust-anchor-identifiers>.
let log_id = TrustAnchorID(log_id_relative_oid.as_bytes().to_vec());

// TODO should the CA cosigner have a different ID than the log itself?
let cosigner_id = log_id.clone();
let signing_key = load_signing_key(env, name).unwrap().clone();

// Make the checkpoint signers from the secret keys and put them in a vec
let signer = MTCSubtreeCosigner::new(cosigner_id, log_id, origin.clone(), signing_key);

vec![Box::new(signer)]
MTCSubtreeCosigner::new(cosigner_id, log_id, origin.clone(), signing_key)
}

pub(crate) fn load_origin(name: &str) -> KeyName {
Expand Down
4 changes: 2 additions & 2 deletions crates/mtc_worker/src/sequencer_do.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use std::{future::Future, pin::Pin, time::Duration};

use crate::{load_checkpoint_signers, load_origin, CONFIG};
use crate::{load_cosigner, load_origin, CONFIG};
use generic_log_worker::{
get_durable_object_name, load_public_bucket, CheckpointCallbacker, GenericSequencer,
SequencerConfig, SEQUENCER_BINDING,
Expand All @@ -31,7 +31,7 @@ impl DurableObject for Sequencer {
let config = SequencerConfig {
name: name.to_string(),
origin: load_origin(name),
checkpoint_signers: load_checkpoint_signers(&env, name),
checkpoint_signers: vec![Box::new(load_cosigner(&env, name))],
checkpoint_extension: Box::new(|_| vec![]), // no checkpoint extension for MTC
sequence_interval: Duration::from_millis(params.sequence_interval_millis),
max_sequence_skips: params.max_sequence_skips,
Expand Down