Store key references are file URLs.

This commit is contained in:
Philip Homburg
2025-06-17 09:46:20 +02:00
parent 174f31efb5
commit 2129fc2b36
3 changed files with 464 additions and 99 deletions
Generated
+277
View File
@@ -312,6 +312,17 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "dnst"
version = "0.1.1-dev"
@@ -336,6 +347,7 @@ dependencies = [
"tokio",
"tracing",
"tracing-subscriber",
"url",
]
[[package]]
@@ -438,6 +450,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
[[package]]
name = "futures-core"
version = "0.3.31"
@@ -557,6 +578,113 @@ dependencies = [
"cc",
]
[[package]]
name = "icu_collections"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
dependencies = [
"displaydoc",
"potential_utf",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
dependencies = [
"displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
[[package]]
name = "icu_properties"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"potential_utf",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
[[package]]
name = "icu_provider"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
dependencies = [
"displaydoc",
"icu_locale_core",
"stable_deref_trait",
"tinystr",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]]
name = "idna"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
@@ -627,6 +755,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "litemap"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]]
name = "lock_api"
version = "0.4.13"
@@ -843,6 +977,12 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pin-project-lite"
version = "0.2.16"
@@ -876,6 +1016,15 @@ dependencies = [
"portable-atomic",
]
[[package]]
name = "potential_utf"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
dependencies = [
"zerovec",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -1187,6 +1336,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "strsim"
version = "0.11.1"
@@ -1204,6 +1359,17 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tagptr"
version = "0.2.0"
@@ -1290,6 +1456,16 @@ dependencies = [
"time-core",
]
[[package]]
name = "tinystr"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "tokio"
version = "1.45.1"
@@ -1408,6 +1584,23 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
@@ -1734,12 +1927,42 @@ dependencies = [
"bitflags",
]
[[package]]
name = "writeable"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "yoke"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
dependencies = [
"serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerocopy"
version = "0.8.25"
@@ -1760,8 +1983,62 @@ dependencies = [
"syn",
]
[[package]]
name = "zerofrom"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[package]]
name = "zerotrie"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
+1
View File
@@ -56,6 +56,7 @@ serde_json = "1.0.137"
serde = "1.0.217"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
url = "2.5.4"
[dev-dependencies]
const_format = " 0.2.33"
+186 -99
View File
@@ -24,8 +24,9 @@ use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::fs::{remove_file, File};
use std::io::Write;
use std::path::PathBuf;
use std::path::{absolute, Path, PathBuf};
use std::time::Duration;
use url::Url;
const MAX_KEY_TAG_TRIES: u8 = 10;
@@ -68,9 +69,15 @@ impl Keyset {
let domainname = self
.domain_name
.ok_or::<Error>("domain name option expected\n".into())?;
let state_file = self
.keyset_state
.ok_or::<Error>("state file option expected\n".into())?;
let state_file = absolute(&state_file).map_err::<Error, _>(|e| {
format!("unable to make {} absolute: {}", state_file.display(), e).into()
})?;
let keys_dir = make_parent_dir(state_file.clone());
let ks = KeySet::new(domainname);
let kss = KeySetState {
keyset: ks,
@@ -83,6 +90,7 @@ impl Keyset {
const FOUR_WEEKS: u64 = 2419200;
let ksc = KeySetConfig {
state_file: state_file.clone(),
keys_dir,
use_csk: false,
ksk_generate_params: KeyParameters::RsaSha256(2048),
zsk_generate_params: KeyParameters::RsaSha256(2048),
@@ -135,12 +143,13 @@ impl Keyset {
ksc.csk_generate_params.to_generate_params(),
true,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
kss.keyset
.add_key_csk(
csk_pub_name.clone(),
Some(csk_priv_name),
csk_pub_name.to_string(),
Some(csk_priv_name.to_string()),
algorithm,
key_tag,
UnixTime::now(),
@@ -148,43 +157,45 @@ impl Keyset {
.expect("should not happen");
kss.keyset
.start_roll(RollType::AlgorithmRoll, &[], &[&csk_pub_name])
.start_roll(RollType::AlgorithmRoll, &[], &[&csk_pub_name.as_str()])
.expect("should not happen")
} else {
let (ksk_pub_name, ksk_priv_name, algorithm, key_tag) = new_keys(
let (ksk_pub_url, ksk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.ksk_generate_params.to_generate_params(),
true,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
kss.keyset
.add_key_ksk(
ksk_pub_name.clone(),
Some(ksk_priv_name),
ksk_pub_url.to_string(),
Some(ksk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.expect("should not happen");
let (zsk_pub_name, zsk_priv_name, algorithm, key_tag) = new_keys(
let (zsk_pub_url, zsk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.zsk_generate_params.to_generate_params(),
false,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
kss.keyset
.add_key_zsk(
zsk_pub_name.clone(),
Some(zsk_priv_name),
zsk_pub_url.to_string(),
Some(zsk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.expect("should not happen");
let new = [ksk_pub_name.as_ref(), zsk_pub_name.as_ref()];
let new = [ksk_pub_url.as_ref(), zsk_pub_url.as_ref()];
kss.keyset
.start_roll(RollType::AlgorithmRoll, &[], &new)
.expect("should not happen")
@@ -237,26 +248,27 @@ impl Keyset {
// Collect algorithms. Maybe this needs to be in the library.
// Create a new KSK
let (ksk_pub_name, ksk_priv_name, algorithm, key_tag) = new_keys(
let (ksk_pub_url, ksk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.ksk_generate_params.to_generate_params(),
true,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
kss.keyset
.add_key_ksk(
ksk_pub_name.clone(),
Some(ksk_priv_name.clone()),
ksk_pub_url.to_string(),
Some(ksk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add KSK {ksk_pub_name}: {e}\n").into()
format!("unable to add KSK {ksk_pub_url}: {e}\n").into()
})?;
let new = [ksk_pub_name.as_ref()];
let new = [ksk_pub_url.as_ref()];
// Start the key roll
let actions = match kss
@@ -267,12 +279,23 @@ impl Keyset {
Ok(actions) => actions,
Err(e) => {
// Remove the key files we just created.
remove_file(ksk_priv_name.clone()).map_err::<Error, _>(|e| {
format!("unable to remove private key file {ksk_priv_name}: {e}\n").into()
})?;
remove_file(ksk_pub_name.clone()).map_err::<Error, _>(|e| {
format!("unable to remove public key file {ksk_pub_name}: {e}\n").into()
})?;
if ksk_priv_url.scheme() == "file" {
remove_file(ksk_priv_url.path()).map_err::<Error, _>(|e| {
format!("unable to remove private key file {ksk_priv_url}: {e}\n")
.into()
})?;
} else {
panic!("unsupported URL scheme in {ksk_priv_url}");
}
if ksk_pub_url.scheme() == "file" {
remove_file(ksk_pub_url.path()).map_err::<Error, _>(|e| {
format!("unable to remove public key file {ksk_pub_url}: {e}\n").into()
})?;
} else {
panic!("unsupported URL scheme in {ksk_pub_url}");
}
return Err(e);
}
};
@@ -320,26 +343,27 @@ impl Keyset {
// Collect algorithms. Maybe this needs to be in the library.
// Create a new ZSK
let (zsk_pub_name, zsk_priv_name, algorithm, key_tag) = new_keys(
let (zsk_pub_url, zsk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.zsk_generate_params.to_generate_params(),
false,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
kss.keyset
.add_key_zsk(
zsk_pub_name.clone(),
Some(zsk_priv_name.clone()),
zsk_pub_url.to_string(),
Some(zsk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add ZSK {zsk_pub_name}: {e}\n").into()
format!("unable to add ZSK {zsk_pub_url}: {e}\n").into()
})?;
let new = [zsk_pub_name.as_ref()];
let new = [zsk_pub_url.as_ref()];
// Start the key roll
let actions = match kss
@@ -350,12 +374,21 @@ impl Keyset {
Ok(actions) => actions,
Err(e) => {
// Remove the key files we just created.
remove_file(zsk_priv_name.clone()).map_err::<Error, _>(|e| {
format!("unable to remove private key file {zsk_priv_name}: {e}\n").into()
})?;
remove_file(zsk_pub_name.clone()).map_err::<Error, _>(|e| {
format!("unable to remove public key file {zsk_pub_name}: {e}\n").into()
})?;
if zsk_priv_url.scheme() == "file" {
remove_file(zsk_priv_url.path()).map_err::<Error, _>(|e| {
format!("unable to remove private key file {zsk_priv_url}: {e}\n")
.into()
})?;
} else {
panic!("unsupported URL scheme in {zsk_priv_url}");
}
if zsk_pub_url.scheme() == "file" {
remove_file(zsk_pub_url.path()).map_err::<Error, _>(|e| {
format!("unable to remove public key file {zsk_pub_url}: {e}\n").into()
})?;
} else {
panic!("unsupported URL scheme in {zsk_pub_url}");
}
return Err(e);
}
};
@@ -388,82 +421,85 @@ impl Keyset {
// Collect algorithms. Maybe this needs to be in the library.
let (new_stored, new_files) = if ksc.use_csk {
let mut new_files = Vec::new();
let (new_stored, new_urls) = if ksc.use_csk {
let mut new_urls = Vec::new();
// Create a new CSK
let (csk_pub_name, csk_priv_name, algorithm, key_tag) = new_keys(
let (csk_pub_url, csk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.csk_generate_params.to_generate_params(),
true,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
new_files.push(csk_priv_name.clone());
new_files.push(csk_pub_name.clone());
new_urls.push(csk_priv_url.clone());
new_urls.push(csk_pub_url.clone());
kss.keyset
.add_key_csk(
csk_pub_name.clone(),
Some(csk_priv_name.clone()),
csk_pub_url.to_string(),
Some(csk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add CSK {csk_pub_name}: {e}\n").into()
format!("unable to add CSK {csk_pub_url}: {e}\n").into()
})?;
let new = vec![csk_pub_name];
(new, new_files)
let new = vec![csk_pub_url];
(new, new_urls)
} else {
let mut new_files = Vec::new();
let mut new_urls = Vec::new();
// Create a new KSK
let (ksk_pub_name, ksk_priv_name, algorithm, key_tag) = new_keys(
let (ksk_pub_url, ksk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.ksk_generate_params.to_generate_params(),
true,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
new_files.push(ksk_priv_name.clone());
new_files.push(ksk_pub_name.clone());
new_urls.push(ksk_priv_url.clone());
new_urls.push(ksk_pub_url.clone());
kss.keyset
.add_key_ksk(
ksk_pub_name.clone(),
Some(ksk_priv_name.clone()),
ksk_pub_url.to_string(),
Some(ksk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add KSK {ksk_pub_name}: {e}\n").into()
format!("unable to add KSK {ksk_pub_url}: {e}\n").into()
})?;
// Create a new ZSK
let (zsk_pub_name, zsk_priv_name, algorithm, key_tag) = new_keys(
let (zsk_pub_url, zsk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.zsk_generate_params.to_generate_params(),
false,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
new_files.push(zsk_priv_name.clone());
new_files.push(zsk_pub_name.clone());
new_urls.push(zsk_priv_url.clone());
new_urls.push(zsk_pub_url.clone());
kss.keyset
.add_key_zsk(
zsk_pub_name.clone(),
Some(zsk_priv_name.clone()),
zsk_pub_url.to_string(),
Some(zsk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add ZSK {zsk_pub_name}: {e}\n").into()
format!("unable to add ZSK {zsk_pub_url}: {e}\n").into()
})?;
let new = vec![ksk_pub_name, zsk_pub_name];
(new, new_files)
let new = vec![ksk_pub_url, zsk_pub_url];
(new, new_urls)
};
let new: Vec<_> = new_stored.iter().map(|v| v.as_ref()).collect();
@@ -477,10 +513,14 @@ impl Keyset {
Ok(actions) => actions,
Err(e) => {
// Remove the key files we just created.
for f in new_files {
remove_file(&f).map_err::<Error, _>(|e| {
format!("unable to private key file {f}: {e}\n").into()
})?;
for u in new_urls {
if u.scheme() == "file" {
remove_file(u.path()).map_err::<Error, _>(|e| {
format!("unable to remove private key file {u}: {e}\n").into()
})?;
} else {
panic!("unsupported URL scheme in {u}");
}
}
return Err(e);
}
@@ -513,82 +553,85 @@ impl Keyset {
.collect();
let old: Vec<_> = old_stored.iter().map(|name| name.as_ref()).collect();
let (new_stored, new_files) = if ksc.use_csk {
let mut new_files = Vec::new();
let (new_stored, new_urls) = if ksc.use_csk {
let mut new_urls = Vec::new();
// Create a new CSK
let (csk_pub_name, csk_priv_name, algorithm, key_tag) = new_keys(
let (csk_pub_url, csk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.csk_generate_params.to_generate_params(),
true,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
new_files.push(csk_priv_name.clone());
new_files.push(csk_pub_name.clone());
new_urls.push(csk_priv_url.clone());
new_urls.push(csk_pub_url.clone());
kss.keyset
.add_key_csk(
csk_pub_name.clone(),
Some(csk_priv_name.clone()),
csk_pub_url.to_string(),
Some(csk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add CSK {csk_pub_name}: {e}\n").into()
format!("unable to add CSK {csk_pub_url}: {e}\n").into()
})?;
let new = vec![csk_pub_name];
(new, new_files)
let new = vec![csk_pub_url];
(new, new_urls)
} else {
let mut new_files = Vec::new();
let mut new_urls = Vec::new();
// Create a new KSK
let (ksk_pub_name, ksk_priv_name, algorithm, key_tag) = new_keys(
let (ksk_pub_url, ksk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.ksk_generate_params.to_generate_params(),
true,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
new_files.push(ksk_priv_name.clone());
new_files.push(ksk_pub_name.clone());
new_urls.push(ksk_priv_url.clone());
new_urls.push(ksk_pub_url.clone());
kss.keyset
.add_key_ksk(
ksk_pub_name.clone(),
Some(ksk_priv_name.clone()),
ksk_pub_url.to_string(),
Some(ksk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add KSK {ksk_pub_name}: {e}\n").into()
format!("unable to add KSK {ksk_pub_url}: {e}\n").into()
})?;
// Create a new ZSK
let (zsk_pub_name, zsk_priv_name, algorithm, key_tag) = new_keys(
let (zsk_pub_url, zsk_priv_url, algorithm, key_tag) = new_keys(
kss.keyset.name(),
ksc.zsk_generate_params.to_generate_params(),
false,
kss.keyset.keys(),
&ksc.keys_dir,
env,
)?;
new_files.push(zsk_priv_name.clone());
new_files.push(zsk_pub_name.clone());
new_urls.push(zsk_priv_url.clone());
new_urls.push(zsk_pub_url.clone());
kss.keyset
.add_key_zsk(
zsk_pub_name.clone(),
Some(zsk_priv_name.clone()),
zsk_pub_url.to_string(),
Some(zsk_priv_url.to_string()),
algorithm,
key_tag,
UnixTime::now(),
)
.map_err::<Error, _>(|e| {
format!("unable to add ZSK {zsk_pub_name}: {e}\n").into()
format!("unable to add ZSK {zsk_pub_url}: {e}\n").into()
})?;
let new = vec![ksk_pub_name, zsk_pub_name];
(new, new_files)
let new = vec![ksk_pub_url, zsk_pub_url];
(new, new_urls)
};
let new: Vec<_> = new_stored.iter().map(|v| v.as_ref()).collect();
@@ -602,10 +645,14 @@ impl Keyset {
Ok(actions) => actions,
Err(e) => {
// Remove the key files we just created.
for f in new_files {
remove_file(&f).map_err::<Error, _>(|e| {
format!("unable to private key file {f}: {e}\n").into()
})?;
for u in new_urls {
if u.scheme() == "file" {
remove_file(u.path()).map_err::<Error, _>(|e| {
format!("unable to private key file {u}: {e}\n").into()
})?;
} else {
panic!("unsupported scheme in {u}");
}
}
return Err(e);
}
@@ -1002,6 +1049,7 @@ impl Keyset {
#[derive(Deserialize, Serialize)]
struct KeySetConfig {
state_file: PathBuf,
keys_dir: PathBuf,
use_csk: bool,
@@ -1153,8 +1201,9 @@ fn new_keys(
algorithm: GenerateParams,
make_ksk: bool,
keys: &HashMap<String, Key>,
keys_dir: &Path,
env: &impl Env,
) -> Result<(String, String, SecurityAlgorithm, u16), Error> {
) -> Result<(Url, Url, SecurityAlgorithm, u16), Error> {
// Generate the key.
// TODO: Attempt repeated generation to avoid key tag collisions.
// TODO: Add a high-level operation in 'domain' to select flags?
@@ -1186,8 +1235,10 @@ fn new_keys(
key_tag
);
let secret_key_path = format!("{base}.private");
let public_key_path = format!("{base}.key");
let mut secret_key_path = keys_dir.to_path_buf();
secret_key_path.push(Path::new(&format!("{base}.private")));
let mut public_key_path = keys_dir.to_path_buf();
public_key_path.push(Path::new(&format!("{base}.key")));
let mut secret_key_file = util::create_new_file(&env, &secret_key_path)?;
let mut public_key_file = util::create_new_file(&env, &public_key_path)?;
@@ -1203,7 +1254,21 @@ fn new_keys(
.write_all(public_key.as_bytes())
.map_err(|err| format!("error while writing public key file '{base}.key': {err}"))?;
Ok((public_key_path, secret_key_path, algorithm, key_tag))
let secret_key_path = secret_key_path.to_str().ok_or::<Error>(
format!("path {} needs to be valid UTF-8", secret_key_path.display()).into(),
)?;
let secret_key_url = "file://".to_owned() + secret_key_path;
let public_key_path = public_key_path.to_str().ok_or::<Error>(
format!("path {} needs to be valid UTF-8", public_key_path.display()).into(),
)?;
let public_key_url = "file://".to_owned() + public_key_path;
let secret_key_url = Url::parse(&secret_key_url)
.map_err::<Error, _>(|e| format!("unable to parse {secret_key_url} as URL: {e}").into())?;
let public_key_url = Url::parse(&public_key_url)
.map_err::<Error, _>(|e| format!("unable to parse {public_key_url} as URL: {e}").into())?;
Ok((public_key_url, secret_key_url, algorithm, key_tag))
}
fn update_dnskey_rrset(
@@ -1220,9 +1285,17 @@ fn update_dnskey_rrset(
KeyType::Include(key_state) => key_state.present(),
};
let pub_url = Url::parse(k).expect("valid URL expected");
if present {
let mut file = File::open(env.in_cwd(&k))?;
let zonefile = domain::zonefile::inplace::Zonefile::load(&mut file)?;
dbg!("before open");
let zonefile = if pub_url.scheme() == "file" {
let mut file = File::open(env.in_cwd(&pub_url.path().to_string()))?;
domain::zonefile::inplace::Zonefile::load(&mut file)?
} else {
panic!("unsupported scheme in {pub_url}");
};
dbg!("after open");
for entry in zonefile {
let entry = entry
.map_err::<Error, _>(|e| format!("bad entry in key file {k}: {e}\n").into())?;
@@ -1269,12 +1342,22 @@ fn update_dnskey_rrset(
if dnskey_signer {
let privref = v.privref().ok_or("missing private key")?;
let private_data = std::fs::read_to_string(privref)?;
let priv_url = Url::parse(privref).expect("valid URL expected");
let private_data = if priv_url.scheme() == "file" {
std::fs::read_to_string(priv_url.path())?
} else {
panic!("unsupported URL scheme in {priv_url}");
};
let secret_key =
SecretKeyBytes::parse_from_bind(&private_data).map_err::<Error, _>(|e| {
format!("unable to parse private key file {privref}: {e}").into()
})?;
let public_data = std::fs::read_to_string(k)?;
let pub_url = Url::parse(k).expect("valid URL expected");
let public_data = if pub_url.scheme() == "file" {
std::fs::read_to_string(pub_url.path())?
} else {
panic!("unsupported URL scheme in {pub_url}");
};
let public_key = parse_from_bind(&public_data).map_err::<Error, _>(|e| {
format!("unable to parse public key file {k}: {e}").into()
})?;
@@ -1641,3 +1724,7 @@ fn key_expired(key: &Key, ksc: &KeySetConfig) -> (bool, &'static str) {
};
(timestamp.elapsed() > validity, label)
}
fn make_parent_dir(filename: PathBuf) -> PathBuf {
filename.parent().unwrap_or(Path::new("/")).to_path_buf()
}