#![warn(missing_docs)]
use crate::base::iana::SecurityAlgorithm;
use crate::base::Name;
use crate::rdata::dnssec::Timestamp;
use serde::{Deserialize, Serialize};
use std::collections::{hash_map, HashMap, HashSet};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::ops::Add;
use std::str::FromStr;
use std::string::{String, ToString};
use std::time::Duration;
use std::vec::Vec;
#[cfg(test)]
use mock_instant::global::{SystemTime, UNIX_EPOCH};
#[cfg(test)]
use mock_instant::SystemTimeError;
#[cfg(not(test))]
use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH};
#[derive(Clone, Deserialize, Serialize)]
pub struct KeySet {
name: Name<Vec<u8>>,
keys: HashMap<String, Key>,
rollstates: HashMap<RollType, RollState>,
}
impl KeySet {
pub fn new(name: Name<Vec<u8>>) -> Self {
Self {
name,
keys: HashMap::new(),
rollstates: HashMap::new(),
}
}
pub fn add_key_ksk(
&mut self,
pubref: String,
privref: Option<String>,
algorithm: SecurityAlgorithm,
key_tag: u16,
creation_ts: UnixTime,
available: Available,
) -> Result<(), Error> {
if !self.unique_key_tag(key_tag) {
return Err(Error::DuplicateKeyTag);
}
let keystate = KeyState {
available: available.to_bool(),
..Default::default()
};
let key = Key::new(
privref,
KeyType::Ksk(keystate),
algorithm,
key_tag,
creation_ts,
);
if let hash_map::Entry::Vacant(e) = self.keys.entry(pubref) {
e.insert(key);
Ok(())
} else {
Err(Error::KeyExists)
}
}
pub fn add_key_zsk(
&mut self,
pubref: String,
privref: Option<String>,
algorithm: SecurityAlgorithm,
key_tag: u16,
creation_ts: UnixTime,
available: Available,
) -> Result<(), Error> {
if !self.unique_key_tag(key_tag) {
return Err(Error::DuplicateKeyTag);
}
let keystate = KeyState {
available: available.to_bool(),
..Default::default()
};
let key = Key::new(
privref,
KeyType::Zsk(keystate),
algorithm,
key_tag,
creation_ts,
);
if let hash_map::Entry::Vacant(e) = self.keys.entry(pubref) {
e.insert(key);
Ok(())
} else {
Err(Error::KeyExists)
}
}
pub fn add_key_csk(
&mut self,
pubref: String,
privref: Option<String>,
algorithm: SecurityAlgorithm,
key_tag: u16,
creation_ts: UnixTime,
available: Available,
) -> Result<(), Error> {
if !self.unique_key_tag(key_tag) {
return Err(Error::DuplicateKeyTag);
}
let keystate = KeyState {
available: available.to_bool(),
..Default::default()
};
let key = Key::new(
privref,
KeyType::Csk(keystate.clone(), keystate),
algorithm,
key_tag,
creation_ts,
);
if let hash_map::Entry::Vacant(e) = self.keys.entry(pubref) {
e.insert(key);
Ok(())
} else {
Err(Error::KeyExists)
}
}
pub fn add_public_key(
&mut self,
pubref: String,
algorithm: SecurityAlgorithm,
key_tag: u16,
creation_ts: UnixTime,
available: bool,
) -> Result<(), Error> {
if !self.unique_key_tag(key_tag) {
return Err(Error::DuplicateKeyTag);
}
let keystate = KeyState {
available,
..Default::default()
};
let key = Key::new(
None,
KeyType::Include(keystate),
algorithm,
key_tag,
creation_ts,
);
if let hash_map::Entry::Vacant(e) = self.keys.entry(pubref) {
e.insert(key);
Ok(())
} else {
Err(Error::KeyExists)
}
}
pub fn set_decoupled(
&mut self,
pubref: &str,
value: bool,
) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => key.decoupled = value,
}
Ok(())
}
pub fn set_present(
&mut self,
pubref: &str,
value: bool,
) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => {
match &mut key.keytype {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Include(keystate) => {
keystate.present = value;
}
KeyType::Csk(ksk_keystate, zsk_keystate) => {
ksk_keystate.present = value;
zsk_keystate.present = value;
}
};
if value && key.timestamps.published.is_none() {
key.timestamps.published = Some(UnixTime::now());
}
}
}
Ok(())
}
pub fn set_signer(
&mut self,
pubref: &str,
value: bool,
) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => {
match &mut key.keytype {
KeyType::Ksk(keystate) | KeyType::Zsk(keystate) => {
keystate.signer = value;
}
KeyType::Csk(ksk_keystate, zsk_keystate) => {
ksk_keystate.signer = value;
zsk_keystate.signer = value;
}
KeyType::Include(_) => return Err(Error::WrongKeyType),
};
}
}
Ok(())
}
pub fn set_at_parent(
&mut self,
pubref: &str,
value: bool,
) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => {
match &mut key.keytype {
KeyType::Ksk(keystate) => {
keystate.at_parent = value;
}
KeyType::Csk(ksk_keystate, _) => {
ksk_keystate.at_parent = value;
}
KeyType::Zsk(_) | KeyType::Include(_) => {
return Err(Error::WrongKeyType)
}
};
}
}
Ok(())
}
pub fn set_stale(&mut self, pubref: &str) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => {
match &mut key.keytype {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Include(keystate) => {
keystate.old = true;
keystate.present = false;
keystate.signer = false;
keystate.at_parent = false;
}
KeyType::Csk(ksk_keystate, zsk_keystate) => {
ksk_keystate.old = true;
ksk_keystate.present = false;
ksk_keystate.signer = false;
ksk_keystate.at_parent = false;
zsk_keystate.old = true;
zsk_keystate.present = false;
zsk_keystate.signer = false;
zsk_keystate.at_parent = false;
}
};
}
}
Ok(())
}
pub fn set_visible(
&mut self,
pubref: &str,
time: UnixTime,
) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => {
key.timestamps.visible = Some(time);
}
}
Ok(())
}
pub fn set_ds_visible(
&mut self,
pubref: &str,
time: UnixTime,
) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => {
key.timestamps.ds_visible = Some(time);
}
}
Ok(())
}
pub fn set_rrsig_visible(
&mut self,
pubref: &str,
time: UnixTime,
) -> Result<(), Error> {
match self.keys.get_mut(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => {
key.timestamps.rrsig_visible = Some(time);
}
}
Ok(())
}
fn unique_key_tag(&self, key_tag: u16) -> bool {
self.keys.iter().all(|(_, k)| k.key_tag != key_tag)
}
pub fn delete_key(&mut self, pubref: &str) -> Result<(), Error> {
match self.keys.get(pubref) {
None => return Err(Error::KeyNotFound),
Some(key) => match &key.keytype {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Include(keystate) => {
if !keystate.stale() {
return Err(Error::KeyNotOld);
}
}
KeyType::Csk(ksk_keystate, zsk_keystate) => {
if !ksk_keystate.stale() {
return Err(Error::KeyNotOld);
}
if !zsk_keystate.stale() {
return Err(Error::KeyNotOld);
}
}
},
}
self.keys.remove(pubref).expect("key should exist");
Ok(())
}
pub fn name(&self) -> &Name<Vec<u8>> {
&self.name
}
pub fn keys(&self) -> &HashMap<String, Key> {
&self.keys
}
pub fn rollstates(&self) -> &HashMap<RollType, RollState> {
&self.rollstates
}
pub fn start_roll(
&mut self,
rolltype: RollType,
old: &[&str],
new: &[&str],
) -> Result<Vec<Action>, Error> {
let next_state = RollState::Propagation1;
rolltype.rollfn()(RollOp::Start(old, new), self)?;
self.rollstates.insert(rolltype, next_state.clone());
Ok(rolltype.roll_actions_fn()(next_state))
}
pub fn propagation1_complete(
&mut self,
rolltype: RollType,
ttl: u32,
) -> Result<Vec<Action>, Error> {
let Some(RollState::Propagation1) = self.rollstates.get(&rolltype)
else {
return Err(Error::WrongStateForRollOperation);
};
let next_state = RollState::CacheExpire1(ttl);
rolltype.rollfn()(RollOp::Propagation1, self)?;
self.rollstates.insert(rolltype, next_state.clone());
Ok(rolltype.roll_actions_fn()(next_state))
}
pub fn cache_expired1(
&mut self,
rolltype: RollType,
) -> Result<Vec<Action>, Error> {
let Some(RollState::CacheExpire1(ttl)) =
self.rollstates.get(&rolltype)
else {
return Err(Error::WrongStateForRollOperation);
};
let next_state = RollState::Propagation2;
rolltype.rollfn()(RollOp::CacheExpire1(*ttl), self)?;
self.rollstates.insert(rolltype, next_state.clone());
Ok(rolltype.roll_actions_fn()(next_state))
}
pub fn propagation2_complete(
&mut self,
rolltype: RollType,
ttl: u32,
) -> Result<Vec<Action>, Error> {
let Some(RollState::Propagation2) = self.rollstates.get(&rolltype)
else {
return Err(Error::WrongStateForRollOperation);
};
let next_state = RollState::CacheExpire2(ttl);
rolltype.rollfn()(RollOp::Propagation2, self)?;
self.rollstates.insert(rolltype, next_state.clone());
Ok(rolltype.roll_actions_fn()(next_state))
}
pub fn cache_expired2(
&mut self,
rolltype: RollType,
) -> Result<Vec<Action>, Error> {
let Some(RollState::CacheExpire2(ttl)) =
self.rollstates.get(&rolltype)
else {
return Err(Error::WrongStateForRollOperation);
};
let next_state = RollState::Done;
rolltype.rollfn()(RollOp::CacheExpire2(*ttl), self)?;
self.rollstates.insert(rolltype, next_state.clone());
Ok(rolltype.roll_actions_fn()(next_state))
}
pub fn roll_done(
&mut self,
rolltype: RollType,
) -> Result<Vec<Action>, Error> {
let Some(RollState::Done) = self.rollstates.get(&rolltype) else {
return Err(Error::WrongStateForRollOperation);
};
rolltype.rollfn()(RollOp::Done, self)?;
self.rollstates.remove(&rolltype);
Ok(Vec::new())
}
pub fn actions(&self, rolltype: RollType) -> Vec<Action> {
if let Some(rollstate) = self.rollstates.get(&rolltype) {
rolltype.roll_actions_fn()(rollstate.clone())
} else {
Vec::new()
}
}
fn update_ksk(
&mut self,
mode: Mode,
old: &[&str],
new: &[&str],
) -> Result<(), Error> {
let mut tmpkeys = self.keys.clone();
let keys: &mut HashMap<String, Key> = match mode {
Mode::DryRun => &mut tmpkeys,
Mode::ForReal => &mut self.keys,
};
let mut algs_old = HashSet::new();
for k in old {
let Some(ref mut key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Ksk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
keystate.old = true;
algs_old.insert(key.algorithm);
}
let now = UnixTime::now();
let mut algs_new = HashSet::new();
for k in new {
let Some(ref mut key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Ksk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
if *keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
keystate.present = true;
keystate.signer = true;
key.timestamps.published = Some(now.clone());
algs_new.insert(key.algorithm);
}
if algs_old != algs_new {
return Err(Error::AlgorithmSetsMismatch);
}
if !keys.iter().any(|(_, k)| {
if let KeyType::Ksk(keystate) = &k.keytype {
!keystate.old && keystate.present
} else {
false
}
}) {
return Err(Error::NoSuitableKeyPresent);
}
Ok(())
}
fn update_ksk_double_ds(
&mut self,
mode: Mode,
old: &[&str],
new: &[&str],
) -> Result<(), Error> {
let mut tmpkeys = self.keys.clone();
let keys: &mut HashMap<String, Key> = match mode {
Mode::DryRun => &mut tmpkeys,
Mode::ForReal => &mut self.keys,
};
let mut algs_old = HashSet::new();
for k in old {
let Some(ref mut key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Ksk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
keystate.old = true;
algs_old.insert(key.algorithm);
}
let mut algs_new = HashSet::new();
for k in new {
let Some(ref mut key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Ksk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
if *keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
keystate.at_parent = true;
algs_new.insert(key.algorithm);
}
if algs_old != algs_new {
return Err(Error::AlgorithmSetsMismatch);
}
if !keys.iter().any(|(_, k)| {
if let KeyType::Ksk(keystate) = &k.keytype {
!keystate.old && keystate.at_parent
} else {
false
}
}) {
return Err(Error::NoSuitableKeyPresent);
}
Ok(())
}
fn update_zsk(
&mut self,
mode: Mode,
old: &[&str],
new: &[&str],
) -> Result<(), Error> {
let mut tmpkeys = self.keys.clone();
let keys: &mut HashMap<String, Key> = match mode {
Mode::DryRun => &mut tmpkeys,
Mode::ForReal => &mut self.keys,
};
let mut algs_old = HashSet::new();
for k in old {
let Some(ref mut key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Zsk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
keystate.old = true;
algs_old.insert(key.algorithm);
}
let now = UnixTime::now();
let mut algs_new = HashSet::new();
for k in new {
let Some(key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Zsk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
if *keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
keystate.present = true;
key.timestamps.published = Some(now.clone());
algs_new.insert(key.algorithm);
}
if algs_old != algs_new {
return Err(Error::AlgorithmSetsMismatch);
}
if !keys.iter().any(|(_, k)| {
if let KeyType::Zsk(keystate) = &k.keytype {
!keystate.old || keystate.present
} else {
false
}
}) {
return Err(Error::NoSuitableKeyPresent);
}
Ok(())
}
fn update_zsk_double_signature(
&mut self,
mode: Mode,
old: &[&str],
new: &[&str],
) -> Result<(), Error> {
let mut tmpkeys = self.keys.clone();
let keys: &mut HashMap<String, Key> = match mode {
Mode::DryRun => &mut tmpkeys,
Mode::ForReal => &mut self.keys,
};
let mut algs_old = HashSet::new();
for k in old {
let Some(ref mut key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Zsk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
keystate.old = true;
algs_old.insert(key.algorithm);
}
let now = UnixTime::now();
let mut algs_new = HashSet::new();
for k in new {
let Some(key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
let KeyType::Zsk(ref mut keystate) = key.keytype else {
return Err(Error::WrongKeyType);
};
if *keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
keystate.present = true;
keystate.signer = true;
key.timestamps.published = Some(now.clone());
algs_new.insert(key.algorithm);
}
if algs_old != algs_new {
return Err(Error::AlgorithmSetsMismatch);
}
if !keys.iter().any(|(_, k)| {
if let KeyType::Zsk(keystate) = &k.keytype {
!keystate.old || keystate.present
} else {
false
}
}) {
return Err(Error::NoSuitableKeyPresent);
}
Ok(())
}
fn update_csk(
&mut self,
mode: Mode,
old: &[&str],
new: &[&str],
) -> Result<(), Error> {
let mut tmpkeys = self.keys.clone();
let keys: &mut HashMap<String, Key> = match mode {
Mode::DryRun => &mut tmpkeys,
Mode::ForReal => &mut self.keys,
};
let mut algs_old = HashSet::new();
for k in old {
let Some(key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
match key.keytype {
KeyType::Ksk(ref mut keystate)
| KeyType::Zsk(ref mut keystate) => {
keystate.old = true;
}
KeyType::Csk(ref mut ksk_keystate, ref mut zsk_keystate) => {
ksk_keystate.old = true;
zsk_keystate.old = true;
}
KeyType::Include(_) => {
return Err(Error::WrongKeyType);
}
}
algs_old.insert(key.algorithm);
}
let now = UnixTime::now();
let mut algs_new = HashSet::new();
for k in new {
let Some(key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
match key.keytype {
KeyType::Ksk(ref mut keystate) => {
if *keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
keystate.present = true;
keystate.signer = true;
key.timestamps.published = Some(now.clone());
}
KeyType::Zsk(ref mut keystate) => {
if *keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
keystate.present = true;
key.timestamps.published = Some(now.clone());
}
KeyType::Csk(ref mut ksk_keystate, ref mut zsk_keystate) => {
if *ksk_keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
ksk_keystate.present = true;
ksk_keystate.signer = true;
if *zsk_keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
zsk_keystate.present = true;
key.timestamps.published = Some(now.clone());
}
_ => {
return Err(Error::WrongKeyType);
}
}
algs_new.insert(key.algorithm);
}
if algs_old != algs_new {
return Err(Error::AlgorithmSetsMismatch);
}
if !keys.iter().any(|(_, k)| match &k.keytype {
KeyType::Ksk(keystate) | KeyType::Csk(keystate, _) => {
!keystate.old && keystate.present
}
_ => false,
}) {
return Err(Error::NoSuitableKeyPresent);
}
if !keys.iter().any(|(_, k)| match &k.keytype {
KeyType::Zsk(keystate) | KeyType::Csk(_, keystate) => {
!keystate.old && keystate.present
}
_ => false,
}) {
return Err(Error::NoSuitableKeyPresent);
}
Ok(())
}
fn update_algorithm(
&mut self,
mode: Mode,
old: &[&str],
new: &[&str],
) -> Result<(), Error> {
let mut tmpkeys = self.keys.clone();
let keys: &mut HashMap<String, Key> = match mode {
Mode::DryRun => &mut tmpkeys,
Mode::ForReal => &mut self.keys,
};
for k in old {
let Some(key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
match key.keytype {
KeyType::Ksk(ref mut keystate)
| KeyType::Zsk(ref mut keystate) => {
keystate.old = true;
}
KeyType::Csk(ref mut ksk_keystate, ref mut zsk_keystate) => {
ksk_keystate.old = true;
zsk_keystate.old = true;
}
KeyType::Include(_) => {
return Err(Error::WrongKeyType);
}
}
}
let now = UnixTime::now();
for k in new {
let Some(key) = keys.get_mut(&(k.to_string())) else {
return Err(Error::KeyNotFound);
};
match key.keytype {
KeyType::Ksk(ref mut keystate)
| KeyType::Zsk(ref mut keystate) => {
if *keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
keystate.present = true;
keystate.signer = true;
key.timestamps.published = Some(now.clone());
}
KeyType::Csk(ref mut ksk_keystate, ref mut zsk_keystate) => {
if *ksk_keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
ksk_keystate.present = true;
ksk_keystate.signer = true;
if *zsk_keystate
!= (KeyState {
available: true,
old: false,
signer: false,
present: false,
at_parent: false,
})
{
return Err(Error::WrongKeyState);
}
zsk_keystate.present = true;
zsk_keystate.signer = true;
key.timestamps.published = Some(now.clone());
}
_ => {
return Err(Error::WrongKeyType);
}
}
}
if !keys.iter().any(|(_, k)| match &k.keytype {
KeyType::Ksk(keystate) | KeyType::Csk(keystate, _) => {
!keystate.old && keystate.present
}
_ => false,
}) {
return Err(Error::NoSuitableKeyPresent);
}
if !keys.iter().any(|(_, k)| match &k.keytype {
KeyType::Zsk(keystate) | KeyType::Csk(_, keystate) => {
!keystate.old && keystate.present
}
_ => false,
}) {
return Err(Error::NoSuitableKeyPresent);
}
Ok(())
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Key {
privref: Option<String>,
decoupled: bool,
keytype: KeyType,
algorithm: SecurityAlgorithm,
key_tag: u16,
timestamps: KeyTimestamps,
}
impl Key {
pub fn privref(&self) -> Option<&str> {
self.privref.as_deref()
}
pub fn decoupled(&self) -> bool {
self.decoupled
}
pub fn keytype(&self) -> KeyType {
self.keytype.clone()
}
pub fn algorithm(&self) -> SecurityAlgorithm {
self.algorithm
}
pub fn key_tag(&self) -> u16 {
self.key_tag
}
pub fn timestamps(&self) -> &KeyTimestamps {
&self.timestamps
}
fn new(
privref: Option<String>,
keytype: KeyType,
algorithm: SecurityAlgorithm,
key_tag: u16,
creation_ts: UnixTime,
) -> Self {
let timestamps = KeyTimestamps {
creation: Some(creation_ts),
..Default::default()
};
Self {
privref,
decoupled: false,
keytype,
algorithm,
key_tag,
timestamps,
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum KeyType {
Ksk(KeyState),
Zsk(KeyState),
Csk(KeyState, KeyState),
Include(KeyState),
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct KeyState {
available: bool,
old: bool,
signer: bool,
present: bool,
at_parent: bool,
}
impl KeyState {
pub fn old(&self) -> bool {
self.old
}
pub fn signer(&self) -> bool {
self.signer
}
pub fn present(&self) -> bool {
self.present
}
pub fn at_parent(&self) -> bool {
self.at_parent
}
pub fn stale(&self) -> bool {
self.old && !self.signer && !self.present && !self.at_parent
}
}
impl Display for KeyState {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
let mut first = true;
if self.old {
write!(f, "Old")?;
first = false;
}
if self.signer {
write!(f, "{}Signer", if first { "" } else { ", " })?;
first = false;
}
if self.present {
write!(f, "{}Present", if first { "" } else { ", " })?;
first = false;
}
if self.at_parent {
write!(f, "{}At Parent", if first { "" } else { ", " })?;
}
match (self.old, self.signer, self.present) {
(false, false, false) => write!(f, "(Future)")?,
(false, false, true) => write!(f, " (Incoming)")?,
(false, true, true) => write!(f, " (Active)")?,
(true, true, true) => write!(f, " (Leaving)")?,
(true, false, true) => write!(f, " (Retired)")?,
(true, false, false) => write!(f, " (Stale)")?,
(_, _, _) => (),
}
Ok(())
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct KeyTimestamps {
creation: Option<UnixTime>,
published: Option<UnixTime>,
visible: Option<UnixTime>,
ds_visible: Option<UnixTime>,
rrsig_visible: Option<UnixTime>,
withdrawn: Option<UnixTime>,
}
impl KeyTimestamps {
pub fn creation(&self) -> Option<UnixTime> {
self.creation.clone()
}
pub fn published(&self) -> Option<UnixTime> {
self.published.clone()
}
pub fn visible(&self) -> Option<UnixTime> {
self.visible.clone()
}
pub fn ds_visible(&self) -> Option<UnixTime> {
self.ds_visible.clone()
}
pub fn rrsig_visible(&self) -> Option<UnixTime> {
self.rrsig_visible.clone()
}
pub fn withdrawn(&self) -> Option<UnixTime> {
self.withdrawn.clone()
}
}
#[derive(
Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct UnixTime(Duration);
impl UnixTime {
pub fn now() -> Self {
let dur = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("System time is expected to be after UNIX_EPOCH");
UnixTime(dur)
}
pub fn elapsed(&self) -> Duration {
let dur = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("System time is expected to be after UNIX_EPOCH");
if dur < self.0 {
Duration::ZERO
} else {
dur - self.0
}
}
}
impl TryFrom<SystemTime> for UnixTime {
type Error = SystemTimeError;
fn try_from(t: SystemTime) -> Result<Self, SystemTimeError> {
Ok(Self(t.duration_since(UNIX_EPOCH)?))
}
}
impl From<Timestamp> for UnixTime {
fn from(t: Timestamp) -> Self {
Self(Duration::from_secs(t.into_int() as u64))
}
}
impl From<UnixTime> for Duration {
fn from(t: UnixTime) -> Self {
t.0
}
}
impl Add<Duration> for UnixTime {
type Output = UnixTime;
fn add(self, d: Duration) -> Self {
Self(self.0 + d)
}
}
impl Display for UnixTime {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{:.0}", jiff::Timestamp::UNIX_EPOCH + self.0)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum RollState {
Propagation1,
CacheExpire1(u32),
Propagation2,
CacheExpire2(u32),
Done,
}
impl FromStr for RollType {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "ksk-roll" {
Ok(RollType::KskRoll)
} else if s == "ksk-double-ds-roll" {
Ok(RollType::KskDoubleDsRoll)
} else if s == "zsk-roll" {
Ok(RollType::ZskRoll)
} else if s == "zsk-double-signature-roll" {
Ok(RollType::ZskDoubleSignatureRoll)
} else if s == "csk-roll" {
Ok(RollType::CskRoll)
} else if s == "algorithm-roll" {
Ok(RollType::AlgorithmRoll)
} else {
Err(Error::UnknownRollType)
}
}
}
pub enum Available {
Available,
NotAvailable,
}
impl Available {
fn to_bool(&self) -> bool {
match self {
Available::Available => true,
Available::NotAvailable => false,
}
}
}
enum Mode {
DryRun,
ForReal,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Action {
UpdateDnskeyRrset,
CreateCdsRrset,
RemoveCdsRrset,
UpdateDsRrset,
UpdateRrsig,
ReportDnskeyPropagated,
WaitDnskeyPropagated,
ReportDsPropagated,
WaitDsPropagated,
ReportRrsigPropagated,
WaitRrsigPropagated,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum RollType {
KskRoll,
KskDoubleDsRoll,
ZskRoll,
ZskDoubleSignatureRoll,
CskRoll,
AlgorithmRoll,
}
impl RollType {
fn rollfn(&self) -> fn(RollOp<'_>, &mut KeySet) -> Result<(), Error> {
match self {
RollType::KskRoll => ksk_roll,
RollType::KskDoubleDsRoll => ksk_double_ds_roll,
RollType::ZskRoll => zsk_roll,
RollType::ZskDoubleSignatureRoll => zsk_double_signature_roll,
RollType::CskRoll => csk_roll,
RollType::AlgorithmRoll => algorithm_roll,
}
}
fn roll_actions_fn(&self) -> fn(RollState) -> Vec<Action> {
match self {
RollType::KskRoll => ksk_roll_actions,
RollType::KskDoubleDsRoll => ksk_double_ds_roll_actions,
RollType::ZskRoll => zsk_roll_actions,
RollType::ZskDoubleSignatureRoll => {
zsk_double_signature_roll_actions
}
RollType::CskRoll => csk_roll_actions,
RollType::AlgorithmRoll => algorithm_roll_actions,
}
}
}
#[derive(Debug)]
enum RollOp<'a> {
Start(&'a [&'a str], &'a [&'a str]),
Propagation1,
CacheExpire1(u32),
Propagation2,
CacheExpire2(u32),
Done,
}
#[derive(Debug)]
pub enum Error {
KeyExists,
KeyNotFound,
KeyNotOld,
DuplicateKeyTag,
WrongKeyType,
WrongKeyState,
NoSuitableKeyPresent,
WrongStateForRollOperation,
ConflictingRollInProgress,
AlgorithmSetsMismatch,
Wait(Duration),
UnknownRollType,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::KeyExists => write!(f, "key already exists"),
Error::KeyNotFound => write!(f, "key not found"),
Error::KeyNotOld => write!(f, "key is still in use, not old"),
Error::DuplicateKeyTag => write!(f, "Key tag already present"),
Error::WrongKeyType => write!(f, "key has the wrong type"),
Error::WrongKeyState => write!(f, "key is in the wrong state"),
Error::NoSuitableKeyPresent => {
write!(f, "no suitable key present after key roll")
}
Error::WrongStateForRollOperation => {
write!(f, "wrong roll state for operation")
}
Error::ConflictingRollInProgress => {
write!(f, "conflicting roll is in progress")
}
Error::AlgorithmSetsMismatch => {
write!(f, "algorithm set mismatch for non-algorithm key roll")
}
Error::Wait(d) => write!(f, "wait for duration {d:?}"),
Error::UnknownRollType => {
write!(f, "unable to parse string as roll type")
}
}
}
}
fn ksk_roll(rollop: RollOp<'_>, ks: &mut KeySet) -> Result<(), Error> {
match rollop {
RollOp::Start(old, new) => {
if let Some(rolltype) = ks.rollstates.keys().find(|k| {
**k != RollType::ZskRoll
&& **k != RollType::ZskDoubleSignatureRoll
}) {
if *rolltype == RollType::KskRoll {
return Err(Error::WrongStateForRollOperation);
} else {
return Err(Error::ConflictingRollInProgress);
}
}
ks.update_ksk(Mode::DryRun, old, new)?;
ks.update_ksk(Mode::ForReal, old, new)
.expect("Should have been checked by DryRun");
}
RollOp::Propagation1 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.present {
continue;
}
k.timestamps.visible = Some(now.clone());
}
}
RollOp::CacheExpire1(ttl) => {
for k in ks.keys.values() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.stale() {
continue;
}
let visible = k
.timestamps
.visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in &mut ks.keys.values_mut() {
if let KeyType::Ksk(ref mut keystate) = k.keytype {
if keystate.old && keystate.present {
keystate.at_parent = false;
}
if !keystate.old && keystate.present {
keystate.at_parent = true;
}
}
}
}
RollOp::Propagation2 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.at_parent {
continue;
}
k.timestamps.ds_visible = Some(now.clone());
}
}
RollOp::CacheExpire2(ttl) => {
for k in ks.keys.values() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.stale() {
continue;
}
let ds_visible = k
.timestamps
.ds_visible
.as_ref()
.expect("Should have been set in Propagation2");
let elapsed = ds_visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
let KeyType::Ksk(ref mut keystate) = k.keytype else {
continue;
};
if keystate.old && keystate.present {
keystate.signer = false;
keystate.present = false;
k.timestamps.withdrawn = Some(UnixTime::now());
}
}
}
RollOp::Done => (),
}
Ok(())
}
fn ksk_double_ds_roll(
rollop: RollOp<'_>,
ks: &mut KeySet,
) -> Result<(), Error> {
match rollop {
RollOp::Start(old, new) => {
if let Some(rolltype) = ks.rollstates.keys().find(|k| {
**k != RollType::ZskRoll
&& **k != RollType::ZskDoubleSignatureRoll
}) {
if *rolltype == RollType::KskDoubleDsRoll {
return Err(Error::WrongStateForRollOperation);
} else {
return Err(Error::ConflictingRollInProgress);
}
}
ks.update_ksk_double_ds(Mode::DryRun, old, new)?;
ks.update_ksk_double_ds(Mode::ForReal, old, new)
.expect("Should have been checked by DryRun");
}
RollOp::Propagation1 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.at_parent {
continue;
}
k.timestamps.ds_visible = Some(now.clone());
}
}
RollOp::CacheExpire1(ttl) => {
for k in ks.keys.values() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.at_parent {
continue;
}
let ds_visible = k
.timestamps
.ds_visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = ds_visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
let now = UnixTime::now();
for k in &mut ks.keys.values_mut() {
if let KeyType::Ksk(ref mut keystate) = k.keytype {
if keystate.old && keystate.present {
keystate.present = false;
keystate.signer = false;
}
if !keystate.old && keystate.at_parent {
keystate.present = true;
keystate.signer = true;
k.timestamps.published = Some(now.clone());
}
}
}
}
RollOp::Propagation2 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.present {
continue;
}
k.timestamps.visible = Some(now.clone());
}
}
RollOp::CacheExpire2(ttl) => {
for k in ks.keys.values() {
let KeyType::Ksk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.present {
continue;
}
let visible = k
.timestamps
.ds_visible
.as_ref()
.expect("Should have been set in Propagation2");
let elapsed = visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
let KeyType::Ksk(ref mut keystate) = k.keytype else {
continue;
};
if keystate.old && keystate.at_parent {
keystate.at_parent = false;
k.timestamps.withdrawn = Some(UnixTime::now());
}
}
}
RollOp::Done => (),
}
Ok(())
}
fn ksk_roll_actions(rollstate: RollState) -> Vec<Action> {
let mut actions = Vec::new();
match rollstate {
RollState::Propagation1 => {
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::ReportDnskeyPropagated);
}
RollState::CacheExpire1(_) => (),
RollState::Propagation2 => {
actions.push(Action::CreateCdsRrset);
actions.push(Action::UpdateDsRrset);
actions.push(Action::ReportDsPropagated);
}
RollState::CacheExpire2(_) => (),
RollState::Done => {
actions.push(Action::RemoveCdsRrset);
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::WaitDnskeyPropagated);
}
}
actions
}
fn ksk_double_ds_roll_actions(rollstate: RollState) -> Vec<Action> {
let mut actions = Vec::new();
match rollstate {
RollState::Propagation1 => {
actions.push(Action::CreateCdsRrset);
actions.push(Action::UpdateDsRrset);
actions.push(Action::ReportDsPropagated);
}
RollState::CacheExpire1(_) => (),
RollState::Propagation2 => {
actions.push(Action::RemoveCdsRrset);
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::ReportDnskeyPropagated);
}
RollState::CacheExpire2(_) => (),
RollState::Done => {
actions.push(Action::CreateCdsRrset);
actions.push(Action::UpdateDsRrset);
actions.push(Action::WaitDsPropagated);
} }
actions
}
fn zsk_roll(rollop: RollOp<'_>, ks: &mut KeySet) -> Result<(), Error> {
match rollop {
RollOp::Start(old, new) => {
if let Some(rolltype) = ks.rollstates.keys().find(|k| {
**k != RollType::KskRoll && **k != RollType::KskDoubleDsRoll
}) {
if *rolltype == RollType::ZskRoll {
return Err(Error::WrongStateForRollOperation);
} else {
return Err(Error::ConflictingRollInProgress);
}
}
ks.update_zsk(Mode::DryRun, old, new)?;
ks.update_zsk(Mode::ForReal, old, new)
.expect("Should have been checked with DryRun");
}
RollOp::Propagation1 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Zsk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.present {
continue;
}
k.timestamps.visible = Some(now.clone());
}
}
RollOp::CacheExpire1(ttl) => {
for k in ks.keys.values() {
let KeyType::Zsk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.present {
continue;
}
let visible = k
.timestamps
.visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
let KeyType::Zsk(ref mut keystate) = k.keytype else {
continue;
};
if !keystate.old && keystate.present {
keystate.signer = true;
}
if keystate.old {
keystate.signer = false;
}
}
}
RollOp::Propagation2 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Zsk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.signer {
continue;
}
k.timestamps.rrsig_visible = Some(now.clone());
}
}
RollOp::CacheExpire2(ttl) => {
for k in ks.keys.values() {
let KeyType::Zsk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.signer {
continue;
}
let rrsig_visible = k
.timestamps
.rrsig_visible
.as_ref()
.expect("Should have been set in Propagation2");
let elapsed = rrsig_visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
let KeyType::Zsk(ref mut keystate) = k.keytype else {
continue;
};
if keystate.old && !keystate.signer {
keystate.present = false;
k.timestamps.withdrawn = Some(UnixTime::now());
}
}
}
RollOp::Done => (),
}
Ok(())
}
fn zsk_double_signature_roll(
rollop: RollOp<'_>,
ks: &mut KeySet,
) -> Result<(), Error> {
match rollop {
RollOp::Start(old, new) => {
if let Some(rolltype) = ks.rollstates.keys().find(|k| {
**k != RollType::KskRoll && **k != RollType::KskDoubleDsRoll
}) {
if *rolltype == RollType::ZskDoubleSignatureRoll {
return Err(Error::WrongStateForRollOperation);
} else {
return Err(Error::ConflictingRollInProgress);
}
}
ks.update_zsk_double_signature(Mode::DryRun, old, new)?;
ks.update_zsk_double_signature(Mode::ForReal, old, new)
.expect("Should have been checked with DryRun");
}
RollOp::Propagation1 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Zsk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.present {
continue;
}
k.timestamps.visible = Some(now.clone());
k.timestamps.rrsig_visible = Some(now.clone());
}
}
RollOp::CacheExpire1(ttl) => {
for k in ks.keys.values() {
let KeyType::Zsk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.present {
continue;
}
let visible = k
.timestamps
.visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
let now = UnixTime::now();
for k in ks.keys.values_mut() {
let KeyType::Zsk(ref mut keystate) = k.keytype else {
continue;
};
if keystate.old {
keystate.present = false;
keystate.signer = false;
k.timestamps.withdrawn = Some(now.clone());
}
}
}
RollOp::Propagation2 => {
}
RollOp::CacheExpire2(ttl) => {
for k in ks.keys.values() {
let KeyType::Zsk(ref keystate) = k.keytype else {
continue;
};
if keystate.old || !keystate.signer {
continue;
}
let rrsig_visible = k
.timestamps
.rrsig_visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = rrsig_visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
}
RollOp::Done => (),
}
Ok(())
}
fn zsk_roll_actions(rollstate: RollState) -> Vec<Action> {
let mut actions = Vec::new();
match rollstate {
RollState::Propagation1 => {
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::ReportDnskeyPropagated);
}
RollState::CacheExpire1(_) => (),
RollState::Propagation2 => {
actions.push(Action::UpdateRrsig);
actions.push(Action::ReportRrsigPropagated);
}
RollState::CacheExpire2(_) => (),
RollState::Done => {
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::WaitDnskeyPropagated);
}
}
actions
}
fn zsk_double_signature_roll_actions(rollstate: RollState) -> Vec<Action> {
let mut actions = Vec::new();
match rollstate {
RollState::Propagation1 => {
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::UpdateRrsig);
actions.push(Action::ReportDnskeyPropagated);
actions.push(Action::ReportRrsigPropagated);
}
RollState::CacheExpire1(_) => (),
RollState::Propagation2 => {
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::UpdateRrsig);
actions.push(Action::ReportDnskeyPropagated);
actions.push(Action::ReportRrsigPropagated);
}
RollState::CacheExpire2(_) => (),
RollState::Done => (),
}
actions
}
fn csk_roll(rollop: RollOp<'_>, ks: &mut KeySet) -> Result<(), Error> {
match rollop {
RollOp::Start(old, new) => {
if let Some(rolltype) = ks.rollstates.keys().next() {
if *rolltype == RollType::CskRoll {
return Err(Error::WrongStateForRollOperation);
} else {
return Err(Error::ConflictingRollInProgress);
}
}
ks.update_csk(Mode::DryRun, old, new)?;
ks.update_csk(Mode::ForReal, old, new)
.expect("Should have been checked with DryRun");
}
RollOp::Propagation1 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
match &k.keytype {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Csk(keystate, _) => {
if keystate.old || !keystate.present {
continue;
}
k.timestamps.visible = Some(now.clone());
}
KeyType::Include(_) => (),
}
}
}
RollOp::CacheExpire1(ttl) => {
for k in ks.keys.values() {
let keystate = match &k.keytype {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Csk(keystate, _) => keystate,
KeyType::Include(_) => continue,
};
if keystate.old || !keystate.present {
continue;
}
let visible = k
.timestamps
.visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
match k.keytype {
KeyType::Ksk(ref mut keystate) => {
if keystate.old && keystate.present {
keystate.at_parent = false;
}
if !keystate.old && keystate.present {
keystate.at_parent = true;
}
}
KeyType::Zsk(ref mut keystate) => {
if !keystate.old && keystate.present {
keystate.signer = true;
}
if keystate.old {
keystate.signer = false;
}
}
KeyType::Csk(
ref mut ksk_keystate,
ref mut zsk_keystate,
) => {
if ksk_keystate.old && ksk_keystate.present {
ksk_keystate.at_parent = false;
}
if !ksk_keystate.old && ksk_keystate.present {
ksk_keystate.at_parent = true;
}
if !zsk_keystate.old && zsk_keystate.present {
zsk_keystate.signer = true;
}
if zsk_keystate.old {
zsk_keystate.signer = false;
}
}
_ => (),
}
}
}
RollOp::Propagation2 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
match &k.keytype {
KeyType::Ksk(keystate) | KeyType::Csk(keystate, _) => {
if keystate.old || !keystate.present {
continue;
}
k.timestamps.ds_visible = Some(now.clone());
}
KeyType::Zsk(_) | KeyType::Include(_) => (),
}
}
for k in ks.keys.values_mut() {
let keystate = match &k.keytype {
KeyType::Zsk(keystate) | KeyType::Csk(_, keystate) => {
keystate
}
KeyType::Ksk(_) | KeyType::Include(_) => continue,
};
if keystate.old || !keystate.signer {
continue;
}
k.timestamps.rrsig_visible = Some(now.clone());
}
}
RollOp::CacheExpire2(ttl) => {
for k in ks.keys.values() {
let keystate = match &k.keytype {
KeyType::Zsk(keystate) | KeyType::Csk(_, keystate) => {
keystate
}
KeyType::Ksk(_) | KeyType::Include(_) => continue,
};
if keystate.old || !keystate.signer {
continue;
}
let rrsig_visible = k
.timestamps
.rrsig_visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = rrsig_visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
match k.keytype {
KeyType::Ksk(ref mut keystate)
| KeyType::Csk(ref mut keystate, _) => {
if keystate.old && keystate.present {
keystate.signer = false;
keystate.present = false;
k.timestamps.withdrawn = Some(UnixTime::now());
}
}
KeyType::Zsk(_) | KeyType::Include(_) => (),
}
}
for k in ks.keys.values_mut() {
match k.keytype {
KeyType::Zsk(ref mut keystate)
| KeyType::Csk(_, ref mut keystate) => {
if keystate.old && !keystate.signer {
keystate.present = false;
k.timestamps.withdrawn = Some(UnixTime::now());
}
}
KeyType::Ksk(_) | KeyType::Include(_) => (),
}
}
}
RollOp::Done => (),
}
Ok(())
}
fn csk_roll_actions(rollstate: RollState) -> Vec<Action> {
let mut actions = Vec::new();
match rollstate {
RollState::Propagation1 => {
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::ReportDnskeyPropagated);
}
RollState::CacheExpire1(_) => (),
RollState::Propagation2 => {
actions.push(Action::CreateCdsRrset);
actions.push(Action::UpdateDsRrset);
actions.push(Action::UpdateRrsig);
actions.push(Action::ReportDsPropagated);
actions.push(Action::ReportRrsigPropagated);
}
RollState::CacheExpire2(_) => (),
RollState::Done => {
actions.push(Action::RemoveCdsRrset);
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::WaitDnskeyPropagated);
}
}
actions
}
fn algorithm_roll(rollop: RollOp<'_>, ks: &mut KeySet) -> Result<(), Error> {
match rollop {
RollOp::Start(old, new) => {
if let Some(rolltype) = ks.rollstates.keys().next() {
if *rolltype == RollType::AlgorithmRoll {
return Err(Error::WrongStateForRollOperation);
} else {
return Err(Error::ConflictingRollInProgress);
}
}
ks.update_algorithm(Mode::DryRun, old, new)?;
ks.update_algorithm(Mode::ForReal, old, new)
.expect("Should have been check with DryRun");
}
RollOp::Propagation1 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
match &mut k.keytype {
KeyType::Ksk(keystate) => {
if keystate.old || !keystate.present {
continue;
}
k.timestamps.visible = Some(now.clone());
}
KeyType::Zsk(keystate) | KeyType::Csk(keystate, _) => {
if keystate.old || !keystate.present {
continue;
}
k.timestamps.visible = Some(now.clone());
k.timestamps.rrsig_visible = Some(now.clone());
}
KeyType::Include(_) => (),
}
}
}
RollOp::CacheExpire1(ttl) => {
for k in ks.keys.values() {
let keystate = match &k.keytype {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Csk(keystate, _) => keystate,
KeyType::Include(_) => continue,
};
if keystate.old || !keystate.present {
continue;
}
let visible = k
.timestamps
.visible
.as_ref()
.expect("Should have been set in Propagation1");
let elapsed = visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
match k.keytype {
KeyType::Ksk(ref mut keystate)
| KeyType::Csk(ref mut keystate, _) => {
if keystate.old && keystate.present {
keystate.at_parent = false;
}
if !keystate.old && keystate.present {
keystate.at_parent = true;
}
}
KeyType::Zsk(_) | KeyType::Include(_) => (),
}
}
}
RollOp::Propagation2 => {
let now = UnixTime::now();
for k in ks.keys.values_mut() {
match &k.keytype {
KeyType::Ksk(keystate) | KeyType::Csk(keystate, _) => {
if keystate.old || !keystate.present {
continue;
}
k.timestamps.ds_visible = Some(now.clone());
}
KeyType::Zsk(_) | KeyType::Include(_) => (),
}
}
}
RollOp::CacheExpire2(ttl) => {
for k in ks.keys.values() {
let keystate = match &k.keytype {
KeyType::Ksk(keystate) | KeyType::Csk(keystate, _) => {
keystate
}
KeyType::Zsk(_) | KeyType::Include(_) => continue,
};
if keystate.old || !keystate.signer {
continue;
}
let ds_visible = k
.timestamps
.ds_visible
.as_ref()
.expect("Should have been set in Propagation2");
let elapsed = ds_visible.elapsed();
let ttl = Duration::from_secs(ttl.into());
if elapsed < ttl {
return Err(Error::Wait(ttl - elapsed));
}
}
for k in ks.keys.values_mut() {
match k.keytype {
KeyType::Ksk(ref mut keystate)
| KeyType::Zsk(ref mut keystate) => {
if keystate.old && keystate.present {
keystate.signer = false;
keystate.present = false;
k.timestamps.withdrawn = Some(UnixTime::now());
}
}
KeyType::Csk(
ref mut ksk_keystate,
ref mut zsk_keystate,
) => {
if ksk_keystate.old && ksk_keystate.present {
ksk_keystate.signer = false;
ksk_keystate.present = false;
zsk_keystate.signer = false;
zsk_keystate.present = false;
k.timestamps.withdrawn = Some(UnixTime::now());
}
}
KeyType::Include(_) => (),
}
}
}
RollOp::Done => (),
}
Ok(())
}
fn algorithm_roll_actions(rollstate: RollState) -> Vec<Action> {
let mut actions = Vec::new();
match rollstate {
RollState::Propagation1 => {
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::UpdateRrsig);
actions.push(Action::ReportDnskeyPropagated);
actions.push(Action::ReportRrsigPropagated);
}
RollState::CacheExpire1(_) => (),
RollState::Propagation2 => {
actions.push(Action::CreateCdsRrset);
actions.push(Action::UpdateDsRrset);
actions.push(Action::ReportDsPropagated);
}
RollState::CacheExpire2(_) => (),
RollState::Done => {
actions.push(Action::RemoveCdsRrset);
actions.push(Action::UpdateDnskeyRrset);
actions.push(Action::UpdateRrsig);
actions.push(Action::WaitDnskeyPropagated);
actions.push(Action::WaitRrsigPropagated);
}
}
actions
}
#[cfg(test)]
mod tests {
use crate::base::Name;
use crate::dnssec::sign::keys::keyset::SecurityAlgorithm;
use crate::dnssec::sign::keys::keyset::{
Action, Available, KeySet, KeyType, RollType, UnixTime,
};
use crate::std::string::ToString;
use mock_instant::global::MockClock;
use std::str::FromStr;
use std::string::String;
use std::time::Duration;
use std::vec::Vec;
#[test]
fn test_name() {
let ks = KeySet::new(Name::from_str("example.com").unwrap());
assert_eq!(ks.name().to_string(), "example.com");
}
#[test]
fn test_rolls() {
let mut ks = KeySet::new(Name::from_str("example.com").unwrap());
ks.add_key_ksk(
"first KSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
0,
UnixTime::now(),
Available::Available,
)
.unwrap();
ks.add_key_zsk(
"first ZSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
1,
UnixTime::now(),
Available::Available,
)
.unwrap();
let actions = ks
.start_roll(
RollType::AlgorithmRoll,
&[],
&["first KSK", "first ZSK"],
)
.unwrap();
assert_eq!(
actions,
[
Action::UpdateDnskeyRrset,
Action::UpdateRrsig,
Action::ReportDnskeyPropagated,
Action::ReportRrsigPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "first ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
assert_eq!(zone_sigs(&ks), ["first ZSK"]);
assert_eq!(ds_keys(&ks), Vec::<String>::new());
let actions = ks
.propagation1_complete(RollType::AlgorithmRoll, 3600)
.unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired1(RollType::AlgorithmRoll).unwrap();
assert_eq!(
actions,
[
Action::CreateCdsRrset,
Action::UpdateDsRrset,
Action::ReportDsPropagated,
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "first ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
assert_eq!(zone_sigs(&ks), ["first ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions = ks
.propagation2_complete(RollType::AlgorithmRoll, 3600)
.unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired2(RollType::AlgorithmRoll).unwrap();
assert_eq!(
actions,
[
Action::RemoveCdsRrset,
Action::UpdateDnskeyRrset,
Action::UpdateRrsig,
Action::WaitDnskeyPropagated,
Action::WaitRrsigPropagated,
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "first ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
assert_eq!(zone_sigs(&ks), ["first ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions = ks.roll_done(RollType::AlgorithmRoll).unwrap();
assert_eq!(actions, []);
ks.add_key_ksk(
"second KSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
2,
UnixTime::now(),
Available::Available,
)
.unwrap();
ks.add_key_zsk(
"second ZSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
3,
UnixTime::now(),
Available::Available,
)
.unwrap();
println!("line {} = {:?}", line!(), ks.keys().get("second ZSK"));
let actions = ks
.start_roll(RollType::ZskRoll, &["first ZSK"], &["second ZSK"])
.unwrap();
println!("line {} = {:?}", line!(), ks.keys().get("second ZSK"));
assert_eq!(
actions,
[Action::UpdateDnskeyRrset, Action::ReportDnskeyPropagated]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "first ZSK", "second ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
println!("keys = {:?}", ks.keys());
assert_eq!(zone_sigs(&ks), ["first ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions =
ks.propagation1_complete(RollType::ZskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired1(RollType::ZskRoll).unwrap();
assert_eq!(
actions,
[Action::UpdateRrsig, Action::ReportRrsigPropagated]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "first ZSK", "second ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
assert_eq!(zone_sigs(&ks), ["second ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions =
ks.propagation2_complete(RollType::ZskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired2(RollType::ZskRoll).unwrap();
assert_eq!(
actions,
[Action::UpdateDnskeyRrset, Action::WaitDnskeyPropagated]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "second ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
assert_eq!(zone_sigs(&ks), ["second ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions = ks.roll_done(RollType::ZskRoll).unwrap();
assert_eq!(actions, []);
ks.delete_key("first ZSK").unwrap();
ks.add_key_zsk(
"third ZSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
4,
UnixTime::now(),
Available::Available,
)
.unwrap();
let actions = ks
.start_roll(
RollType::ZskDoubleSignatureRoll,
&["second ZSK"],
&["third ZSK"],
)
.unwrap();
assert_eq!(
actions,
[
Action::UpdateDnskeyRrset,
Action::UpdateRrsig,
Action::ReportDnskeyPropagated,
Action::ReportRrsigPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "second ZSK", "third ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
let mut zs = zone_sigs(&ks);
zs.sort();
assert_eq!(zs, ["second ZSK", "third ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions = ks
.propagation1_complete(RollType::ZskDoubleSignatureRoll, 3600)
.unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions =
ks.cache_expired1(RollType::ZskDoubleSignatureRoll).unwrap();
assert_eq!(
actions,
[
Action::UpdateDnskeyRrset,
Action::UpdateRrsig,
Action::ReportDnskeyPropagated,
Action::ReportRrsigPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "third ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions = ks
.propagation2_complete(RollType::ZskDoubleSignatureRoll, 3600)
.unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions =
ks.cache_expired2(RollType::ZskDoubleSignatureRoll).unwrap();
assert_eq!(actions, []);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "third ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["first KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions = ks.roll_done(RollType::ZskDoubleSignatureRoll).unwrap();
assert_eq!(actions, []);
ks.delete_key("second ZSK").unwrap();
let actions = ks
.start_roll(RollType::KskRoll, &["first KSK"], &["second KSK"])
.unwrap();
assert_eq!(
actions,
[Action::UpdateDnskeyRrset, Action::ReportDnskeyPropagated]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "second KSK", "third ZSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["first KSK", "second KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
assert_eq!(ds_keys(&ks), ["first KSK"]);
let actions =
ks.propagation1_complete(RollType::KskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired1(RollType::KskRoll).unwrap();
assert_eq!(
actions,
[
Action::CreateCdsRrset,
Action::UpdateDsRrset,
Action::ReportDsPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first KSK", "second KSK", "third ZSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["first KSK", "second KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
assert_eq!(ds_keys(&ks), ["second KSK"]);
let actions =
ks.propagation2_complete(RollType::KskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired2(RollType::KskRoll).unwrap();
assert_eq!(
actions,
[
Action::RemoveCdsRrset,
Action::UpdateDnskeyRrset,
Action::WaitDnskeyPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["second KSK", "third ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["second KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
assert_eq!(ds_keys(&ks), ["second KSK"]);
let actions = ks.roll_done(RollType::KskRoll).unwrap();
assert_eq!(actions, []);
ks.delete_key("first KSK").unwrap();
ks.add_key_ksk(
"third KSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
5,
UnixTime::now(),
Available::Available,
)
.unwrap();
let actions = ks
.start_roll(
RollType::KskDoubleDsRoll,
&["second KSK"],
&["third KSK"],
)
.unwrap();
assert_eq!(
actions,
[
Action::CreateCdsRrset,
Action::UpdateDsRrset,
Action::ReportDsPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["second KSK", "third ZSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["second KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
let mut dsks = ds_keys(&ks);
dsks.sort();
assert_eq!(dsks, ["second KSK", "third KSK"]);
let actions = ks
.propagation1_complete(RollType::KskDoubleDsRoll, 3600)
.unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired1(RollType::KskDoubleDsRoll).unwrap();
assert_eq!(
actions,
[
Action::RemoveCdsRrset,
Action::UpdateDnskeyRrset,
Action::ReportDnskeyPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["third KSK", "third ZSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["third KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
let mut dsks = ds_keys(&ks);
dsks.sort();
assert_eq!(dsks, ["second KSK", "third KSK"]);
let actions = ks
.propagation2_complete(RollType::KskDoubleDsRoll, 3600)
.unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired2(RollType::KskDoubleDsRoll).unwrap();
assert_eq!(
actions,
[
Action::CreateCdsRrset,
Action::UpdateDsRrset,
Action::WaitDsPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["third KSK", "third ZSK"]);
assert_eq!(dnskey_sigs(&ks), ["third KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
assert_eq!(ds_keys(&ks), ["third KSK"]);
let actions = ks.roll_done(RollType::KskDoubleDsRoll).unwrap();
assert_eq!(actions, []);
ks.delete_key("second KSK").unwrap();
ks.add_key_csk(
"first CSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
0,
UnixTime::now(),
Available::Available,
)
.unwrap();
let actions = ks
.start_roll(
RollType::CskRoll,
&["third KSK", "third ZSK"],
&["first CSK"],
)
.unwrap();
assert_eq!(
actions,
[Action::UpdateDnskeyRrset, Action::ReportDnskeyPropagated]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first CSK", "third KSK", "third ZSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["first CSK", "third KSK"]);
assert_eq!(zone_sigs(&ks), ["third ZSK"]);
assert_eq!(ds_keys(&ks), ["third KSK"]);
let actions =
ks.propagation1_complete(RollType::CskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired1(RollType::CskRoll).unwrap();
assert_eq!(
actions,
[
Action::CreateCdsRrset,
Action::UpdateDsRrset,
Action::UpdateRrsig,
Action::ReportDsPropagated,
Action::ReportRrsigPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first CSK", "third KSK", "third ZSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["first CSK", "third KSK"]);
assert_eq!(zone_sigs(&ks), ["first CSK"]);
assert_eq!(ds_keys(&ks), ["first CSK"]);
let actions =
ks.propagation2_complete(RollType::CskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired2(RollType::CskRoll).unwrap();
assert_eq!(
actions,
[
Action::RemoveCdsRrset,
Action::UpdateDnskeyRrset,
Action::WaitDnskeyPropagated
]
);
assert_eq!(dnskey(&ks), ["first CSK"]);
assert_eq!(dnskey_sigs(&ks), ["first CSK"]);
assert_eq!(zone_sigs(&ks), ["first CSK"]);
assert_eq!(ds_keys(&ks), ["first CSK"]);
let actions = ks.roll_done(RollType::CskRoll).unwrap();
assert_eq!(actions, []);
ks.delete_key("third KSK").unwrap();
ks.delete_key("third ZSK").unwrap();
ks.add_key_csk(
"second CSK".to_string(),
None,
SecurityAlgorithm::ECDSAP256SHA256,
4,
UnixTime::now(),
Available::Available,
)
.unwrap();
let actions = ks
.start_roll(RollType::CskRoll, &["first CSK"], &["second CSK"])
.unwrap();
assert_eq!(
actions,
[Action::UpdateDnskeyRrset, Action::ReportDnskeyPropagated]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first CSK", "second CSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["first CSK", "second CSK"]);
assert_eq!(zone_sigs(&ks), ["first CSK"]);
assert_eq!(ds_keys(&ks), ["first CSK"]);
let actions =
ks.propagation1_complete(RollType::CskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
println!("CSK roll cache expired1");
let actions = ks.cache_expired1(RollType::CskRoll).unwrap();
assert_eq!(
actions,
[
Action::CreateCdsRrset,
Action::UpdateDsRrset,
Action::UpdateRrsig,
Action::ReportDsPropagated,
Action::ReportRrsigPropagated
]
);
let mut dk = dnskey(&ks);
dk.sort();
assert_eq!(dk, ["first CSK", "second CSK"]);
let mut dks = dnskey_sigs(&ks);
dks.sort();
assert_eq!(dks, ["first CSK", "second CSK"]);
assert_eq!(zone_sigs(&ks), ["second CSK"]);
assert_eq!(ds_keys(&ks), ["second CSK"]);
let actions =
ks.propagation2_complete(RollType::CskRoll, 3600).unwrap();
assert_eq!(actions, []);
MockClock::advance_system_time(Duration::from_secs(3600));
let actions = ks.cache_expired2(RollType::CskRoll).unwrap();
assert_eq!(
actions,
[
Action::RemoveCdsRrset,
Action::UpdateDnskeyRrset,
Action::WaitDnskeyPropagated
]
);
assert_eq!(dnskey(&ks), ["second CSK"]);
assert_eq!(dnskey_sigs(&ks), ["second CSK"]);
assert_eq!(zone_sigs(&ks), ["second CSK"]);
assert_eq!(ds_keys(&ks), ["second CSK"]);
let actions = ks.roll_done(RollType::CskRoll).unwrap();
assert_eq!(actions, []);
ks.delete_key("first CSK").unwrap();
}
fn dnskey(ks: &KeySet) -> Vec<String> {
ks.keys()
.iter()
.filter(|(_, k)| {
let status = match k.keytype() {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Csk(keystate, _)
| KeyType::Include(keystate) => keystate,
};
status.present()
})
.map(|(pr, _)| pr.to_string())
.collect()
}
fn dnskey_sigs(ks: &KeySet) -> Vec<String> {
let keys = ks.keys();
let mut vec = Vec::new();
for (pubref, key) in keys {
match key.keytype() {
KeyType::Ksk(keystate) | KeyType::Csk(keystate, _) => {
if keystate.signer() {
vec.push(pubref.to_string());
}
}
KeyType::Zsk(_) | KeyType::Include(_) => (),
}
}
vec
}
fn zone_sigs(ks: &KeySet) -> Vec<String> {
let keys = ks.keys();
let mut vec = Vec::new();
for (pubref, key) in keys {
match key.keytype() {
KeyType::Zsk(keystate) | KeyType::Csk(_, keystate) => {
if keystate.signer() {
vec.push(pubref.to_string());
}
}
KeyType::Ksk(_) | KeyType::Include(_) => (),
}
}
vec
}
fn ds_keys(ks: &KeySet) -> Vec<String> {
let keys = ks.keys();
let mut vec = Vec::new();
for (pubref, key) in keys {
let status = match key.keytype() {
KeyType::Ksk(keystate)
| KeyType::Zsk(keystate)
| KeyType::Csk(keystate, _)
| KeyType::Include(keystate) => keystate,
};
if status.at_parent() {
vec.push(pubref.to_string());
}
}
vec
}
}