Manually finish key-roll by activating the new key. Tested with apnic. Fixes #23

This commit is contained in:
Tim Bruijnzeels
2019-08-12 15:25:58 +02:00
parent 47e0240734
commit c1875b9de8
23 changed files with 974 additions and 371 deletions
+7 -1
View File
@@ -119,7 +119,13 @@ impl KrillClient {
Ok(ApiResponse::CertAuths(cas))
}
CaCommand::KeyRollInit(handle) => {
let uri = format!("api/v1/cas/{}/keys/init_roll", handle);
let uri = format!("api/v1/cas/{}/keys/roll_init", handle);
let uri = self.resolve_uri(&uri);
self.post_empty(&uri)?;
Ok(ApiResponse::Empty)
}
CaCommand::KeyRollActivate(handle) => {
let uri = format!("api/v1/cas/{}/keys/roll_activate", handle);
let uri = self.resolve_uri(&uri);
self.post_empty(&uri)?;
Ok(ApiResponse::Empty)
+9 -2
View File
@@ -1,9 +1,10 @@
use clap::{App, Arg, SubCommand};
use rpki::uri;
use std::io;
use std::path::PathBuf;
use std::str::FromStr;
use clap::{App, Arg, SubCommand};
use rpki::uri;
use krill_commons::api::admin::{
AddChildRequest, AddParentRequest, CertAuthInit, CertAuthPubMode, ChildAuthRequest, Handle,
ParentCaContact, Token, UpdateChildRequest,
@@ -241,6 +242,9 @@ impl Options {
.subcommand(SubCommand::with_name("init")
.about("Initialise a key roll for all active keys")
)
.subcommand(SubCommand::with_name("activate")
.about("Activate all new keys now (RFC say to do this >24H after init)")
)
)
.subcommand(SubCommand::with_name("add")
@@ -496,6 +500,8 @@ impl Options {
let handle = Handle::from(m.value_of("handle").unwrap());
if let Some(_m) = m.subcommand_matches("init") {
command = Command::CertAuth(CaCommand::KeyRollInit(handle));
} else if let Some(_m) = m.subcommand_matches("activate") {
command = Command::CertAuth(CaCommand::KeyRollActivate(handle));
}
}
@@ -622,6 +628,7 @@ pub enum CaCommand {
ChildRequest(Handle),
Init(CertAuthInit),
KeyRollInit(Handle),
KeyRollActivate(Handle),
List,
Show(Handle),
}
+76 -28
View File
@@ -3,7 +3,7 @@
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ops::Deref;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::FromStr;
use std::{fmt, ops};
@@ -12,19 +12,22 @@ use bytes::Bytes;
use chrono::Duration;
use rpki::cert::Cert;
use rpki::crypto::{KeyIdentifier, PublicKey};
use rpki::crypto::KeyIdentifier;
use rpki::resources::{AsBlocks, AsResources, IpBlocks, IpBlocksForFamily, IpResources};
use rpki::uri;
use rpki::x509::{Serial, Time};
use crate::api::admin::{Handle, ParentCaContact, Token};
use crate::api::publication;
use crate::api::{Base64, EncodedHash, IssuanceRequest, RequestResourceLimit};
use crate::api::{
Base64, EncodedHash, IssuanceRequest, RequestResourceLimit, RevocationRequest,
RevocationResponse,
};
use crate::remote::id::IdCert;
use crate::rpki::crl::{Crl, CrlEntry};
use crate::rpki::manifest::{FileAndHash, Manifest};
use crate::util::ext_serde;
use crate::util::softsigner::SignerKeyId;
use crate::util::softsigner::KeyId;
//------------ ChildCaInfo ---------------------------------------------------
@@ -125,6 +128,11 @@ impl ChildCaDetails {
// been issued to it. So, it's safe to unwrap here.
self.resources.get_mut(class_name).unwrap().add_cert(cert)
}
pub fn revoke_key(&mut self, revocation: RevocationResponse) {
let (class_name, key_id) = revocation.unpack();
self.resources.get_mut(&class_name).unwrap().revoke(&key_id)
}
}
/// This type defines a reference to PublicKey for easy storage and lookup.
@@ -200,8 +208,8 @@ impl ChildResources {
self.certs.values()
}
pub fn cert(&self, pub_key: &PublicKey) -> Option<&IssuedCert> {
let key_ref = KeyRef::from(&pub_key.key_identifier());
pub fn cert(&self, key_id: &KeyIdentifier) -> Option<&IssuedCert> {
let key_ref = KeyRef::from(key_id);
self.certs.get(&key_ref)
}
@@ -212,6 +220,11 @@ impl ChildResources {
self.resources = ResourceSet::try_from(cert.cert()).unwrap();
self.certs.insert(key_ref, cert);
}
pub fn revoke(&mut self, key_id: &KeyIdentifier) {
let key_ref = KeyRef::from(key_id);
self.certs.remove(&key_ref);
}
}
//------------ IssuedCert ----------------------------------------------------
@@ -465,22 +478,22 @@ impl Eq for RepoInfo {}
/// when a certificate is received.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct PendingKey {
key_id: SignerKeyId,
key_id: KeyId,
request: Option<IssuanceRequest>,
}
impl PendingKey {
pub fn new(key_id: SignerKeyId) -> Self {
pub fn new(key_id: KeyId) -> Self {
PendingKey {
key_id,
request: None,
}
}
pub fn unwrap(self) -> (SignerKeyId, Option<IssuanceRequest>) {
pub fn unwrap(self) -> (KeyId, Option<IssuanceRequest>) {
(self.key_id, self.request)
}
pub fn key_id(&self) -> &SignerKeyId {
pub fn key_id(&self) -> &KeyId {
&self.key_id
}
pub fn request(&self) -> Option<&IssuanceRequest> {
@@ -494,20 +507,55 @@ impl PendingKey {
}
}
//------------ OldKey --------------------------------------------------------
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)]
pub struct OldKey {
key: CertifiedKey,
revoke_req: RevocationRequest,
}
impl OldKey {
pub fn new(key: CertifiedKey, revoke_req: RevocationRequest) -> Self {
OldKey { key, revoke_req }
}
pub fn key(&self) -> &CertifiedKey {
&self.key
}
pub fn revoke_req(&self) -> &RevocationRequest {
&self.revoke_req
}
}
impl Deref for OldKey {
type Target = CertifiedKey;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl DerefMut for OldKey {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.key
}
}
//------------ CertifiedKey --------------------------------------------------
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
/// Describes a Key that is certified. I.e. it received an incoming certificate
/// and has at least a MFT and CRL.
pub struct CertifiedKey {
key_id: SignerKeyId,
key_id: KeyId,
incoming_cert: RcvdCert,
current_set: CurrentObjectSet,
request: Option<IssuanceRequest>,
}
impl CertifiedKey {
pub fn new(key_id: SignerKeyId, incoming_cert: RcvdCert) -> Self {
pub fn new(key_id: KeyId, incoming_cert: RcvdCert) -> Self {
let current_set = CurrentObjectSet::default();
CertifiedKey {
@@ -518,7 +566,7 @@ impl CertifiedKey {
}
}
pub fn key_id(&self) -> &SignerKeyId {
pub fn key_id(&self) -> &KeyId {
&self.key_id
}
pub fn incoming_cert(&self) -> &RcvdCert {
@@ -760,26 +808,30 @@ impl ops::Add for CurrentObjects {
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Revocation {
serial: Serial,
revocation_date: Time,
expires: Time,
}
impl From<&CurrentObject> for Revocation {
fn from(co: &CurrentObject) -> Self {
Revocation {
serial: co.serial,
revocation_date: Time::now(),
serial: co.serial(),
expires: co.expires(),
}
}
}
impl From<&Cert> for Revocation {
fn from(cer: &Cert) -> Self {
Revocation {
serial: cer.serial_number(),
expires: cer.validity().not_after(),
}
}
}
impl From<&Manifest> for Revocation {
fn from(m: &Manifest) -> Self {
let serial = m.cert().serial_number();
let revocation_date = Time::now();
Revocation {
serial,
revocation_date,
}
Self::from(m.cert())
}
}
@@ -792,16 +844,13 @@ impl Revocations {
pub fn to_crl_entries(&self) -> Vec<CrlEntry> {
self.0
.iter()
.map(|r| CrlEntry::new(r.serial, r.revocation_date))
.map(|r| CrlEntry::new(r.serial, r.expires))
.collect()
}
/// Purges all expired revocations, and returns them.
pub fn purge(&mut self) -> Vec<Revocation> {
let (relevant, expired) = self
.0
.iter()
.partition(|r| r.revocation_date.validate_not_after(Time::now()).is_ok());
let (relevant, expired) = self.0.iter().partition(|r| r.expires > Time::now());
self.0 = relevant;
expired
}
@@ -1444,7 +1493,6 @@ pub enum ResourceClassKeysInfo {
type NewKey = CertifiedKey;
type CurrentKey = CertifiedKey;
type OldKey = CertifiedKey;
impl fmt::Display for ResourceClassKeysInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+45
View File
@@ -370,3 +370,48 @@ impl RevocationRequest {
&self.key
}
}
//------------ RevocationResponse --------------------------------------------
/// This type represents a Certificate Revocation Response as
/// defined in section 3.5.2 of RFC6492.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RevocationResponse {
class_name: String,
key: KeyIdentifier,
}
impl RevocationResponse {
pub fn new(class_name: String, key: KeyIdentifier) -> Self {
RevocationResponse { class_name, key }
}
pub fn unpack(self) -> (String, KeyIdentifier) {
(self.class_name, self.key)
}
pub fn class_name(&self) -> &str {
&self.class_name
}
pub fn key(&self) -> &KeyIdentifier {
&self.key
}
}
impl From<&RevocationRequest> for RevocationResponse {
fn from(req: &RevocationRequest) -> Self {
RevocationResponse {
class_name: req.class_name.clone(),
key: req.key,
}
}
}
impl From<RevocationRequest> for RevocationResponse {
fn from(req: RevocationRequest) -> Self {
RevocationResponse {
class_name: req.class_name,
key: req.key,
}
}
}
+29 -1
View File
@@ -1,7 +1,10 @@
//! Support for requests sent to the Json API
use std::ops;
use rpki::uri;
use crate::api::{Base64, EncodedHash};
use crate::util::file::CurrentFile;
use rpki::uri;
//------------ PublishRequest ------------------------------------------------
@@ -33,6 +36,10 @@ impl PublishDelta {
}
}
pub fn empty() -> Self {
Self::default()
}
pub fn publishes(&self) -> &Vec<Publish> {
&self.publishes
}
@@ -56,6 +63,27 @@ impl PublishDelta {
}
}
impl Default for PublishDelta {
fn default() -> Self {
PublishDelta {
publishes: vec![],
updates: vec![],
withdraws: vec![],
}
}
}
impl ops::Add for PublishDelta {
type Output = PublishDelta;
fn add(mut self, mut other: Self) -> Self::Output {
self.publishes.append(&mut other.publishes);
self.updates.append(&mut other.updates);
self.withdraws.append(&mut other.withdraws);
self
}
}
//------------ PublishDeltaBuilder -------------------------------------------
#[derive(Default)]
+5 -10
View File
@@ -1,7 +1,7 @@
use rpki::uri;
use crate::api::admin::Handle;
use crate::util::softsigner::SignerKeyId;
use crate::util::softsigner::KeyId;
use crate::remote::id::IdCert;
@@ -55,17 +55,12 @@ impl ClientInfo {
pub struct CmsClientInfo {
handle: Handle,
server_cert: IdCert,
key_id: SignerKeyId,
key_id: KeyId,
publication_uri: uri::Https,
}
impl CmsClientInfo {
pub fn new(
handle: Handle,
cert: IdCert,
key_id: SignerKeyId,
publication_uri: uri::Https,
) -> Self {
pub fn new(handle: Handle, cert: IdCert, key_id: KeyId, publication_uri: uri::Https) -> Self {
CmsClientInfo {
handle,
server_cert: cert,
@@ -86,10 +81,10 @@ impl CmsClientInfo {
pub fn set_server_cert(&mut self, cert: IdCert) {
self.server_cert = cert;
}
pub fn key_id(&self) -> &SignerKeyId {
pub fn key_id(&self) -> &KeyId {
&self.key_id
}
pub fn set_key_id(&mut self, key_id: SignerKeyId) {
pub fn set_key_id(&mut self, key_id: KeyId) {
self.key_id = key_id;
}
pub fn publication_uri(&self) -> &uri::Https {
+4 -4
View File
@@ -11,7 +11,7 @@ use rpki::uri;
use rpki::x509::{Name, SignedData, Time, ValidationError, Validity};
use crate::remote::rfc8183::ServiceUri;
use crate::util::softsigner::SignerKeyId;
use crate::util::softsigner::KeyId;
//------------ MyIdentity ----------------------------------------------------
@@ -23,11 +23,11 @@ pub struct MyIdentity {
id_cert: IdCert,
key_id: SignerKeyId,
key_id: KeyId,
}
impl MyIdentity {
pub fn new(name: &str, id_cert: IdCert, key_id: SignerKeyId) -> Self {
pub fn new(name: &str, id_cert: IdCert, key_id: KeyId) -> Self {
MyIdentity {
name: name.to_string(),
id_cert,
@@ -47,7 +47,7 @@ impl MyIdentity {
/// The identifier that the Signer needs to use the key for the identity
/// certificate.
pub fn key_id(&self) -> &SignerKeyId {
pub fn key_id(&self) -> &KeyId {
&self.key_id
}
}
+1 -1
View File
@@ -5,6 +5,7 @@ use std::sync::Arc;
use bcder::encode::Values;
use bcder::{Captured, Mode};
use rpki::crypto::{PublicKeyFormat, Signer};
use rpki::uri;
use rpki::x509::ValidationError;
@@ -25,7 +26,6 @@ use crate::remote::rfc8183::ServiceUri;
use crate::remote::sigmsg::SignedMessage;
use crate::util::httpclient;
use crate::util::softsigner::{OpenSslSigner, SignerError};
use rpki::crypto::{PublicKeyFormat, Signer};
#[derive(Clone)]
pub struct ProxyServer {
+53 -22
View File
@@ -1,6 +1,6 @@
use std::convert::TryFrom;
use std::io;
use std::str::FromStr;
use std::{fmt, io};
use bytes::Bytes;
use chrono::{DateTime, SecondsFormat, Utc};
@@ -16,7 +16,7 @@ use crate::api::admin::Handle;
use crate::api::ca::{IssuedCert, ResSetErr, ResourceSet};
use crate::api::{
EntitlementClass, Entitlements, IssuanceRequest, IssuanceResponse, RequestResourceLimit,
RevocationRequest, SigningCert,
RevocationRequest, RevocationResponse, SigningCert,
};
use crate::remote::sigmsg::SignedMessage;
use crate::rpki::resources::{AsBlocks, IpBlocks};
@@ -141,7 +141,7 @@ impl Message {
pub fn revoke_response(
sender: String,
recipient: String,
revocation: RevocationRequest,
revocation: RevocationResponse,
) -> Self {
let content = Content::Res(Res::Revoke(revocation));
Message {
@@ -151,12 +151,12 @@ impl Message {
}
}
pub fn error_response(
pub fn not_performed_response(
sender: String,
recipient: String,
err: NotPerformedResponse,
) -> Result<Self, Error> {
let content = Content::Res(Res::Error(err));
let content = Content::Res(Res::NotPerformed(err));
Ok(Message {
sender,
recipient,
@@ -295,14 +295,15 @@ impl Qry {
where
R: io::Read,
{
r.take_named_element("key", |mut a, r| {
r.take_named_element("key", |mut a, _r| {
let class_name = a.take_req("class_name")?;
let ski = a.take_req("ski")?;
let ski_bytes = base64::decode_config(&ski, base64::URL_SAFE_NO_PAD)
.map_err(|_| Error::InvalidSki)?;
a.exhausted()?;
let ski_bytes = r.take_bytes_url_safe_pad()?;
let ski = KeyIdentifier::try_from(ski_bytes.as_ref()).map_err(|_| Error::InvalidSki)?;
Ok(RevocationRequest::new(class_name.to_string(), ski))
})
}
@@ -386,9 +387,10 @@ impl Qry {
rev: &RevocationRequest,
w: &mut XmlWriter<W>,
) -> Result<(), io::Error> {
let att = [("class_name", rev.class_name())];
let bytes = rev.key().as_slice();
w.put_element("key", Some(&att), |w| w.put_base64_url_safe(bytes))
let encoded = base64::encode_config(bytes, base64::URL_SAFE_NO_PAD);
let att = [("class_name", rev.class_name()), ("ski", encoded.as_str())];
w.put_element("key", Some(&att), |w| w.empty())
}
}
@@ -400,8 +402,8 @@ impl Qry {
pub enum Res {
List(Entitlements),
Issue(IssuanceResponse),
Revoke(RevocationRequest),
Error(NotPerformedResponse),
Revoke(RevocationResponse),
NotPerformed(NotPerformedResponse),
}
/// # Data Access
@@ -412,7 +414,7 @@ impl Res {
Res::List(_) => TYPE_LIST_RES,
Res::Issue(_) => TYPE_ISSUE_RES,
Res::Revoke(_) => TYPE_REVOKE_RES,
Res::Error(_) => TYPE_ERROR_RES,
Res::NotPerformed(_) => TYPE_ERROR_RES,
}
}
}
@@ -435,11 +437,11 @@ impl Res {
}
TYPE_REVOKE_RES => {
let request = Qry::decode_revoke(r)?;
Ok(Res::Revoke(request))
Ok(Res::Revoke(request.into()))
}
TYPE_ERROR_RES => {
let err = Self::decode_error_response(r)?;
Ok(Res::Error(err))
Ok(Res::NotPerformed(err))
}
_ => Err(Error::UnknownMessageType),
}
@@ -595,9 +597,18 @@ impl Res {
{
let code = r.take_named_element("status", |_a, r| r.take_chars())?;
let _desc = r.take_named_element("description", |_a, r| r.take_chars())?;
let desc = r.take_named_element("description", |_a, r| r.take_chars())?;
NotPerformedResponse::from_code(&code)
match NotPerformedResponse::from_code(&code) {
Ok(res) => Ok(res),
Err(e) => {
error!(
"Strange error response with code: {}, description: {}",
code, desc
);
Err(e)
}
}
}
}
@@ -608,8 +619,8 @@ impl Res {
match self {
Res::List(ents) => Self::encode_entitlements(ents, w),
Res::Issue(response) => Self::encode_issuance_response(response, w),
Res::Revoke(request) => Qry::encode_revoke(request, w),
Res::Error(err) => Self::encode_error_response(err, w),
Res::Revoke(response) => Self::encode_revoke_reponse(response, w),
Res::NotPerformed(err) => Self::encode_error_response(err, w),
}
}
@@ -732,6 +743,16 @@ impl Res {
w.put_text(&error.description)
})
}
fn encode_revoke_reponse<W: io::Write>(
res: &RevocationResponse,
w: &mut XmlWriter<W>,
) -> Result<(), io::Error> {
let bytes = res.key().as_slice();
let encoded = base64::encode_config(bytes, base64::URL_SAFE_NO_PAD);
let att = [("class_name", res.class_name()), ("ski", encoded.as_str())];
w.put_element("key", Some(&att), |w| w.empty())
}
}
//------------ NotPerformedResponse ------------------------------------------
@@ -838,6 +859,16 @@ impl NotPerformedResponse {
}
}
impl fmt::Display for NotPerformedResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"status: {}, description: {}",
self.status, &self.description
)
}
}
//------------ Error ---------------------------------------------------------
#[derive(Debug, Display)]
@@ -1034,7 +1065,7 @@ mod tests {
let class = "all".to_string();
let ski = cert.subject_public_key_info().key_identifier();
let revocation = RevocationRequest::new(class, ski);
let revocation = RevocationResponse::new(class, ski);
let rev = Message::revoke_response(sender, rcpt, revocation);
let decoded_rev = Message::decode(rev.encode_vec().as_slice()).unwrap();
@@ -1050,7 +1081,7 @@ mod tests {
let rcpt = "parent".to_string();
let err = NotPerformedResponse::_1101();
let err = Message::error_response(sender, rcpt, err).unwrap();
let err = Message::not_performed_response(sender, rcpt, err).unwrap();
let decoded = Message::decode(err.encode_vec().as_slice()).unwrap();
assert_eq!(err, decoded);
+21 -19
View File
@@ -1,39 +1,41 @@
//! Support for signing things using software keys (through openssl) and
//! storing them unencrypted on disk.
use std::{fs, io};
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use bytes::Bytes;
use openssl::error::ErrorStack;
use openssl::hash::MessageDigest;
use openssl::pkey::{PKey, PKeyRef, Private};
use openssl::rsa::Rsa;
use serde::{de, ser};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use rpki::crypto::signer::KeyError;
use rpki::crypto::{
PublicKey, PublicKeyFormat, Signature, SignatureAlgorithm, Signer, SigningError,
};
use serde::{de, ser};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::{fs, io};
//------------ SignerKeyId ---------------------------------------------------
//------------ KeyId ---------------------------------------------------------
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SignerKeyId(String);
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct KeyId(String);
impl SignerKeyId {
impl KeyId {
pub fn new(s: &str) -> Self {
SignerKeyId(s.to_string())
KeyId(s.to_string())
}
}
impl AsRef<str> for SignerKeyId {
impl AsRef<str> for KeyId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Serialize for SignerKeyId {
impl Serialize for KeyId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@@ -42,13 +44,13 @@ impl Serialize for SignerKeyId {
}
}
impl<'de> Deserialize<'de> for SignerKeyId {
impl<'de> Deserialize<'de> for KeyId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(SignerKeyId::new(&s))
Ok(KeyId::new(&s))
}
}
@@ -95,7 +97,7 @@ impl OpenSslSigner {
Ok(signature)
}
fn load_key(&self, id: &SignerKeyId) -> Result<OpenSslKeyPair, SignerError> {
fn load_key(&self, id: &KeyId) -> Result<OpenSslKeyPair, SignerError> {
let path = self.key_path(id);
if path.exists() {
let f = File::open(path)?;
@@ -106,7 +108,7 @@ impl OpenSslSigner {
}
}
fn key_path(&self, key_id: &SignerKeyId) -> PathBuf {
fn key_path(&self, key_id: &KeyId) -> PathBuf {
let mut path = self.keys_dir.clone();
path.push(key_id.as_ref());
path
@@ -114,7 +116,7 @@ impl OpenSslSigner {
}
impl Signer for OpenSslSigner {
type KeyId = SignerKeyId;
type KeyId = KeyId;
type Error = SignerError;
fn create_key(&mut self, _algorithm: PublicKeyFormat) -> Result<Self::KeyId, Self::Error> {
@@ -122,7 +124,7 @@ impl Signer for OpenSslSigner {
let pk = &kp.subject_public_key_info()?;
let hex_hash = hex::encode(pk.key_identifier().as_ref());
let key_id = SignerKeyId(hex_hash);
let key_id = KeyId(hex_hash);
let path = self.key_path(&key_id);
let json = serde_json::to_string(&kp)?;
+4 -15
View File
@@ -1,12 +1,13 @@
//! Support for RPKI XML structures.
use std::{fs, io};
use std::fs::File;
use std::path::Path;
use base64;
use base64::DecodeError;
use bytes::Bytes;
use hex;
use hex::FromHexError;
use std::fs::File;
use std::path::Path;
use std::{fs, io};
use xmlrs::attribute::OwnedAttribute;
use xmlrs::reader::XmlEvent;
use xmlrs::{reader, writer};
@@ -220,11 +221,6 @@ impl<R: io::Read> XmlReader<R> {
self.take_bytes(base64::STANDARD_NO_PAD)
}
/// Takes base64 encoded bytes from the next 'characters' event.
pub fn take_bytes_url_safe_pad(&mut self) -> Result<Bytes, XmlReaderErr> {
self.take_bytes(base64::URL_SAFE_NO_PAD)
}
fn take_bytes(&mut self, config: base64::Config) -> Result<Bytes, XmlReaderErr> {
let chars = self.take_chars()?;
// strip whitespace and padding (we are liberal in what we accept here)
@@ -486,13 +482,6 @@ impl<W: io::Write> XmlWriter<W> {
self.put_text(b64.as_ref())
}
/// Converts bytes to base64 encoded Characters as the content, using the
/// URL safe character set and padding.
pub fn put_base64_url_safe(&mut self, bytes: &[u8]) -> Result<(), io::Error> {
let b64 = base64::encode_config(bytes, base64::URL_SAFE);
self.put_text(b64.as_ref())
}
/// Use this for convenience where empty content is required
pub fn empty(&mut self) -> Result<(), io::Error> {
Ok(())
+173 -38
View File
@@ -16,11 +16,11 @@ use krill_commons::api::admin::{
use krill_commons::api::ca::{
AddedObject, CaParentsInfo, CertAuthInfo, CertifiedKey, ChildCaDetails, CurrentObject,
IssuedCert, ObjectName, ObjectsDelta, ParentCaInfo, PublicationDelta, RcvdCert, RepoInfo,
ResourceSet, TrustAnchorInfo, TrustAnchorLocator, UpdatedObject,
ResourceSet, Revocation, TrustAnchorInfo, TrustAnchorLocator, UpdatedObject, WithdrawnObject,
};
use krill_commons::api::{
self, EncodedHash, EntitlementClass, Entitlements, IssuanceRequest, IssuanceResponse,
SigningCert, DFLT_CLASS,
RevocationRequest, RevocationResponse, SigningCert, DFLT_CLASS,
};
use krill_commons::eventsourcing::{Aggregate, StoredEvent};
use krill_commons::remote::builder::{IdCertBuilder, SignedMessageBuilder};
@@ -28,7 +28,7 @@ use krill_commons::remote::id::IdCert;
use krill_commons::remote::rfc6492;
use krill_commons::remote::rfc8183::ChildRequest;
use krill_commons::remote::sigmsg::SignedMessage;
use krill_commons::util::softsigner::SignerKeyId;
use krill_commons::util::softsigner::KeyId;
use crate::ca::{
self, ChildHandle, Cmd, CmdDet, Error, Evt, EvtDet, Ini, ParentHandle, ResourceClass,
@@ -39,7 +39,7 @@ use crate::ca::{
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Rfc8183Id {
key: SignerKeyId,
key: KeyId,
cert: IdCert,
}
@@ -210,18 +210,21 @@ impl<S: Signer> Aggregate for CertAuth<S> {
fn apply(&mut self, event: Evt) {
self.version += 1;
match event.into_details() {
//-----------------------------------------------------------------------
// Being a parent
//-----------------------------------------------------------------------
EvtDet::ChildAdded(child, details) => {
self.children.insert(child, details);
}
EvtDet::CertificateIssued(child, response) => {
EvtDet::ChildCertificateIssued(child, response) => {
let (class_name, _, _, issued) = response.unwrap();
let child = self.children.get_mut(&child).unwrap();
child.add_cert(&class_name, issued);
}
EvtDet::ChildKeyRevoked(child, response) => {
let child = self.children.get_mut(&child).unwrap();
child.revoke_key(response);
}
EvtDet::ChildUpdatedToken(child, token) => {
let child = self.children.get_mut(&child).unwrap();
child.set_token(token);
@@ -271,19 +274,31 @@ impl<S: Signer> Aggregate for CertAuth<S> {
//-----------------------------------------------------------------------
// Key Roll
//-----------------------------------------------------------------------
EvtDet::KeyrollPendingKeyAdded(parent, class_name, key_id) => {
EvtDet::KeyRollPendingKeyAdded(parent, class_name, key_id) => {
let parent = self.parent_mut(&parent).unwrap();
let rc = parent.class_mut(&class_name).unwrap();
rc.pending_key_added(key_id);
}
EvtDet::KeyRollActivated(parent, class_name, revoke_req) => {
let parent = self.parent_mut(&parent).unwrap();
let rc = parent.class_mut(&class_name).unwrap();
rc.new_key_activated(revoke_req);
}
EvtDet::KeyRollFinished(parent, class_name, _delta) => {
let parent = self.parent_mut(&parent).unwrap();
let rc = parent.class_mut(&class_name).unwrap();
rc.old_key_removed();
}
//-----------------------------------------------------------------------
// General functions
//-----------------------------------------------------------------------
EvtDet::Published(parent, class_name, key_id, delta) => {
EvtDet::Published(parent, class_name, delta_map) => {
let parent = self.parent_mut(&parent).unwrap();
let rc = parent.class_mut(&class_name).unwrap();
rc.apply_delta(delta, key_id);
for (key_id, delta) in delta_map.into_iter() {
rc.apply_delta(delta, key_id);
}
}
EvtDet::TaPublished(delta) => {
let ta_key = self.ta_key_mut().unwrap();
@@ -302,6 +317,9 @@ impl<S: Signer> Aggregate for CertAuth<S> {
CmdDet::CertifyChild(child, request, token, signer) => {
self.certify_child(child, request, token, signer)
}
CmdDet::RevokeKeyForChild(child, request, signer) => {
self.revoke_child_key(child, request, signer)
}
// being a child
CmdDet::AddParent(parent, info) => self.add_parent(parent, info),
@@ -314,8 +332,8 @@ impl<S: Signer> Aggregate for CertAuth<S> {
// Key rolls
CmdDet::KeyRollInitiate(duration, signer) => self.keyroll_initiate(duration, signer),
CmdDet::KeyRollActivate(duration) => self.keyroll_activate(duration),
CmdDet::KeyRollFinish(parent, class_name) => self.keyroll_finish(parent, class_name),
CmdDet::KeyRollActivate(duration, signer) => self.keyroll_activate(duration, signer),
CmdDet::KeyRollFinish(parent, response) => self.keyroll_finish(parent, response),
// Republish
CmdDet::Republish(signer) => self.republish(signer),
@@ -358,7 +376,7 @@ impl<S: Signer> CertAuth<S> {
pub fn id_cert(&self) -> &IdCert {
&self.id.cert
}
pub fn id_key(&self) -> &SignerKeyId {
pub fn id_key(&self) -> &KeyId {
&self.id.key
}
pub fn handle(&self) -> &Handle {
@@ -563,7 +581,13 @@ impl<S: Signer> CertAuth<S> {
.map_err(|_| Error::invalid_csr(&child, "invalid signature"))?;
// TODO: Check for key-re-use, ultimately return 1204 (RFC6492 3.4.1)
let current_cert = child_resources.cert(csr.public_key());
let current_cert = child_resources.cert(&csr.public_key().key_identifier());
// Check if we need to revoke
let mut revocations = vec![];
if let Some(issued) = current_cert {
revocations.push(Revocation::from(issued.cert()))
}
// create new cert
let issued_cert = {
@@ -636,7 +660,7 @@ impl<S: Signer> CertAuth<S> {
issued_cert.clone(),
);
let issued_event = EvtDet::certificate_issued(&self.handle, version, child, response);
let issued_event = EvtDet::child_certificate_issued(&self.handle, version, child, response);
let delta = {
let ca_repo = self.base_repo.ca_repository("");
@@ -647,7 +671,7 @@ impl<S: Signer> CertAuth<S> {
None => delta.add(AddedObject::new(cert_name, cert_object)),
Some(old) => {
let old_hash = EncodedHash::from_content(old.cert().to_captured().as_slice());
delta.update(UpdatedObject::new(cert_name, cert_object, old_hash))
delta.update(UpdatedObject::new(cert_name, cert_object, old_hash));
}
}
delta
@@ -656,7 +680,7 @@ impl<S: Signer> CertAuth<S> {
let publish_event = EvtDet::published_ta(
&self.handle,
version + 1,
SignSupport::publish(signer, issuing_key, &self.base_repo, "", delta)
SignSupport::publish(signer, issuing_key, &self.base_repo, "", delta, revocations)
.map_err(Error::signer)?,
);
@@ -754,6 +778,60 @@ impl<S: Signer> CertAuth<S> {
Ok(res)
}
/// Revokes a key for a child. So, add all certs for the key to the CRL, and withdraw
/// the .cer file for it.
fn revoke_child_key(
&self,
child: ChildHandle,
request: RevocationRequest,
signer: Arc<RwLock<S>>,
) -> ca::Result<Vec<Evt>> {
// verify child and resources
let class_name = request.class_name();
let child_resources = self
.get_child(&child)?
.resources_for_class(class_name)
.ok_or_else(|| Error::MissingResourceClass)?;
let ca_key = match &self.parents {
CaParents::SelfSigned(key, _) => key,
CaParents::Parents(_map) => unimplemented!("Issue #25"),
};
// TODO For #25 find correct namespace for matching RC
let name_space = "";
if let Some(last_cert) = child_resources.cert(request.key()) {
let response = request.into();
let name = ObjectName::from(last_cert.cert());
let current_object = CurrentObject::from(last_cert.cert());
let withdrawn = WithdrawnObject::for_current(name, &current_object);
let revocations = vec![Revocation::from(last_cert.cert())];
let mut objects_delta = ObjectsDelta::new(self.base_repo.ca_repository(name_space));
objects_delta.withdraw(withdrawn);
let pub_delta = SignSupport::publish(
signer,
ca_key,
&self.base_repo,
name_space,
objects_delta,
revocations,
)
.map_err(Error::signer)?;
let revoked = EvtDet::child_revoke_key(&self.handle, self.version, child, response);
let published = EvtDet::published_ta(&self.handle, self.version + 1, pub_delta);
Ok(vec![revoked, published])
} else {
Err(Error::NoIssuedCert)
}
}
/// Returns `true` if the child is known, `false` otherwise. No errors.
fn has_child(&self, child_handle: &Handle) -> bool {
self.children.contains_key(child_handle)
@@ -775,7 +853,7 @@ impl<S: Signer> CertAuth<S> {
}
}
fn parent(&self, parent: &Handle) -> Result<&ParentCa> {
pub fn parent(&self, parent: &Handle) -> Result<&ParentCa> {
self.parents.get(parent)
}
@@ -833,6 +911,19 @@ impl<S: Signer> CertAuth<S> {
Ok(res)
}
/// Returns the open revocation requests for the given parent.
pub fn revoke_requests(&self, parent: &ParentHandle) -> Vec<&RevocationRequest> {
let mut res = vec![];
if let Ok(parent) = self.parent(parent) {
for (_class_name, rc) in parent.resources.iter() {
if let Some(req) = rc.revoke_request() {
res.push(req)
}
}
}
res
}
/// This processes entitlements from a parent, and updates the known
/// entitlement(s) and/or requests certificate(s) as needed. In case
/// there are no changes in entitlements and certificates, this method
@@ -938,7 +1029,7 @@ impl<S: Signer> CertAuth<S> {
rcvd_cert: RcvdCert,
signer: Arc<RwLock<S>>,
) -> ca::Result<Vec<Evt>> {
info!(
debug!(
"CA {}: Updating received cert for class: {}",
self.handle, class_name
);
@@ -977,19 +1068,17 @@ impl<S: Signer> CertAuth<S> {
for (parent_handle, parent) in map.iter() {
for (class_name, class) in parent.resources().iter() {
for details in class.keyroll_initiate(
parent_handle.clone(),
class_name.clone(),
&self.base_repo,
duration,
signer.deref_mut()
)?.into_iter() {
res.push(StoredEvent::new(
self.handle(),
version,
details
));
for details in class
.keyroll_initiate(
parent_handle.clone(),
class_name.clone(),
&self.base_repo,
duration,
signer.deref_mut(),
)?
.into_iter()
{
res.push(StoredEvent::new(self.handle(), version, details));
version += 1;
}
}
@@ -1000,16 +1089,62 @@ impl<S: Signer> CertAuth<S> {
}
}
fn keyroll_activate(&self, _duration: Duration) -> ca::Result<Vec<Evt>> {
unimplemented!()
fn keyroll_activate(&self, staging: Duration, signer: Arc<RwLock<S>>) -> ca::Result<Vec<Evt>> {
match &self.parents {
CaParents::SelfSigned(_, _) => Ok(vec![]),
CaParents::Parents(map) => {
let signer = signer.read().unwrap();
let mut version = self.version;
let mut res = vec![];
for (parent_handle, parent) in map.iter() {
for (class_name, class) in parent.resources().iter() {
for details in class
.keyroll_activate(
parent_handle.clone(),
class_name.clone(),
staging,
signer.deref(),
)?
.into_iter()
{
res.push(StoredEvent::new(self.handle(), version, details));
version += 1;
}
}
}
Ok(res)
}
}
}
fn keyroll_finish(
&self,
_parent: ParentHandle,
_class_name: ResourceClassName,
parent_h: ParentHandle,
response: RevocationResponse,
) -> ca::Result<Vec<Evt>> {
unimplemented!()
match &self.parents {
CaParents::SelfSigned(_, _) => Ok(vec![]),
CaParents::Parents(map) => {
let (class_name, _key_id) = response.unpack();
let parent = map
.get(&parent_h)
.ok_or_else(|| Error::UnknownParent(parent_h.clone()))?;
let rc = parent
.resources()
.get(&class_name)
.ok_or_else(|| Error::UnknownResourceClass(class_name.clone()))?;
let finish_details = rc.keyroll_finish(parent_h, class_name, &self.base_repo)?;
Ok(vec![StoredEvent::new(
self.handle(),
self.version,
finish_details,
)])
}
}
}
}
@@ -1024,7 +1159,7 @@ impl<S: Signer> CertAuth<S> {
) -> Result<PublicationDelta> {
let ca_repo = repo_info.ca_repository(name_space);
let objects_delta = ObjectsDelta::new(ca_repo);
SignSupport::publish(signer, key, repo_info, name_space, objects_delta)
SignSupport::publish(signer, key, repo_info, name_space, objects_delta, vec![])
.map_err(Error::signer)
}
@@ -1040,7 +1175,7 @@ impl<S: Signer> CertAuth<S> {
res.push(EvtDet::published_ta(&self.handle, self.version, delta))
}
}
CaParents::Parents(_map) => unimplemented!(),
CaParents::Parents(_map) => error!("Republishing CAs not implemented"),
}
Ok(res)
}
+45 -14
View File
@@ -4,7 +4,7 @@ use chrono::Duration;
use krill_commons::api::admin::{Handle, ParentCaContact, Token, UpdateChildRequest};
use krill_commons::api::ca::{RcvdCert, ResourceSet};
use krill_commons::api::{Entitlements, IssuanceRequest};
use krill_commons::api::{Entitlements, IssuanceRequest, RevocationRequest, RevocationResponse};
use krill_commons::eventsourcing;
use krill_commons::remote::id::IdCert;
@@ -29,6 +29,8 @@ pub enum CmdDet<S: Signer> {
UpdateChild(ChildHandle, UpdateChildRequest),
// Process an issuance request by an existing child.
CertifyChild(ChildHandle, IssuanceRequest, Token, Arc<RwLock<S>>),
// Process a revoke request by an existing child.
RevokeKeyForChild(ChildHandle, RevocationRequest, Arc<RwLock<S>>),
// ------------------------------------------------------------
// Being a child (only allowed if this CA is not self-signed)
@@ -59,11 +61,11 @@ pub enum CmdDet<S: Signer> {
//
// RFC6489 dictates that 24 hours MUST be observed. However, shorter time frames can
// be used for testing, and in case of emergency rolls.
KeyRollActivate(Duration),
KeyRollActivate(Duration, Arc<RwLock<S>>),
// Finish the keyroll after the parent confirmed that a key for a parent and resource
// class has been revoked. I.e. remove the old key, and withdraw the crl and mft for it.
KeyRollFinish(ParentHandle, ResourceClassName),
KeyRollFinish(ParentHandle, RevocationResponse),
// ------------------------------------------------------------
// Publishing
@@ -104,8 +106,8 @@ impl<S: Signer> CmdDet<S> {
/// Certify a child. Will return an error in case the child is
/// unknown, or in case resources are not held by the child.
pub fn certify_child(
handle: &ParentHandle,
child_handle: Handle,
handle: &Handle,
child_handle: ChildHandle,
request: IssuanceRequest,
token: Token,
signer: Arc<RwLock<S>>,
@@ -117,42 +119,71 @@ impl<S: Signer> CmdDet<S> {
)
}
pub fn add_parent(handle: &Handle, name: &str, info: ParentCaContact) -> Cmd<S> {
eventsourcing::SentCommand::new(handle, None, CmdDet::AddParent(Handle::from(name), info))
/// Revoke a key for a child.
pub fn revoke_key_for_child(
handle: &Handle,
child_handle: ChildHandle,
request: RevocationRequest,
signer: Arc<RwLock<S>>,
) -> Cmd<S> {
eventsourcing::SentCommand::new(
handle,
None,
CmdDet::RevokeKeyForChild(child_handle, request, signer),
)
}
pub fn add_parent(handle: &Handle, parent: ParentHandle, info: ParentCaContact) -> Cmd<S> {
eventsourcing::SentCommand::new(handle, None, CmdDet::AddParent(parent, info))
}
pub fn upd_entitlements(
handle: &Handle,
parent: &ParentHandle,
parent: ParentHandle,
entitlements: Entitlements,
signer: Arc<RwLock<S>>,
) -> Cmd<S> {
eventsourcing::SentCommand::new(
handle,
None,
CmdDet::UpdateEntitlements(parent.clone(), entitlements, signer),
CmdDet::UpdateEntitlements(parent, entitlements, signer),
)
}
pub fn upd_received_cert(
handle: &Handle,
parent: &ParentHandle,
class_name: &str,
parent: ParentHandle,
class_name: ResourceClassName,
cert: RcvdCert,
signer: Arc<RwLock<S>>,
) -> Cmd<S> {
eventsourcing::SentCommand::new(
handle,
None,
CmdDet::UpdateRcvdCert(parent.clone(), class_name.to_string(), cert, signer),
CmdDet::UpdateRcvdCert(parent, class_name, cert, signer),
)
}
//----- Key Rolls
pub fn init_roll(handle: &Handle, duration: Duration, signer: Arc<RwLock<S>>) -> Cmd<S> {
//-------------------------------------------------------------------------------
// Key Rolls
//-------------------------------------------------------------------------------
pub fn key_roll_init(handle: &Handle, duration: Duration, signer: Arc<RwLock<S>>) -> Cmd<S> {
eventsourcing::SentCommand::new(handle, None, CmdDet::KeyRollInitiate(duration, signer))
}
pub fn key_roll_activate(handle: &Handle, staging: Duration, signer: Arc<RwLock<S>>) -> Cmd<S> {
eventsourcing::SentCommand::new(handle, None, CmdDet::KeyRollActivate(staging, signer))
}
pub fn key_roll_finish(
handle: &Handle,
parent: ParentHandle,
res: RevocationResponse,
) -> Cmd<S> {
eventsourcing::SentCommand::new(handle, None, CmdDet::KeyRollFinish(parent, res))
}
pub fn publish(handle: &Handle, signer: Arc<RwLock<S>>) -> Cmd<S> {
eventsourcing::SentCommand::new(handle, None, CmdDet::Republish(signer))
}
+28 -10
View File
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, RwLock};
@@ -7,15 +8,17 @@ use rpki::crypto::PublicKeyFormat;
use rpki::uri;
use rpki::x509::{Serial, Time, Validity};
use krill_commons::api::{IssuanceRequest, IssuanceResponse};
use krill_commons::api::admin::{Handle, ParentCaContact, Token};
use krill_commons::api::ca::{
CertifiedKey, ChildCaDetails, ObjectsDelta, PublicationDelta, RcvdCert, RepoInfo, ResourceSet,
TrustAnchorLocator,
};
use krill_commons::api::{
IssuanceRequest, IssuanceResponse, RevocationRequest, RevocationResponse,
};
use krill_commons::eventsourcing::StoredEvent;
use krill_commons::remote::id::IdCert;
use krill_commons::util::softsigner::SignerKeyId;
use krill_commons::util::softsigner::KeyId;
use crate::ca::signing::Signer;
use crate::ca::{
@@ -130,7 +133,8 @@ pub type Evt = StoredEvent<EvtDet>;
pub enum EvtDet {
// Being a parent Events
ChildAdded(ChildHandle, ChildCaDetails),
CertificateIssued(ChildHandle, IssuanceResponse),
ChildCertificateIssued(ChildHandle, IssuanceResponse),
ChildKeyRevoked(ChildHandle, RevocationResponse),
ChildUpdatedToken(ChildHandle, Token),
ChildUpdatedIdCert(ChildHandle, IdCert),
ChildUpdatedResourceClass(ChildHandle, ResourceClassName, ResourceSet),
@@ -140,18 +144,19 @@ pub enum EvtDet {
ParentAdded(ParentHandle, ParentCaContact),
ResourceClassAdded(ParentHandle, ResourceClassName, ResourceClass),
ResourceClassRemoved(ParentHandle, ResourceClassName, ObjectsDelta),
CertificateRequested(ParentHandle, IssuanceRequest, SignerKeyId),
CertificateReceived(ParentHandle, ResourceClassName, SignerKeyId, RcvdCert),
CertificateRequested(ParentHandle, IssuanceRequest, KeyId),
CertificateReceived(ParentHandle, ResourceClassName, KeyId, RcvdCert),
// Key roll
KeyrollPendingKeyAdded(ParentHandle, ResourceClassName, SignerKeyId),
KeyRollPendingKeyAdded(ParentHandle, ResourceClassName, KeyId),
KeyRollActivated(ParentHandle, ResourceClassName, RevocationRequest),
KeyRollFinished(ParentHandle, ResourceClassName, ObjectsDelta),
// Publishing
Published(
ParentHandle,
ResourceClassName,
SignerKeyId,
PublicationDelta,
HashMap<KeyId, PublicationDelta>,
),
TaPublished(PublicationDelta),
}
@@ -238,13 +243,26 @@ impl EvtDet {
)
}
pub(super) fn certificate_issued(
pub(super) fn child_certificate_issued(
handle: &Handle,
version: u64,
child: ChildHandle,
response: IssuanceResponse,
) -> Evt {
StoredEvent::new(handle, version, EvtDet::CertificateIssued(child, response))
StoredEvent::new(
handle,
version,
EvtDet::ChildCertificateIssued(child, response),
)
}
pub(super) fn child_revoke_key(
handle: &Handle,
version: u64,
child: ChildHandle,
response: RevocationResponse,
) -> Evt {
StoredEvent::new(handle, version, EvtDet::ChildKeyRevoked(child, response))
}
pub(super) fn published_ta(handle: &Handle, version: u64, delta: PublicationDelta) -> Evt {
+129 -33
View File
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::ops::Deref;
use std::sync::{Arc, RwLock};
@@ -9,11 +10,13 @@ use rpki::uri;
use rpki::x509::Time;
use krill_commons::api::ca::{
CertifiedKey, CurrentObjects, KeyRef, ObjectsDelta, PendingKey, PublicationDelta, RcvdCert,
RepoInfo, ResourceClassInfo, ResourceClassKeysInfo,
CertifiedKey, CurrentObjects, KeyRef, ObjectsDelta, OldKey, PendingKey, PublicationDelta,
RcvdCert, RepoInfo, ResourceClassInfo, ResourceClassKeysInfo,
};
use krill_commons::api::{EntitlementClass, IssuanceRequest, RequestResourceLimit};
use krill_commons::util::softsigner::SignerKeyId;
use krill_commons::api::{
EntitlementClass, IssuanceRequest, RequestResourceLimit, RevocationRequest,
};
use krill_commons::util::softsigner::KeyId;
use crate::ca::{
self, Error, EvtDet, ParentHandle, ResourceClassName, Result, SignSupport, Signer,
@@ -82,7 +85,7 @@ pub struct ResourceClass {
impl ResourceClass {
/// Creates a new ResourceClass with a single pending key only.
pub fn create(name_space: String, pending_key: SignerKeyId) -> Self {
pub fn create(name_space: String, pending_key: KeyId) -> Self {
ResourceClass {
name_space,
last_key_change: Time::now(),
@@ -95,7 +98,7 @@ impl ResourceClass {
}
/// Adds a request to an existing key for future reference.
pub fn add_request(&mut self, key_id: SignerKeyId, req: IssuanceRequest) {
pub fn add_request(&mut self, key_id: KeyId, req: IssuanceRequest) {
self.keys.add_request(key_id, req);
}
@@ -155,13 +158,18 @@ impl ResourceClass {
pub fn cert_requests(&self) -> Vec<IssuanceRequest> {
self.keys.cert_requests()
}
/// Returns the revocation request for the old key, if it exists.
pub fn revoke_request(&self) -> Option<&RevocationRequest> {
self.keys.revoke_request()
}
}
/// # Publishing
///
impl ResourceClass {
/// Applies a publication delta to the appropriate key in this resource class.
pub fn apply_delta(&mut self, delta: PublicationDelta, key_id: SignerKeyId) {
pub fn apply_delta(&mut self, delta: PublicationDelta, key_id: KeyId) {
self.keys.apply_delta(delta, key_id);
}
}
@@ -170,7 +178,7 @@ impl ResourceClass {
///
impl ResourceClass {
/// This function marks a certificate as received.
pub fn received_cert(&mut self, key_id: SignerKeyId, cert: RcvdCert) {
pub fn received_cert(&mut self, key_id: KeyId, cert: RcvdCert) {
// if there is a pending key, then we need to do some promotions..
match &mut self.keys {
ResourceClassKeys::Pending(pending) => {
@@ -208,16 +216,38 @@ impl ResourceClass {
}
/// Adds a pending key.
pub fn pending_key_added(&mut self, key_id: SignerKeyId) {
pub fn pending_key_added(&mut self, key_id: KeyId) {
match &self.keys {
ResourceClassKeys::Active(current) => {
let pending = PendingKey::new(key_id);
self.keys = ResourceClassKeys::RollPending(pending, current.clone())
}
_ => unimplemented!("Should never create event to add key when roll in progress")
_ => unimplemented!("Should never create event to add key when roll in progress"),
}
}
/// Activates the new key
pub fn new_key_activated(&mut self, revoke_req: RevocationRequest) {
match &self.keys {
ResourceClassKeys::RollNew(new, current) => {
let old_key = OldKey::new(current.clone(), revoke_req);
self.keys = ResourceClassKeys::RollOld(new.clone(), old_key);
}
_ => unimplemented!("Should never create event to add key when roll in progress"),
}
}
/// Removes the old key, we return the to the state where there is one active key.
pub fn old_key_removed(&mut self) {
match &self.keys {
ResourceClassKeys::RollOld(current, _old) => {
self.keys = ResourceClassKeys::Active(current.clone());
}
_ => unimplemented!("Should never create event to remove old key, when there is none"),
}
}
/// Initiate a key roll
pub fn keyroll_initiate<S: Signer>(
&self,
parent: ParentHandle,
@@ -230,13 +260,46 @@ impl ResourceClass {
return Ok(vec![]);
}
self.keys.keyroll_initiate(
parent,
class_name,
base_repo,
&self.name_space,
signer
)
self.keys
.keyroll_initiate(parent, class_name, base_repo, &self.name_space, signer)
}
/// Activate a new key, if it's been longer than the staging period.
pub fn keyroll_activate<S: Signer>(
&self,
parent: ParentHandle,
class_name: ResourceClassName,
staging: Duration,
signer: &S,
) -> ca::Result<Vec<EvtDet>> {
if self.last_key_change + staging > Time::now() {
return Ok(vec![]);
}
self.keys.keyroll_activate(parent, class_name, signer)
}
/// Finish a key roll, withdraw the old key
pub fn keyroll_finish(
&self,
parent: ParentHandle,
class_name: ResourceClassName,
base_repo: &RepoInfo,
) -> ca::Result<EvtDet> {
let withdraws = match &self.keys {
ResourceClassKeys::RollOld(_current, old) => {
Some(old.current_set().objects().withdraw())
}
_ => None,
}
.ok_or_else(|| Error::InvalidKeyStatus)?;
let mut objects_delta = ObjectsDelta::new(base_repo.ca_repository(self.name_space()));
for withdraw in withdraws.into_iter() {
objects_delta.withdraw(withdraw);
}
Ok(EvtDet::KeyRollFinished(parent, class_name, objects_delta))
}
}
@@ -256,14 +319,13 @@ pub enum ResourceClassKeys {
type NewKey = CertifiedKey;
type CurrentKey = CertifiedKey;
type OldKey = CertifiedKey;
impl ResourceClassKeys {
fn create(pending_key: SignerKeyId) -> Self {
fn create(pending_key: KeyId) -> Self {
ResourceClassKeys::Pending(PendingKey::new(pending_key))
}
fn add_request(&mut self, key_id: SignerKeyId, req: IssuanceRequest) {
fn add_request(&mut self, key_id: KeyId, req: IssuanceRequest) {
match self {
ResourceClassKeys::Pending(pending) => pending.add_request(req),
ResourceClassKeys::Active(current) => current.add_request(req),
@@ -358,7 +420,7 @@ impl ResourceClassKeys {
Ok(current.clone())
} else {
self.matches_key_id(old.key_id(), cert, signer)?;
Ok(old.clone())
Ok(old.key().clone())
}
}
}
@@ -367,7 +429,7 @@ impl ResourceClassKeys {
/// Helper to match a key_id to a pub key.
fn matches_key_id<S: Signer>(
&self,
key_id: &SignerKeyId,
key_id: &KeyId,
cert: &RcvdCert,
signer: &S,
) -> ca::Result<()> {
@@ -407,20 +469,19 @@ impl ResourceClassKeys {
let ca_repo = base_repo.ca_repository(name_space);
let delta = ObjectsDelta::new(ca_repo);
let delta = SignSupport::publish(signer, &certified_key, base_repo, name_space, delta)
.map_err(Error::signer)?;
let delta =
SignSupport::publish(signer, &certified_key, base_repo, name_space, delta, vec![])
.map_err(Error::signer)?;
res.push(EvtDet::Published(
parent,
class_name,
certified_key.key_id().clone(),
delta,
));
let mut delta_map = HashMap::new();
delta_map.insert(certified_key.key_id().clone(), delta);
res.push(EvtDet::Published(parent, class_name, delta_map));
Ok(res)
}
fn apply_delta(&mut self, delta: PublicationDelta, key_id: SignerKeyId) {
fn apply_delta(&mut self, delta: PublicationDelta, key_id: KeyId) {
match self {
ResourceClassKeys::Pending(_pending) => unimplemented!("Cannot apply delta to pending"),
ResourceClassKeys::Active(current) => current.apply_delta(delta),
@@ -558,7 +619,7 @@ impl ResourceClassKeys {
base_repo: &RepoInfo,
name_space: &str,
class_name: &str,
key: &SignerKeyId,
key: &KeyId,
signer: &S,
) -> Result<IssuanceRequest> {
let pub_key = signer.get_key_info(key).map_err(Error::signer)?;
@@ -581,6 +642,14 @@ impl ResourceClassKeys {
))
}
/// Returns the revoke request if there is an old key.
pub fn revoke_request(&self) -> Option<&RevocationRequest> {
match self {
ResourceClassKeys::RollOld(_current, old) => Some(old.revoke_req()),
_ => None,
}
}
fn as_info(&self) -> ResourceClassKeysInfo {
match self.clone() {
ResourceClassKeys::Pending(p) => ResourceClassKeysInfo::Pending(p),
@@ -617,7 +686,7 @@ impl ResourceClassKeys {
self.create_issuance_req(base_repo, name_space, &class_name, &key_id, signer)?;
Ok(vec![
EvtDet::KeyrollPendingKeyAdded(
EvtDet::KeyRollPendingKeyAdded(
parent.clone(),
class_name.clone(),
key_id.clone(),
@@ -628,4 +697,31 @@ impl ResourceClassKeys {
_ => Ok(vec![]),
}
}
/// Marks the new key as current, and the current key as old, and requests revocation of
/// the old key.
// TODO: When ROAs are supported, now is also the time to republish all objects under the
// new current key, and withdraw them from the old key.
fn keyroll_activate<S: Signer>(
&self,
parent: ParentHandle,
class_name: ResourceClassName,
signer: &S,
) -> ca::Result<Vec<EvtDet>> {
match self {
ResourceClassKeys::RollNew(_new, current) => {
let ki = signer
.get_key_info(current.key_id())
.map_err(Error::signer)?
.key_identifier();
let revoke_req = RevocationRequest::new(class_name.clone(), ki);
Ok(vec![EvtDet::KeyRollActivated(
parent, class_name, revoke_req,
)])
}
_ => Ok(vec![]),
}
}
}
+218 -109
View File
@@ -15,16 +15,20 @@ use krill_commons::api::admin::{
use krill_commons::api::ca::{
CertAuthList, CertAuthSummary, ChildCaInfo, IssuedCert, RcvdCert, RepoInfo,
};
use krill_commons::api::{Entitlements, IssuanceRequest, IssuanceResponse, DFLT_CLASS};
use krill_commons::api::{
Entitlements, IssuanceRequest, IssuanceResponse, RevocationRequest, RevocationResponse,
DFLT_CLASS,
};
use krill_commons::eventsourcing::{Aggregate, AggregateStore, DiskAggregateStore};
use krill_commons::remote::builder::SignedMessageBuilder;
use krill_commons::remote::sigmsg::SignedMessage;
use krill_commons::remote::{rfc6492, rfc8183};
use krill_commons::util::httpclient;
use krill_commons::util::softsigner::SignerKeyId;
use krill_commons::util::softsigner::KeyId;
use crate::ca::{
self, CertAuth, ChildHandle, CmdDet, IniDet, ParentHandle, ServerError, ServerResult, Signer,
self, CertAuth, ChildHandle, CmdDet, IniDet, ParentHandle, ResourceClassName, ServerError,
ServerResult, Signer,
};
use crate::mq::EventQueueListener;
@@ -208,34 +212,32 @@ impl<S: Signer> CaServer<S> {
/// Verifies an RFC6492 message and returns the child handle, token,
/// and content of the request, so that the simple 'list' and 'issue'
/// functions can be called.
pub fn rfc6492(&self, parent_handle: &Handle, msg: SignedMessage) -> ServerResult<Bytes, S> {
info!("RFC6492 Request: will check");
pub fn rfc6492(&self, ca_handle: &Handle, msg: SignedMessage) -> ServerResult<Bytes, S> {
debug!("RFC6492 Request: will check");
let (content, token) = {
let parent = self.ca_store.get_latest(parent_handle)?;
parent.verify_rfc6492(msg)?
let ca = self.ca_store.get_latest(ca_handle)?;
ca.verify_rfc6492(msg)?
};
info!("RFC6492 Request: verified");
debug!("RFC6492 Request: verified");
let (sender, recipient, content) = content.unwrap();
let sender_handle = Handle::from(sender.as_str());
let child = Handle::from(sender.as_str());
match content {
rfc6492::Content::Qry(rfc6492::Qry::Revoke(_)) => {
unimplemented!("Revocation not yet supported")
rfc6492::Content::Qry(rfc6492::Qry::Revoke(req)) => {
let res = self.revoke(ca_handle, child, req)?;
let msg = rfc6492::Message::revoke_response(sender, recipient, res);
self.wrap_rfc6492_response(ca_handle, msg)
}
rfc6492::Content::Qry(rfc6492::Qry::List) => {
let entitlements = self.list(parent_handle, &sender_handle, &token)?;
let entitlements = self.list(ca_handle, &child, &token)?;
let msg = rfc6492::Message::list_response(sender, recipient, entitlements);
self.wrap_rfc6492_response(parent_handle, msg)
self.wrap_rfc6492_response(ca_handle, msg)
}
rfc6492::Content::Qry(rfc6492::Qry::Issue(req)) => {
let res = self.issue(parent_handle, &sender_handle, req, token)?;
let res = self.issue(ca_handle, &child, req, token)?;
let msg = rfc6492::Message::issue_response(sender, recipient, res);
self.wrap_rfc6492_response(parent_handle, msg)
self.wrap_rfc6492_response(ca_handle, msg)
}
_ => Err(ServerError::custom("Unsupported RFC6492 message")),
}
@@ -276,7 +278,7 @@ impl<S: Signer> CaServer<S> {
pub fn issue(
&self,
parent: &Handle,
child: &Handle,
child: &ChildHandle,
issue_req: IssuanceRequest,
token: Token,
) -> ServerResult<IssuanceResponse, S> {
@@ -311,6 +313,25 @@ impl<S: Signer> CaServer<S> {
}
}
/// See: https://tools.ietf.org/html/rfc6492#section3.5.1-2
pub fn revoke(
&self,
ca_handle: &Handle,
child: ChildHandle,
revoke_request: RevocationRequest,
) -> ServerResult<RevocationResponse, S> {
let res = (&revoke_request).into(); // response provided that no errors are returned earlier
let cmd =
CmdDet::revoke_key_for_child(ca_handle, child, revoke_request, self.signer.clone());
let ca = self.get_ca(ca_handle)?;
let events = ca.process_command(cmd)?;
self.ca_store.update(ca_handle, ca, events)?;
Ok(res)
}
/// Get the current CAs
pub fn cas(&self) -> CertAuthList {
CertAuthList::new(
@@ -343,7 +364,7 @@ impl<S: Signer> CaServer<S> {
let ca = self.get_ca(&handle)?;
let (parent_handle, parent_contact) = parent.unwrap();
let add = CmdDet::add_parent(&handle, parent_handle.as_str(), parent_contact);
let add = CmdDet::add_parent(&handle, parent_handle, parent_contact);
let events = ca.process_command(add)?;
self.ca_store.update(&handle, ca, events)?;
@@ -355,10 +376,26 @@ impl<S: Signer> CaServer<S> {
pub fn ca_keyroll_init(&self, handle: Handle, max_age: Duration) -> ServerResult<(), S> {
let ca = self.get_ca(&handle)?;
let init_key_roll = CmdDet::init_roll(&handle, max_age, self.signer.clone());
let init_key_roll = CmdDet::key_roll_init(&handle, max_age, self.signer.clone());
let events = ca.process_command(init_key_roll)?;
if ! events.is_empty() {
if !events.is_empty() {
self.ca_store.update(&handle, ca, events)?;
}
Ok(())
}
/// Activate a new key, as part of the key roll process (RFC6489). Only new keys that
/// have an age equal to or greater than the staging period are promoted. The RFC mandates
/// a staging period of 24 hours, but we may use a shorter period for testing and/or emergency
/// manual key rolls.
pub fn ca_keyroll_activate(&self, handle: Handle, staging: Duration) -> ServerResult<(), S> {
let ca = self.get_ca(&handle)?;
let activate_cmd = CmdDet::key_roll_activate(&handle, staging, self.signer.clone());
let events = ca.process_command(activate_cmd)?;
if !events.is_empty() {
self.ca_store.update(&handle, ca, events)?;
}
@@ -372,9 +409,8 @@ impl<S: Signer> CaServer<S> {
for handle in self.ca_store.list() {
if let Ok(ca) = self.get_ca(&handle) {
if let Ok(parents) = ca.parents() {
for (parent, info) in parents.into_iter() {
let contact = info.contact();
if let Err(e) = self.get_updates_from_parent(&handle, &parent, contact) {
for (parent, _info) in parents.into_iter() {
if let Err(e) = self.get_updates_from_parent(&handle, &parent) {
error!(
"Failed to refresh CA certificates for {}, error: {}",
&handle, e
@@ -393,41 +429,140 @@ impl<S: Signer> CaServer<S> {
&self,
handle: &Handle,
parent: &ParentHandle,
contact: &ParentCaContact,
) -> ServerResult<(), S> {
let entitlements = self.get_entitlements_from_parent(handle, contact)?;
let entitlements = self.get_entitlements_from_parent(handle, parent)?;
if !self.update_if_need(handle, parent, entitlements)? {
if !self.update_if_needed(handle, parent.clone(), entitlements)? {
return Ok(()); // Nothing to do
}
self.send_requests(handle, parent, contact)
self.send_requests(handle, parent)
}
fn send_requests(
&self,
handle: &Handle,
parent: &ParentHandle,
contact: &ParentCaContact,
) -> ServerResult<(), S> {
match contact {
ParentCaContact::Embedded(_p, token) => {
self.send_requests_embedded(handle, parent, token)
pub fn send_requests(&self, handle: &Handle, parent: &ParentHandle) -> ServerResult<(), S> {
self.send_revoke_requests(handle, parent)?;
self.send_cert_requests(handle, parent)
}
fn send_revoke_requests(&self, handle: &Handle, parent: &ParentHandle) -> ServerResult<(), S> {
let mut child = self.ca_store.get_latest(handle)?;
let revoke_request = child.revoke_requests(parent);
let revoke_responses = match child.parent(parent)?.contact() {
ParentCaContact::Embedded(_parent, _token) => {
self.send_revoke_requests_embedded(revoke_request, handle, parent)
}
ParentCaContact::Rfc6492(res) => self.send_requests_rfc6492(handle, parent, res),
_ => unimplemented!(),
ParentCaContact::Rfc6492(parent_res) => {
self.send_revoke_requests_rfc6492(revoke_request, child.id_key(), parent_res)
}
ParentCaContact::RemoteKrill(_, _) => unimplemented!(),
}?;
for response in revoke_responses.into_iter() {
let cmd = CmdDet::key_roll_finish(handle, parent.clone(), response);
let events = child.process_command(cmd)?;
child = self.ca_store.update(handle, child, events)?;
}
Ok(())
}
fn send_requests_embedded(
fn send_revoke_requests_embedded(
&self,
revoke_requests: Vec<&RevocationRequest>,
handle: &Handle,
parent_h: &ParentHandle,
) -> ServerResult<Vec<RevocationResponse>, S> {
let mut parent = self.ca_store.get_latest(parent_h)?;
let mut revocation_responses = vec![];
for req in revoke_requests.into_iter() {
let cmd = CmdDet::revoke_key_for_child(
parent_h,
handle.clone(),
req.clone(),
self.signer.clone(),
);
let events = parent.process_command(cmd)?;
parent = self.ca_store.update(parent_h, parent, events)?;
revocation_responses.push(req.into());
}
Ok(revocation_responses)
}
fn send_revoke_requests_rfc6492(
&self,
revoke_requests: Vec<&RevocationRequest>,
signing_key: &KeyId,
parent_res: &rfc8183::ParentResponse,
) -> ServerResult<Vec<RevocationResponse>, S> {
let mut res = vec![];
for req in revoke_requests.into_iter() {
let sender = parent_res.child_handle().to_string();
let recipient = parent_res.parent_handle().to_string();
let revoke = rfc6492::Message::revoke(sender, recipient, req.clone());
match self.send_rfc6492_and_validate_response(
signing_key,
parent_res,
revoke.into_bytes(),
) {
Err(e) => error!("Could not send/validate revoke: {}", e),
Ok(response) => match response {
rfc6492::Res::Revoke(revoke_response) => res.push(revoke_response),
rfc6492::Res::NotPerformed(e) => error!("We got an error response: {}", e),
rfc6492::Res::List(_) => error!("List response to revoke request??"),
rfc6492::Res::Issue(_) => error!("Issue response to revoke request??"),
},
}
}
Ok(res)
}
fn send_cert_requests(&self, handle: &Handle, parent: &ParentHandle) -> ServerResult<(), S> {
let mut child = self.ca_store.get_latest(handle)?;
let cert_requests = child.cert_requests(parent);
let issued_certs = match child.parent(parent)?.contact() {
ParentCaContact::Embedded(_parent, token) => {
self.send_cert_requests_embedded(cert_requests, handle, parent, token)
}
ParentCaContact::Rfc6492(parent_res) => {
self.send_cert_requests_rfc6492(cert_requests, child.id_key(), &parent_res)
}
ParentCaContact::RemoteKrill(_, _) => unimplemented!("Deprecate?"),
}?;
for (class_name, issued) in issued_certs.into_iter() {
let received = RcvdCert::from(issued);
let upd_rcvd_cmd = CmdDet::upd_received_cert(
handle,
parent.clone(),
class_name,
received,
self.signer.clone(),
);
let evts = child.process_command(upd_rcvd_cmd)?;
child = self.ca_store.update(handle, child, evts)?;
}
Ok(())
}
fn send_cert_requests_embedded(
&self,
requests: Vec<IssuanceRequest>,
handle: &Handle,
parent_h: &ParentHandle,
token: &Token,
) -> ServerResult<(), S> {
let mut child = self.ca_store.get_latest(handle)?;
let requests = child.cert_requests(parent_h);
) -> ServerResult<Vec<(ResourceClassName, IssuedCert)>, S> {
let mut parent = self.ca_store.get_latest(parent_h)?;
let mut issued_certs: Vec<(String, IssuedCert)> = vec![];
@@ -453,83 +588,51 @@ impl<S: Signer> CaServer<S> {
issued_certs.push((class_name, issued));
}
for (class_name, issued) in issued_certs {
let received = RcvdCert::from(issued);
let upd_rcvd_cmd = CmdDet::upd_received_cert(
handle,
parent_h,
&class_name,
received,
self.signer.clone(),
);
let evts = child.process_command(upd_rcvd_cmd)?;
child = self.ca_store.update(handle, child, evts)?;
}
Ok(())
Ok(issued_certs)
}
fn send_requests_rfc6492(
fn send_cert_requests_rfc6492(
&self,
handle: &Handle,
parent_h: &ParentHandle,
requests: Vec<IssuanceRequest>,
signing_key: &KeyId,
parent_res: &rfc8183::ParentResponse,
) -> ServerResult<(), S> {
let mut child = self.ca_store.get_latest(handle)?;
let requests = child.cert_requests(parent_h);
) -> ServerResult<Vec<(ResourceClassName, IssuedCert)>, S> {
let mut res = vec![];
for req in requests.into_iter() {
let sender = parent_res.child_handle().to_string();
let recipient = parent_res.parent_handle().to_string();
let issue = rfc6492::Message::issue(sender, recipient, req);
let res = self.send_rfc6492_and_validate_response(
child.id_key(),
match self.send_rfc6492_and_validate_response(
signing_key,
parent_res,
issue.into_bytes(),
)?;
match res {
rfc6492::Res::Error(_) => unimplemented!("Deal with error"),
rfc6492::Res::Issue(issue_response) => {
let (class_name, _, _, issued) = issue_response.unwrap();
let received = RcvdCert::from(issued);
let update_rcvd_cmd = CmdDet::upd_received_cert(
handle,
parent_h,
&class_name,
received,
self.signer.clone(),
);
let events = child.process_command(update_rcvd_cmd)?;
child = self.ca_store.update(handle, child, events)?;
}
_ => {
return {
Err(ServerError::custom(
"Got unexpected response to issue query",
))
) {
Err(e) => error!("Could not send/validate csr: {}", e),
Ok(response) => match response {
rfc6492::Res::NotPerformed(e) => error!("We got an error response: {}", e),
rfc6492::Res::Issue(issue_response) => {
let (class_name, _, _, issued) = issue_response.unwrap();
res.push((class_name, issued));
}
}
rfc6492::Res::List(_) => error!("List reply to issue request??"),
rfc6492::Res::Revoke(_) => error!("Revoke reply to issue request??"),
},
}
}
Ok(())
Ok(res)
}
/// Updates the CA if entitlements are different from what the CA
/// currently has under this parent. Returns [`Ok(true)`] in case
/// there were any updates. In that case the CA will have been updated
/// with open certificate requests which can be retrieved.
fn update_if_need(
fn update_if_needed(
&self,
handle: &Handle,
parent: &ParentHandle,
parent: ParentHandle,
entitlements: Entitlements,
) -> ServerResult<bool, S> {
let child = self.ca_store.get_latest(handle)?;
@@ -549,9 +652,9 @@ impl<S: Signer> CaServer<S> {
fn get_entitlements_from_parent(
&self,
handle: &Handle,
contact: &ParentCaContact,
parent: &ParentHandle,
) -> ServerResult<api::Entitlements, S> {
match contact {
match self.get_ca(&handle)?.parent(parent)?.contact() {
ParentCaContact::Embedded(parent, token) => {
self.get_entitlements_embedded(handle, parent, token)
}
@@ -587,7 +690,9 @@ impl<S: Signer> CaServer<S> {
self.send_rfc6492_and_validate_response(child.id_key(), parent_res, list.into_bytes())?;
match response {
rfc6492::Res::Error(_) => unimplemented!("Deal with error response"),
rfc6492::Res::NotPerformed(np) => {
Err(ServerError::Custom(format!("Not performed: {}", np)))
}
rfc6492::Res::List(ent) => Ok(ent),
_ => Err(ServerError::custom("Got unexpected response to list query")),
}
@@ -595,7 +700,7 @@ impl<S: Signer> CaServer<S> {
fn send_rfc6492_and_validate_response(
&self,
signing_key: &SignerKeyId,
signing_key: &KeyId,
parent_res: &rfc8183::ParentResponse,
msg: Bytes,
) -> ServerResult<rfc6492::Res, S> {
@@ -780,7 +885,7 @@ mod tests {
let parent = ParentCaContact::for_embedded(ta_handle.clone(), child_token.clone());
let add_parent = CmdDet::add_parent(&child_handle, ta_handle.as_str(), parent);
let add_parent = CmdDet::add_parent(&child_handle, ta_handle.clone(), parent);
let events = child.process_command(add_parent).unwrap();
let child = ca_store.update(&child_handle, child, events).unwrap();
@@ -796,8 +901,12 @@ mod tests {
let entitlements = ta.list(&child_handle, &child_token).unwrap();
let upd_ent =
CmdDet::upd_entitlements(&child_handle, &ta_handle, entitlements, signer.clone());
let upd_ent = CmdDet::upd_entitlements(
&child_handle,
ta_handle.clone(),
entitlements,
signer.clone(),
);
let events = child.process_command(upd_ent).unwrap();
assert_eq!(2, events.len()); // rc and csr
@@ -836,7 +945,7 @@ mod tests {
let _ta = ca_store.update(&ta_handle, ta, ta_events).unwrap();
let (handle, issuance_res) = match issued_evt {
EvtDet::CertificateIssued(child, issued) => (child, issued),
EvtDet::ChildCertificateIssued(child, issued) => (child, issued),
_ => panic!("Expected issued certificate."),
};
let (class_name, _, _, issued) = issuance_res.unwrap();
@@ -855,8 +964,8 @@ mod tests {
let upd_rcvd = CmdDet::upd_received_cert(
&child_handle,
&ta_handle,
DFLT_CLASS,
ta_handle,
DFLT_CLASS.to_string(),
rcvd_cert,
signer.clone(),
);
+9 -21
View File
@@ -1,11 +1,9 @@
//! Support for signing mft, crl, certificates, roas..
//! Common objects for TAs and CAs
use std::fmt::Debug;
use std::ops::Deref;
use std::sync::{Arc, RwLock};
use bytes::Bytes;
use serde::Serialize;
use rpki::crl::{Crl, TbsCertList};
use rpki::crypto::signer::KeyError;
@@ -18,27 +16,12 @@ use krill_commons::api::ca::{
AddedObject, CertifiedKey, CurrentObject, ObjectsDelta, PublicationDelta, RepoInfo, Revocation,
RevocationsDelta, UpdatedObject,
};
use krill_commons::util::softsigner::SignerKeyId;
use krill_commons::util::softsigner::KeyId;
//------------ Signer --------------------------------------------------------
pub trait Signer:
crypto::Signer<KeyId = SignerKeyId> + Clone + Debug + Serialize + Sized + Sync + Send + 'static
{
}
impl<
T: crypto::Signer<KeyId = SignerKeyId>
+ Clone
+ Debug
+ Serialize
+ Sized
+ Sync
+ Send
+ 'static,
> Signer for T
{
}
pub trait Signer: crypto::Signer<KeyId = KeyId> + Clone + Sized + Sync + Send + 'static {}
impl<T: crypto::Signer<KeyId = KeyId> + Clone + Sized + Sync + Send + 'static> Signer for T {}
//------------ CaSignSupport -------------------------------------------------
@@ -57,6 +40,7 @@ impl SignSupport {
repo_info: &RepoInfo,
name_space: &str,
mut objects_delta: ObjectsDelta,
new_revocations: Vec<Revocation>,
) -> Result<PublicationDelta, SignError<S>> {
let aia = ca_key.incoming_cert().uri();
let key_id = ca_key.key_id();
@@ -81,12 +65,16 @@ impl SignSupport {
let mut revocations = current_set.revocations().clone();
let mut revocations_delta = RevocationsDelta::default();
let mut current_objects = current_set.objects().clone();
for revocation in new_revocations.into_iter() {
revocations_delta.add(revocation);
}
for expired in revocations.purge() {
revocations_delta.drop(expired);
}
let mut current_objects = current_set.objects().clone();
let mft_name = RepoInfo::mft_name(&pub_key.key_identifier());
let mft_uri = repo_info.resolve(name_space, &mft_name);
let old_mft = current_set.objects().object_for(&mft_name);
+13 -4
View File
@@ -380,12 +380,21 @@ pub fn ca_add_parent(
pub fn ca_keyroll_init(
server: web::Data<AppServer>,
auth: Auth,
handle: Path<Handle>
handle: Path<Handle>,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
render_empty_res(
server.read().ca_keyroll_init(handle.into_inner())
)
render_empty_res(server.read().ca_keyroll_init(handle.into_inner()))
})
}
/// Force key activation for all new keys, i.e. use a staging period of 0 seconds.
pub fn ca_keyroll_activate(
server: web::Data<AppServer>,
auth: Auth,
handle: Path<Handle>,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
render_empty_res(server.read().ca_keyroll_activate(handle.into_inner()))
})
}
+6 -7
View File
@@ -72,12 +72,10 @@ pub fn start(config: &Config) -> Result<(), Error> {
.service(
scope("/api/v1")
.route("/health", get().to(api_health))
.route("/publishers", get().to(publishers))
.route("/publishers", post().to(add_publisher))
.route("/publishers/{handle}", get().to(publisher_details))
.route("/publishers/{handle}", delete().to(deactivate_publisher))
.route("/rfc8181/clients", get().to(rfc8181_clients))
.route("/rfc8181/clients", post().to(add_rfc8181_client))
.data(web::Bytes::configure(|cfg| cfg.limit(256 * 1024 * 1024)))
@@ -85,21 +83,22 @@ pub fn start(config: &Config) -> Result<(), Error> {
"/rfc8181/{handle}/response.xml",
get().to(repository_response),
)
.route("/trustanchor", get().to(ta_info))
.route("/trustanchor", post().to(ta_init))
.route("/trustanchor/children", post().to(ta_add_child))
.route("/trustanchor/children/{handle}", get().to(ta_show_child))
.route("/trustanchor/children/{handle}", post().to(ta_update_child))
.route("/cas", post().to(ca_init))
.route("/cas", get().to(cas))
.route("/cas/{handle}", get().to(ca_info))
.route("/cas/{handle}/child_request", get().to(ca_child_req))
.route("/cas/{handle}/parents", post().to(ca_add_parent))
.route("/cas/{handle}/keys/init_roll", post().to(ca_keyroll_init))
.route("/republish", post().to(republish_all))
.route("/cas/{handle}/keys/roll_init", post().to(ca_keyroll_init))
.route(
"/cas/{handle}/keys/roll_activate",
post().to(ca_keyroll_activate),
)
.route("/republish", post().to(republish_all)),
)
// Public TA related methods
.route("/ta/ta.tal", get().to(tal))
+10 -2
View File
@@ -4,8 +4,8 @@ use std::path::PathBuf;
use std::sync::Arc;
use bcder::Captured;
use chrono::Duration;
use bytes::Bytes;
use chrono::Duration;
use rpki::uri;
use krill_commons::api::admin;
@@ -374,7 +374,15 @@ impl KrillServer {
}
pub fn ca_keyroll_init(&self, handle: Handle) -> EmptyRes {
Ok(self.caserver.ca_keyroll_init(handle, Duration::seconds(0))?)
Ok(self
.caserver
.ca_keyroll_init(handle, Duration::seconds(0))?)
}
pub fn ca_keyroll_activate(&self, handle: Handle) -> EmptyRes {
Ok(self
.caserver
.ca_keyroll_activate(handle, Duration::seconds(0))?)
}
pub fn list(&self, parent: &Handle, child: &Handle, auth: Auth) -> KrillRes<Entitlements> {
+25 -6
View File
@@ -7,7 +7,7 @@ use std::collections::VecDeque;
use std::fmt;
use std::sync::RwLock;
use krill_commons::api::admin::{Handle, ParentCaContact};
use krill_commons::api::admin::Handle;
use krill_commons::api::publication::PublishDelta;
use krill_commons::eventsourcing;
@@ -20,8 +20,9 @@ use crate::ca::{CertAuth, Evt, EvtDet, ParentHandle, Signer};
#[derive(Clone, Debug, Eq, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum QueueEvent {
ParentAdded(Handle, ParentHandle, ParentCaContact),
Delta(Handle, PublishDelta),
ParentAdded(Handle, ParentHandle),
RequestsPending(Handle, ParentHandle),
}
#[derive(Debug)]
@@ -61,8 +62,12 @@ impl<S: Signer> eventsourcing::EventListener<CertAuth<S>> for EventQueueListener
let handle = event.handle();
match event.details() {
EvtDet::Published(_, _, _, delta) => {
let evt = QueueEvent::Delta(handle.clone(), delta.objects().clone().into());
EvtDet::Published(_, _, delta) => {
let publish_delta = delta.values().fold(PublishDelta::empty(), |acc, el| {
acc + el.objects().clone().into()
});
let evt = QueueEvent::Delta(handle.clone(), publish_delta);
self.push_back(evt);
}
EvtDet::TaPublished(delta) => {
@@ -73,8 +78,22 @@ impl<S: Signer> eventsourcing::EventListener<CertAuth<S>> for EventQueueListener
let evt = QueueEvent::Delta(handle.clone(), delta.clone().into());
self.push_back(evt);
}
EvtDet::ParentAdded(parent, contact) => {
let evt = QueueEvent::ParentAdded(handle.clone(), parent.clone(), contact.clone());
EvtDet::KeyRollFinished(_parent, _class_name, delta) => {
let evt = QueueEvent::Delta(handle.clone(), delta.clone().into());
self.push_back(evt);
}
EvtDet::ParentAdded(parent, _contact) => {
let evt = QueueEvent::ParentAdded(handle.clone(), parent.clone());
self.push_back(evt);
}
EvtDet::CertificateRequested(parent, _, _) => {
let evt = QueueEvent::RequestsPending(handle.clone(), parent.clone());
self.push_back(evt);
}
EvtDet::KeyRollActivated(parent, _, _) => {
let evt = QueueEvent::RequestsPending(handle.clone(), parent.clone());
self.push_back(evt);
}
_ => {}
+11 -5
View File
@@ -56,11 +56,17 @@ fn make_event_sh(
QueueEvent::Delta(handle, delta) => {
publish(&handle, delta, &pubserver);
}
QueueEvent::ParentAdded(handle, parent, contact) => {
if let Err(e) = caserver.get_updates_from_parent(&handle, &parent, &contact) {
error!("Getting updates for {}, error: {}", &handle, e);
} else {
info!("Parent added, updated certificates for CA {}", &handle);
QueueEvent::ParentAdded(handle, parent) => {
if let Err(e) = caserver.get_updates_from_parent(&handle, &parent) {
error!(
"Error getting updates for {}, from parent: {}, error: {}",
&handle, &parent, e
)
}
}
QueueEvent::RequestsPending(handle, parent) => {
if let Err(e) = caserver.send_requests(&handle, &parent) {
error!("Sending pending requests for {}, error: {}", &handle, e);
}
}
}
+53 -19
View File
@@ -9,7 +9,7 @@ use krill_commons::api::admin::{
AddChildRequest, AddParentRequest, CertAuthInit, CertAuthPubMode, ChildAuthRequest, Handle,
ParentCaContact, Token, UpdateChildRequest,
};
use krill_commons::api::ca::{CaParentsInfo, CertAuthInfo, ResourceSet, ResourceClassKeysInfo};
use krill_commons::api::ca::{CaParentsInfo, CertAuthInfo, ResourceClassKeysInfo, ResourceSet};
use krill_commons::remote::rfc8183;
use krill_daemon::ca::ta_handle;
use krill_daemon::test::{krill_admin, test_with_krill_server, wait_seconds};
@@ -78,10 +78,16 @@ fn add_parent_to_ca(handle: &Handle, parent: AddParentRequest) {
)));
}
fn ca_init_roll(handle: &Handle) {
fn ca_roll_init(handle: &Handle) {
krill_admin(Command::CertAuth(CaCommand::KeyRollInit(handle.clone())));
}
fn ca_roll_activate(handle: &Handle) {
krill_admin(Command::CertAuth(CaCommand::KeyRollActivate(
handle.clone(),
)));
}
fn ca_details(handle: &Handle) -> CertAuthInfo {
match krill_admin(Command::CertAuth(CaCommand::Show(handle.clone()))) {
ApiResponse::CertAuthInfo(inf) => inf,
@@ -89,7 +95,10 @@ fn ca_details(handle: &Handle) -> CertAuthInfo {
}
}
fn wait_for<O>(tries: u64, error_msg: &'static str, op: O) where O: Copy + FnOnce() -> bool {
fn wait_for<O>(tries: u64, error_msg: &'static str, op: O)
where
O: Copy + FnOnce() -> bool,
{
for _counter in 1..tries + 1 {
if op() == true {
return;
@@ -100,22 +109,26 @@ fn wait_for<O>(tries: u64, error_msg: &'static str, op: O) where O: Copy + FnOnc
}
fn wait_for_resources_on_current_key(handle: &Handle, resources: &ResourceSet) {
wait_for(30, "cms child did not get its resource certificate", move || {
let cms_ca_info = ca_details(handle);
wait_for(
30,
"cms child did not get its resource certificate",
move || {
let cms_ca_info = ca_details(handle);
if let CaParentsInfo::Parents(parents) = cms_ca_info.parents() {
if let Some(parent) = parents.get(&ta_handle()) {
if let Some(rc) = parent.resources().get("all") {
if let Some(current_resources) = rc.current_resources() {
if resources == current_resources {
return true;
if let CaParentsInfo::Parents(parents) = cms_ca_info.parents() {
if let Some(parent) = parents.get(&ta_handle()) {
if let Some(rc) = parent.resources().get("all") {
if let Some(current_resources) = rc.current_resources() {
if resources == current_resources {
return true;
}
}
}
}
}
}
false
})
false
},
)
}
fn wait_for_new_key(handle: &Handle) {
@@ -126,8 +139,28 @@ fn wait_for_new_key(handle: &Handle) {
if let Some(parent) = parents.get(&ta_handle()) {
if let Some(rc) = parent.resources().get("all") {
match rc.keys() {
ResourceClassKeysInfo::RollNew(_,_) => return true,
_ => return false
ResourceClassKeysInfo::RollNew(new, _) => {
return new.current_set().number() == 2
}
_ => return false,
}
}
}
}
false
})
}
fn wait_for_key_roll_complete(handle: &Handle) {
wait_for(30, "Key roll did not complete", || {
let cms_ca_info = ca_details(handle);
if let CaParentsInfo::Parents(parents) = cms_ca_info.parents() {
if let Some(parent) = parents.get(&ta_handle()) {
if let Some(rc) = parent.resources().get("all") {
match rc.keys() {
ResourceClassKeysInfo::Active(_) => return true,
_ => return false,
}
}
}
@@ -174,15 +207,16 @@ fn ca_under_ta() {
};
add_parent_to_ca(&cms_child_handle, parent);
wait_for_resources_on_current_key(&cms_child_handle, &cms_child_resources);
let cms_child_resources = ResourceSet::from_strs("AS65000", "10.0.0.0/16", "").unwrap();
update_child(&cms_child_handle, &cms_child_resources);
wait_for_resources_on_current_key(&cms_child_handle, &cms_child_resources);
ca_init_roll(&cms_child_handle);
ca_roll_init(&cms_child_handle);
wait_for_new_key(&cms_child_handle);
ca_roll_activate(&cms_child_handle);
wait_for_key_roll_complete(&cms_child_handle);
});
}