mirror of
https://github.com/NLnetLabs/krill.git
synced 2026-09-13 21:17:41 +02:00
Merge release 0.9.3-rc3
This commit is contained in:
Generated
+3
-3
@@ -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
@@ -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"] }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user