Merge release 0.9.3-rc3

This commit is contained in:
Tim Bruijnzeels
2021-11-10 15:37:59 +01:00
committed by GitHub
8 changed files with 191 additions and 149 deletions
Generated
+3 -3
View File
@@ -779,7 +779,7 @@ dependencies = [
[[package]]
name = "krill"
version = "0.9.3-rc2"
version = "0.9.3-rc3"
dependencies = [
"base64 0.13.0",
"basic-cookies",
@@ -1537,9 +1537,9 @@ dependencies = [
[[package]]
name = "rpki"
version = "0.13.1-rc1"
version = "0.13.1-rc2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7c07c6977a509b11d01aae0d9dcf6e30f0dcfe46f9c3fcb4f47f7789a356e35"
checksum = "ec2e4c12ee5b7a4924508122b2020901f7a37c56fc68455c7860d8e96e9fc16d"
dependencies = [
"base64 0.13.0",
"bcder",
+2 -2
View File
@@ -1,7 +1,7 @@
[package]
# Note: some of these values are also used when building Debian packages below.
name = "krill"
version = "0.9.3-rc2"
version = "0.9.3-rc3"
edition = "2018"
authors = [ "The NLnet Labs RPKI team <rpki-team@nlnetlabs.nl>" ]
description = "Resource Public Key Infrastructure (RPKI) daemon"
@@ -44,7 +44,7 @@ rand = "^0.8"
regex = { version = "^1.4", optional = true, default_features = false, features = ["std"] }
reqwest = { version = "0.11", features = ["json"] }
rpassword = { version = "^5.0", optional = true }
rpki = { version = "0.13.1-rc1", features = [ "repository", "rrdp", "serde" ] }
rpki = { version = "0.13.1-rc2", features = [ "repository", "rrdp", "serde" ] }
# rpki = { version = "0.13.1-rc1", git = "https://github.com/NLnetLabs/rpki-rs/", features = [ "repository", "rrdp", "serde" ] }
scrypt = { version = "^0.6", optional = true, default-features = false }
serde = { version = "^1.0", features = ["derive"] }
+9
View File
@@ -1,7 +1,16 @@
# Change Log
<<<<<<< HEAD
## 0.9.3 (RC3) 'The Thundering Herd'
RC3 fixes the following issues in RC2:
- Use the, now official, ASPA OID (#700)
- Re-issue ASPA objects on key rolls (717)
=======
## 0.9.3 (RC2) 'The Thundering Herd'
>>>>>>> main
This release adds the following features and fixes:
- Prevent a thundering herd of hosted CAs publishing at the same time (#692)
- Re-issue ROAs to ensure that short EE subject names are used (#700)
+12
View File
@@ -335,6 +335,18 @@ impl IssuedCert {
pub fn replaces(&self) -> Option<&ReplacedObject> {
self.replaces.as_ref()
}
/// Returns a (possibly empty) set of reduced applicable resources which is the intersection
/// of the encompassing resources and this certificate's current resources.
/// Returns None if the current resource set is not overclaiming and does not need to be
/// reduced.
pub fn reduced_applicable_resources(&self, encompassing: &ResourceSet) -> Option<ResourceSet> {
if encompassing.contains(&self.resource_set) {
None
} else {
Some(encompassing.intersection(&self.resource_set))
}
}
}
impl PartialEq for IssuedCert {
+9 -5
View File
@@ -8,7 +8,6 @@
use std::{collections::HashMap, fmt::Debug};
use chrono::Duration;
use rpki::repository::{
aspa::{Aspa, AspaBuilder},
sigobj::SignedObjectBuilder,
@@ -190,19 +189,24 @@ impl AspaObjects {
Ok(object_updates)
}
// Re-new ASPAs before they would expire
// Re-new ASPAs, if the renew_threshold is specified, then
// only objects which will expire before that time will be
// renewed.
pub fn renew(
&self,
certified_key: &CertifiedKey,
renew_threshold: Option<Time>,
issuance_timing: &IssuanceTimingConfig,
signer: &KrillSigner,
) -> KrillResult<AspaObjectsUpdates> {
let mut updates = AspaObjectsUpdates::default();
let renew_threshold = Time::now() + Duration::weeks(issuance_timing.timing_aspa_reissue_weeks_before);
for aspa in self.0.values() {
if aspa.expires() < renew_threshold {
let renew = renew_threshold
.map(|threshold| aspa.expires() < threshold)
.unwrap_or(true); // always renew if no threshold is specified
if renew {
let aspa_definition = aspa.definition().clone();
let new_aspa = self.make_aspa(aspa_definition, certified_key, issuance_timing, signer)?;
+106 -8
View File
@@ -7,14 +7,17 @@ use rpki::repository::{crypto::KeyIdentifier, x509::Time};
use crate::{
commons::{
api::{
ChildCaInfo, ChildHandle, ChildState, IssuedCert, ResourceClassName, ResourceSet, SuspendedCert,
UnsuspendedCert,
ChildCaInfo, ChildHandle, ChildState, HexEncodedHash, IssuedCert, ReplacedObject, ResourceClassName,
ResourceSet, Revocation, SuspendedCert, UnsuspendedCert,
},
crypto::IdCert,
crypto::{CsrInfo, IdCert, KrillSigner, SignSupport},
error::Error,
KrillResult,
},
daemon::config::IssuanceTimingConfig,
daemon::{
ca::{CertifiedKey, ChildCertificateUpdates},
config::IssuanceTimingConfig,
},
};
//------------ UsedKeyState ------------------------------------------------
@@ -184,6 +187,105 @@ impl ChildCertificates {
self.issued.values()
}
/// Re-issue everything when activating a new key
pub fn activate_key(
&self,
new_key: &CertifiedKey,
issuance_timing: &IssuanceTimingConfig,
signer: &KrillSigner,
) -> KrillResult<ChildCertificateUpdates> {
let mut updates = ChildCertificateUpdates::default();
for issued in self.issued.values() {
updates.issue(self.re_issue(issued, None, new_key, issuance_timing, signer)?);
}
// Also re-issue suspended certificates, they may yet become unsuspended at some point
for suspended in self.suspended.values() {
updates.suspend(self.re_issue(suspended, None, new_key, issuance_timing, signer)?);
}
Ok(updates)
}
/// Shrink any overclaiming certificates.
///
/// NOTE: We need to pro-actively shrink child certificates to avoid invalidating them.
/// But, if we gain additional resources it is up to child to request a new certificate
/// with those resources.
pub fn shrink_overclaiming(
&self,
updated_key: &CertifiedKey,
issuance_timing: &IssuanceTimingConfig,
signer: &KrillSigner,
) -> KrillResult<ChildCertificateUpdates> {
let mut updates = ChildCertificateUpdates::default();
let updated_resources = updated_key.incoming_cert().resources();
for issued in self.issued.values() {
if let Some(reduced_set) = issued.reduced_applicable_resources(updated_resources) {
if reduced_set.is_empty() {
// revoke
updates.remove(issued.subject_key_identifier());
} else {
// re-issue
updates.issue(self.re_issue(issued, Some(reduced_set), updated_key, issuance_timing, signer)?);
}
}
}
// Also shrink suspended, in case they would come back
for suspended in self.suspended.values() {
if let Some(reduced_set) = suspended.reduced_applicable_resources(updated_resources) {
if reduced_set.is_empty() {
// revoke
updates.remove(suspended.subject_key_identifier());
} else {
// re-issue shrunk suspended
//
// Note: this will not be published yet, but remain suspended
// until the child contacts us again, or is manually
// un-suspended.
updates.suspend(self.re_issue(
suspended,
Some(reduced_set),
updated_key,
issuance_timing,
signer,
)?);
}
}
}
Ok(updates)
}
/// Re-issue a delegated certificate to replace an earlier
/// one which is about to be outdated or has changed resources.
fn re_issue(
&self,
previous: &IssuedCert,
updated_resources: Option<ResourceSet>,
signing_key: &CertifiedKey,
issuance_timing: &IssuanceTimingConfig,
signer: &KrillSigner,
) -> KrillResult<IssuedCert> {
let (_uri, limit, resource_set, cert) = previous.clone().unpack();
let csr = CsrInfo::from(&cert);
let resource_set = updated_resources.unwrap_or(resource_set);
let replaced = ReplacedObject::new(Revocation::from(&cert), HexEncodedHash::from(&cert));
let re_issued = SignSupport::make_issued_cert(
csr,
&resource_set,
limit,
Some(replaced),
signing_key,
issuance_timing.timing_child_certificate_valid_weeks,
signer,
)?;
Ok(re_issued)
}
pub fn expiring(&self, issuance_timing: &IssuanceTimingConfig) -> Vec<&IssuedCert> {
self.issued
.values()
@@ -200,10 +302,6 @@ impl ChildCertificates {
.filter(|issued| !resources.contains(issued.resource_set()))
.collect()
}
pub fn iter(&self) -> impl Iterator<Item = &IssuedCert> {
self.issued.values()
}
}
impl Default for ChildCertificates {
+47 -79
View File
@@ -10,16 +10,16 @@ use rpki::repository::{
use crate::{
commons::{
api::{
EntitlementClass, Handle, HexEncodedHash, IssuanceRequest, IssuedCert, ParentHandle, RcvdCert,
ReplacedObject, RepoInfo, RequestResourceLimit, ResourceClassInfo, ResourceClassName, ResourceSet,
Revocation, RevocationRequest, SuspendedCert, UnsuspendedCert,
EntitlementClass, Handle, IssuanceRequest, IssuedCert, ParentHandle, RcvdCert, ReplacedObject, RepoInfo,
RequestResourceLimit, ResourceClassInfo, ResourceClassName, ResourceSet, RevocationRequest, SuspendedCert,
UnsuspendedCert,
},
crypto::{CsrInfo, KrillSigner, SignSupport},
error::Error,
KrillResult,
},
daemon::{
ca::events::{ChildCertificateUpdates, RoaUpdates},
ca::events::RoaUpdates,
ca::{
self, ta_handle, AspaObjects, AspaObjectsUpdates, CaEvtDet, CertifiedKey, ChildCertificates, CurrentKey,
KeyState, NewKey, OldKey, PendingKey, Roas, Routes,
@@ -301,31 +301,13 @@ impl ResourceClass {
rcvd_cert.validity().not_after().to_rfc3339()
);
// Check whether child certificates should be shrunk
//
// NOTE: We need to pro-actively shrink child certificates to avoid invalidating them.
// But, if we gain additional resources it is up to child to request a new certificate
// with those resources.
//
let mut updates = ChildCertificateUpdates::default();
for issued in self.certificates.overclaiming(rcvd_resources) {
let remaining_resources = issued.resource_set().intersection(rcvd_resources);
if remaining_resources.is_empty() {
// revoke
updates.remove(issued.subject_key_identifier());
} else {
// re-issue
let re_issued = self.re_issue(
issued,
Some(remaining_resources),
current_key,
None,
&config.issuance_timing,
signer,
)?;
updates.issue(re_issued);
}
}
// Prep certified key for updated received certificate
let updated_key = CertifiedKey::create(rcvd_cert);
// Shrink any overclaiming child certificates
let updates = self
.certificates
.shrink_overclaiming(&updated_key, &config.issuance_timing, signer)?;
if !updates.is_empty() {
res.push(CaEvtDet::ChildCertificatesUpdated {
resource_class_name: self.name.clone(),
@@ -333,11 +315,10 @@ impl ResourceClass {
});
}
let certified_key = CertifiedKey::create(rcvd_cert);
// Check whether ROAs need to be re-issued.
// Re-issue ROAs based on updated resources.
// Note that route definitions will not have changed in this case, but the decision logic is all the same.
{
let updates = self.roas.update(routes, &certified_key, config, signer)?;
let updates = self.roas.update(routes, &updated_key, config, signer)?;
if !updates.is_empty() {
res.push(CaEvtDet::RoasUpdated {
resource_class_name: self.name.clone(),
@@ -346,9 +327,10 @@ impl ResourceClass {
}
}
// Check whether ASPA objects need to be re-issued
// Re-issue ASPA objects based on updated resources.
// Note that aspa definitions will not have changed in this case, but the decision logic is all the same.
{
let updates = self.aspas.update(aspas, &certified_key, config, signer)?;
let updates = self.aspas.update(aspas, &updated_key, config, signer)?;
if !updates.is_empty() {
res.push(CaEvtDet::AspaObjectsUpdated {
resource_class_name: self.name.clone(),
@@ -543,24 +525,36 @@ impl ResourceClass {
self.key_state
.keyroll_activate(self.name.clone(), self.parent_rc_name.clone(), signer)?;
let roa_updates = self.roas.activate_key(new_key, issuance_timing, signer)?;
let roas_updated = CaEvtDet::RoasUpdated {
resource_class_name: self.name.clone(),
updates: roa_updates,
};
let mut events = vec![key_activated];
let mut cert_updates = ChildCertificateUpdates::default();
for issued in self.certificates.iter() {
// re-issue
let re_issued = self.re_issue(issued, None, new_key, None, issuance_timing, signer)?;
cert_updates.issue(re_issued);
let roa_updates = self.roas.renew(true, new_key, issuance_timing, signer)?;
if !roa_updates.is_empty() {
let roas_updated = CaEvtDet::RoasUpdated {
resource_class_name: self.name.clone(),
updates: roa_updates,
};
events.push(roas_updated);
}
let certs_updated = CaEvtDet::ChildCertificatesUpdated {
resource_class_name: self.name.clone(),
updates: cert_updates,
};
Ok(vec![key_activated, roas_updated, certs_updated])
let aspa_updates = self.aspas.renew(new_key, None, issuance_timing, signer)?;
if !aspa_updates.is_empty() {
let aspas_updated = CaEvtDet::AspaObjectsUpdated {
resource_class_name: self.name.clone(),
updates: aspa_updates,
};
events.push(aspas_updated);
}
let cert_updates = self.certificates.activate_key(new_key, issuance_timing, signer)?;
if !cert_updates.is_empty() {
let certs_updated = CaEvtDet::ChildCertificatesUpdated {
resource_class_name: self.name.clone(),
updates: cert_updates,
};
events.push(certs_updated);
}
Ok(events)
}
} else {
Ok(vec![])
@@ -616,33 +610,6 @@ impl ResourceClass {
Ok(issued)
}
fn re_issue(
&self,
previous: &IssuedCert,
updated_resources: Option<ResourceSet>,
signing_key: &CertifiedKey,
csr_info_opt: Option<CsrInfo>,
issuance_timing: &IssuanceTimingConfig,
signer: &KrillSigner,
) -> KrillResult<IssuedCert> {
let (_uri, limit, resource_set, cert) = previous.clone().unpack();
let csr = csr_info_opt.unwrap_or_else(|| CsrInfo::from(&cert));
let resource_set = updated_resources.unwrap_or(resource_set);
let replaced = ReplacedObject::new(Revocation::from(&cert), HexEncodedHash::from(&cert));
let re_issued = SignSupport::make_issued_cert(
csr,
&resource_set,
limit,
Some(replaced),
signing_key,
issuance_timing.timing_child_certificate_valid_weeks,
signer,
)?;
Ok(re_issued)
}
/// Stores an [IssuedCert](krill_commons.api.ca.IssuedCert)
pub fn certificate_issued(&mut self, issued: IssuedCert) {
self.certificates.certificate_issued(issued);
@@ -694,7 +661,7 @@ impl ResourceClass {
signer: &KrillSigner,
) -> KrillResult<RoaUpdates> {
let key = self.get_new_key()?;
self.roas.activate_key(key, issuance_timing, signer)
self.roas.renew(true, key, issuance_timing, signer)
}
/// Updates the ROAs in accordance with the current authorizations
@@ -722,7 +689,8 @@ impl ResourceClass {
signer: &KrillSigner,
) -> KrillResult<AspaObjectsUpdates> {
let key = self.get_current_key()?;
self.aspas.renew(key, issuance_timing, signer)
let renew_threshold = Some(Time::now() + Duration::weeks(issuance_timing.timing_aspa_reissue_weeks_before));
self.aspas.renew(key, renew_threshold, issuance_timing, signer)
}
/// Updates the ASPA objects in accordance with the supplied definitions
+3 -52
View File
@@ -650,7 +650,9 @@ impl Roas {
}
}
/// Re-new ROAs before they would expire
/// Re-new ROAs before they would expire, or when forced e.g. in case
/// ROAs need to be reissued because of a keyroll, or because of a change
/// in encoding (like forcing shorter subject names, see issue #700)
pub fn renew(
&self,
force: bool,
@@ -700,57 +702,6 @@ impl Roas {
Ok(updates)
}
/// Re-generate all ROAs when a new key is being activated
pub fn activate_key(
&self,
certified_key: &CertifiedKey,
issuance_timing: &IssuanceTimingConfig,
signer: &KrillSigner,
) -> KrillResult<RoaUpdates> {
let mut updates = RoaUpdates::default();
for (auth, roa) in self.simple.iter() {
let name = ObjectName::from(auth);
let new_roa = Self::make_roa(
&[*auth],
&name,
certified_key,
issuance_timing.timing_roa_valid_weeks,
signer,
)?;
let new_roa_info = RoaInfo::updated_roa(roa, new_roa);
updates.update(*auth, new_roa_info);
}
for (roa_key, aggregate) in self.aggregate.iter() {
let roa = aggregate.roa_info();
let authorizations = aggregate.authorizations().clone();
let name = ObjectName::from(roa_key);
let new_roa = Self::make_roa(
authorizations.as_slice(),
&name,
certified_key,
issuance_timing.timing_roa_valid_weeks,
signer,
)?;
let new_roa_info = RoaInfo::updated_roa(roa, new_roa);
let aggregate = AggregateRoaInfo::new(authorizations, new_roa_info);
updates.update_aggregate(*roa_key, aggregate);
}
Ok(updates)
}
pub fn iter(&self) -> impl Iterator<Item = (&RouteAuthorization, &RoaInfo)> {
self.simple.iter()
}
pub fn authorizations(&self) -> impl Iterator<Item = &RouteAuthorization> {
self.simple.keys()
}
pub fn make_roa(
authorizations: &[RouteAuthorization],
name: &ObjectName,