From c345c6637d5e2c27be64e5c6b4976ebc215aa191 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Tue, 19 Dec 2023 10:30:18 +0100 Subject: [PATCH] Allow overriding the TA manifest number. --- .gitignore | 1 + src/cli/ta_client.rs | 76 +++++++++++++++++++++++++++++-------- src/commons/api/import.rs | 11 +++--- src/daemon/ca/manager.rs | 4 +- src/daemon/ca/publishing.rs | 10 +++-- src/daemon/krillserver.rs | 5 +-- src/ta/common.rs | 17 +++++++-- src/ta/mod.rs | 10 +++-- src/ta/signer.rs | 65 +++++++++++++++++++++---------- 9 files changed, 146 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index b239de2c7..178f54ffe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .cargo .idea/ +.locks .vscode/ .DS_Store data/ diff --git a/src/cli/ta_client.rs b/src/cli/ta_client.rs index 418652b0f..780fb3b82 100644 --- a/src/cli/ta_client.rs +++ b/src/cli/ta_client.rs @@ -148,7 +148,10 @@ pub struct SignerCommand { pub enum SignerCommandDetails { Init(SignerInitInfo), ShowInfo, - ProcessRequest(TrustAnchorSignedRequest), + ProcessRequest { + signed_request: TrustAnchorSignedRequest, + ta_mft_number_override: Option, + }, ShowLastResponse, ShowExchanges, } @@ -160,6 +163,7 @@ pub struct SignerInitInfo { tal_https: Vec, tal_rsync: uri::Rsync, private_key_pem: Option, + ta_mft_nr_override: Option, } impl TrustAnchorClientCommand { @@ -405,6 +409,13 @@ impl TrustAnchorClientCommand { .value_name("path") .help("[OPTIONAL] Import an existing private key in PEM format") .required(false), + ) + .arg( + Arg::with_name("initial_manifest_number") + .long("initial_manifest_number") + .value_name("number") + .help("[OPTIONAL] Override the initial manifest number (defaults to 1)") + .required(false), ); app.subcommand(sub) @@ -422,15 +433,22 @@ impl TrustAnchorClientCommand { sub = Self::add_config_arg(sub); sub = Self::add_format_arg(sub); - sub = sub.arg( - Arg::with_name("request") - .long("request") - .short("r") - .value_name("file") - .help("Path to TA Proxy request file (JSON)") - .required(true), - ); - + sub = sub + .arg( + Arg::with_name("request") + .long("request") + .short("r") + .value_name("file") + .help("Path to TA Proxy request file (JSON)") + .required(true), + ) + .arg( + Arg::with_name("ta_mft_number_override") + .long("ta_mft_number_override") + .value_name("number") + .help("[OPTIONAL] Override the next manifest number (defaults to last + 1)") + .required(false), + ); app.subcommand(sub) } @@ -727,6 +745,13 @@ impl TrustAnchorClientCommand { .map_err(|_| TaClientError::Other(format!("Invalid rsync uri: {}", rsync_str)))? }; + let ta_mft_nr_override = if let Some(number) = matches.value_of("initial_manifest_number") { + let nr = u64::from_str(number).map_err(|_| TaClientError::other("Invalid manifest number, must be >1"))?; + Some(nr) + } else { + None + }; + let private_key_pem = if let Some(path) = matches.value_of("private_key_pem") { let bytes = Self::read_file_arg(path)?; let pem = std::str::from_utf8(&bytes) @@ -741,6 +766,7 @@ impl TrustAnchorClientCommand { repo_info, tal_https, tal_rsync, + ta_mft_nr_override, private_key_pem, }; let details = SignerCommandDetails::Init(info); @@ -766,12 +792,23 @@ impl TrustAnchorClientCommand { fn parse_matches_signer_process(matches: &ArgMatches) -> Result { let config = Self::parse_config(matches)?; let format = Self::parse_format(matches)?; - let request = Self::read_json(matches.value_of("request").unwrap())?; + let signed_request = Self::read_json(matches.value_of("request").unwrap())?; + + let ta_mft_number_override = if let Some(nr_str) = matches.value_of("ta_mft_number_override") { + let nr = u64::from_str(nr_str) + .map_err(|_| TaClientError::other("Invalid number for ta_mft_number_override, must be >1"))?; + Some(nr) + } else { + None + }; Ok(TrustAnchorClientCommand::Signer(SignerCommand { config, format, - details: SignerCommandDetails::ProcessRequest(request), + details: SignerCommandDetails::ProcessRequest { + signed_request, + ta_mft_number_override, + }, })) } @@ -877,7 +914,10 @@ impl TrustAnchorClient { match signer_command.details { SignerCommandDetails::Init(info) => signer_manager.init(info), SignerCommandDetails::ShowInfo => signer_manager.show(), - SignerCommandDetails::ProcessRequest(request) => signer_manager.process(request), + SignerCommandDetails::ProcessRequest { + signed_request, + ta_mft_number_override, + } => signer_manager.process(signed_request, ta_mft_number_override), SignerCommandDetails::ShowLastResponse => signer_manager.show_last_response(), SignerCommandDetails::ShowExchanges => signer_manager.show_exchanges(), } @@ -1032,6 +1072,7 @@ impl TrustAnchorSignerManager { tal_https: info.tal_https, tal_rsync: info.tal_rsync, private_key_pem: info.private_key_pem, + ta_mft_nr_override: info.ta_mft_nr_override, timing: self.config.timing_config, signer: self.signer.clone(), }, @@ -1050,11 +1091,16 @@ impl TrustAnchorSignerManager { Ok(TrustAnchorClientApiResponse::TrustAnchorProxySignerInfo(info)) } - fn process(&self, request: TrustAnchorSignedRequest) -> Result { + fn process( + &self, + signed_request: TrustAnchorSignedRequest, + ta_mft_number_override: Option, + ) -> Result { let cmd = TrustAnchorSignerCommand::make_process_request_command( &self.ta_handle, - request, + signed_request, self.config.timing_config, + ta_mft_number_override, self.signer.clone(), &self.actor, ); diff --git a/src/commons/api/import.rs b/src/commons/api/import.rs index 30e29b103..2f3fe776b 100644 --- a/src/commons/api/import.rs +++ b/src/commons/api/import.rs @@ -37,10 +37,9 @@ pub struct Structure { } impl Structure { - pub fn new( + pub fn for_testbed( ta_aia: uri::Rsync, ta_uri: uri::Https, - ta_key_pem: Option, publication_server_uris: PublicationServerUris, cas: Vec, ) -> Self { @@ -48,7 +47,8 @@ impl Structure { ta: Some(ImportTa { ta_aia, ta_uri, - ta_key_pem, + ta_key_pem: None, + ta_mft_nr_override: None, }), publication_server: Some(publication_server_uris), cas, @@ -129,11 +129,12 @@ pub struct ImportTa { pub ta_aia: uri::Rsync, pub ta_uri: uri::Https, pub ta_key_pem: Option, + pub ta_mft_nr_override: Option, } impl ImportTa { - pub fn unpack(self) -> (uri::Rsync, Vec, Option) { - (self.ta_aia, vec![self.ta_uri], self.ta_key_pem) + pub fn unpack(self) -> (uri::Rsync, Vec, Option, Option) { + (self.ta_aia, vec![self.ta_uri], self.ta_key_pem, self.ta_mft_nr_override) } } diff --git a/src/daemon/ca/manager.rs b/src/daemon/ca/manager.rs index 6c6a50fbf..d71358298 100644 --- a/src/daemon/ca/manager.rs +++ b/src/daemon/ca/manager.rs @@ -332,6 +332,7 @@ impl CaManager { tal_https, tal_rsync, private_key_pem, + ta_mft_nr_override: None, timing: self.config.ta_timing, signer: self.signer.clone(), }; @@ -1243,7 +1244,7 @@ impl CaManager { } } - /// Synchronise the Trust Anchor Proxy with the Signer - it the Signer is local. + /// Synchronise the Trust Anchor Proxy with the Signer - if the Signer is local. pub async fn sync_ta_proxy_signer_if_possible(&self) -> KrillResult<()> { let ta_handle = ta_handle(); @@ -1262,6 +1263,7 @@ impl CaManager { &ta_handle, signed_request, self.config.ta_timing, + None, // do not override next manifest number self.signer.clone(), &self.system_actor, ); diff --git a/src/daemon/ca/publishing.rs b/src/daemon/ca/publishing.rs index 13648dd86..a27e98444 100644 --- a/src/daemon/ca/publishing.rs +++ b/src/daemon/ca/publishing.rs @@ -1016,7 +1016,7 @@ impl KeyObjectSet { self.revision.next_update.to_rfc3339() ); - self.revision.next(timing.publish_next()); + self.revision.next(timing.publish_next(), None); self.revocations.remove_expired(); let signing_key = self.signing_cert.key_identifier(); @@ -1101,8 +1101,12 @@ impl ObjectSetRevision { } } - pub fn next(&mut self, next_update: Time) { - self.number += 1; + pub fn next(&mut self, next_update: Time, mft_number_override: Option) { + if let Some(forced_next) = mft_number_override { + self.number = forced_next; + } else { + self.number += 1; + } self.this_update = Time::five_minutes_ago(); self.next_update = next_update; } diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index 15bc55051..3d96ed8ec 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -240,10 +240,9 @@ impl KrillServer { } } - let startup_structure = api::import::Structure::new( + let startup_structure = api::import::Structure::for_testbed( testbed.ta_aia().clone(), testbed.ta_uri().clone(), - None, testbed.publication_server_uris(), import_cas, ); @@ -595,7 +594,7 @@ impl KrillServer { if let Some(import_ta) = structure.ta.clone() { if self.config.ta_proxy_enabled() && self.config.ta_signer_enabled() { info!("Creating embedded Trust Anchor"); - let (ta_aia, ta_uris, ta_key_pem) = import_ta.unpack(); + let (ta_aia, ta_uris, ta_key_pem, _ta_mft_nr_override) = import_ta.unpack(); self.ca_manager .ta_init_fully_embedded(ta_aia, ta_uris, ta_key_pem, &self.repo_manager, &actor) .await?; diff --git a/src/ta/common.rs b/src/ta/common.rs index 85a5aed46..d6943e797 100644 --- a/src/ta/common.rs +++ b/src/ta/common.rs @@ -70,8 +70,17 @@ pub struct TrustAnchorObjects { impl TrustAnchorObjects { /// Creates a new TrustAnchorObjects for the signing certificate. - pub fn create(signing_cert: &ReceivedCert, next_update_weeks: i64, signer: &KrillSigner) -> KrillResult { - let revision = ObjectSetRevision::new(1, Self::this_update(), Self::next_update(next_update_weeks)); + pub fn create( + signing_cert: &ReceivedCert, + initial_number: u64, + next_update_weeks: i64, + signer: &KrillSigner, + ) -> KrillResult { + let revision = ObjectSetRevision::new( + initial_number, + Self::this_update(), + Self::next_update(next_update_weeks), + ); let key_identifier = signing_cert.key_identifier(); let base_uri = signing_cert.ca_repository().clone(); let revocations = Revocations::default(); @@ -104,9 +113,11 @@ impl TrustAnchorObjects { &mut self, signing_cert: &ReceivedCert, next_update_weeks: i64, + mft_number_override: Option, signer: &KrillSigner, ) -> KrillResult<()> { - self.revision.next(Self::next_update(next_update_weeks)); + self.revision + .next(Self::next_update(next_update_weeks), mft_number_override); let signing_key = signing_cert.key_identifier(); diff --git a/src/ta/mod.rs b/src/ta/mod.rs index 7dbb67f24..e387bd094 100644 --- a/src/ta/mod.rs +++ b/src/ta/mod.rs @@ -106,6 +106,7 @@ mod tests { tal_https: tal_https.clone(), tal_rsync: tal_rsync.clone(), private_key_pem: Some(import_key_pem.to_string()), + ta_mft_nr_override: Some(42), timing, signer: signer.clone(), }, @@ -119,9 +120,9 @@ mod tests { proxy = ta_proxy_store.command(add_signer_cmd).unwrap(); // The initial signer starts off with a TA certificate - // and a CRL and manifest with revision number 1. + // and a CRL and manifest with revision number 42, as specified in the init. let ta_objects = proxy.get_trust_anchor_objects().unwrap(); - assert_eq!(ta_objects.revision().number(), 1); + assert_eq!(ta_objects.revision().number(), 42); let ta_cert_details = proxy.get_ta_details().unwrap(); assert_eq!(ta_cert_details.tal().uris(), &tal_https); @@ -139,6 +140,7 @@ mod tests { &signer_handle, signed_request, timing, + Some(55), // override the next manifest number again signer, &actor, ); @@ -153,9 +155,9 @@ mod tests { .unwrap(); // The TA should have published again, the revision used for manifest and crl will - // have been updated. + // have been updated to the overridden number. let ta_objects = proxy.get_trust_anchor_objects().unwrap(); - assert_eq!(ta_objects.revision().number(), 2); + assert_eq!(ta_objects.revision().number(), 55); // We still need to test some higher order functions: // - add child diff --git a/src/ta/signer.rs b/src/ta/signer.rs index fa9f58a42..46eea3b88 100644 --- a/src/ta/signer.rs +++ b/src/ta/signer.rs @@ -73,6 +73,7 @@ pub struct TrustAnchorSignerInitCommandDetails { pub tal_https: Vec, pub tal_rsync: uri::Rsync, pub private_key_pem: Option, + pub ta_mft_nr_override: Option, pub timing: TaTimingConfig, pub signer: Arc, } @@ -137,7 +138,12 @@ impl fmt::Display for TrustAnchorSignerEvent { // Commands #[derive(Clone, Debug)] pub enum TrustAnchorSignerCommandDetails { - TrustAnchorSignerRequest(TrustAnchorSignedRequest, TaTimingConfig, Arc), + TrustAnchorSignerRequest { + signed_request: TrustAnchorSignedRequest, + ta_timing_config: TaTimingConfig, + ta_mft_number_override: Option, + signer: Arc, + }, } impl eventsourcing::CommandDetails for TrustAnchorSignerCommandDetails { @@ -158,15 +164,21 @@ impl fmt::Display for TrustAnchorSignerCommandDetails { impl TrustAnchorSignerCommand { pub fn make_process_request_command( id: &TrustAnchorHandle, - request: TrustAnchorSignedRequest, - timing: TaTimingConfig, + signed_request: TrustAnchorSignedRequest, + ta_timing_config: TaTimingConfig, + ta_mft_number_override: Option, signer: Arc, actor: &Actor, ) -> TrustAnchorSignerCommand { TrustAnchorSignerCommand::new( id, None, - TrustAnchorSignerCommandDetails::TrustAnchorSignerRequest(request, timing, signer), + TrustAnchorSignerCommandDetails::TrustAnchorSignerRequest { + signed_request, + ta_timing_config, + ta_mft_number_override, + signer, + }, actor, ) } @@ -182,8 +194,8 @@ pub enum TrustAnchorSignerStorableCommand { impl From<&TrustAnchorSignerCommandDetails> for TrustAnchorSignerStorableCommand { fn from(details: &TrustAnchorSignerCommandDetails) -> Self { match details { - TrustAnchorSignerCommandDetails::TrustAnchorSignerRequest(request, _, _) => { - TrustAnchorSignerStorableCommand::TrustAnchorSignerRequest(request.clone()) + TrustAnchorSignerCommandDetails::TrustAnchorSignerRequest { signed_request, .. } => { + TrustAnchorSignerStorableCommand::TrustAnchorSignerRequest(signed_request.clone()) } } } @@ -258,7 +270,12 @@ impl eventsourcing::Aggregate for TrustAnchorSigner { timing.certificate_validity_years, &signer, )?; - let objects = TrustAnchorObjects::create(ta_cert_details.cert(), timing.mft_next_update_weeks, &signer)?; + let objects = TrustAnchorObjects::create( + ta_cert_details.cert(), + cmd.ta_mft_nr_override.unwrap_or(1), + timing.mft_next_update_weeks, + &signer, + )?; Ok(TrustAnchorSignerInitEvent { id, @@ -305,9 +322,12 @@ impl eventsourcing::Aggregate for TrustAnchorSigner { } match command.into_details() { - TrustAnchorSignerCommandDetails::TrustAnchorSignerRequest(request, timing, signer) => { - self.process_signer_request(request, timing, &signer) - } + TrustAnchorSignerCommandDetails::TrustAnchorSignerRequest { + signed_request, + ta_timing_config, + ta_mft_number_override, + signer, + } => self.process_signer_request(signed_request, ta_timing_config, ta_mft_number_override, &signer), } } } @@ -391,13 +411,14 @@ impl TrustAnchorSigner { /// Process a request. fn process_signer_request( &self, - request: TrustAnchorSignedRequest, - timing: TaTimingConfig, + signed_request: TrustAnchorSignedRequest, + ta_timing_config: TaTimingConfig, + ta_mft_number_override: Option, signer: &KrillSigner, ) -> KrillResult> { // Let's first make sure this request is valid // and the 'content' is not tampered with. - request.validate(&self.proxy_id)?; + signed_request.validate(&self.proxy_id)?; let mut objects = self.objects.clone(); @@ -406,7 +427,7 @@ impl TrustAnchorSigner { let signing_cert = self.ta_cert_details.cert(); let ta_rcn = ta_resource_class_name(); - for child_request in &request.content().child_requests { + for child_request in &signed_request.content().child_requests { let mut responses = HashMap::new(); for (key_id, provisioning_request) in child_request.requests.clone() { @@ -421,7 +442,8 @@ impl TrustAnchorSigner { ))); } - let validity = SignSupport::sign_validity_weeks(timing.issued_certificate_validity_weeks); + let validity = + SignSupport::sign_validity_weeks(ta_timing_config.issued_certificate_validity_weeks); let issue_resources = limit.apply_to(&child_request.resources)?; // Create issued certificate @@ -487,22 +509,27 @@ impl TrustAnchorSigner { child_responses.insert(child_request.child.clone(), responses); } - objects.republish(signing_cert, timing.mft_next_update_weeks, signer)?; + objects.republish( + signing_cert, + ta_timing_config.mft_next_update_weeks, + ta_mft_number_override, + signer, + )?; let response = TrustAnchorSignerResponse { - nonce: request.content().nonce.clone(), + nonce: signed_request.content().nonce.clone(), objects, child_responses, } .sign( - timing.signed_message_validity_days, + ta_timing_config.signed_message_validity_days, self.id.public_key().key_identifier(), signer, )?; let exchange = TrustAnchorProxySignerExchange { time: Time::now(), - request, + request: signed_request, response, };