Get ed25519 dkim signature working
Some checks failed
/ check (push) Failing after 1m1s
/ dev-shell (push) Successful in 2m22s
/ rust-packages (push) Successful in 2m43s
/ systems (push) Successful in 28m40s
/ terraform-providers (push) Successful in 2m27s

This commit is contained in:
Kaare Hoff Skovgaard 2025-07-30 16:29:00 +02:00
parent 9af8f29b48
commit fabaf54549
Signed by: khs
GPG key ID: C7D890804F01E9F0
10 changed files with 894 additions and 17 deletions

View file

@ -30,6 +30,8 @@ jobs:
nix build --no-link '.#packages.x86_64-linux.terraform-provider-openstack'
nix build --no-link '.#packages.x86_64-linux.terraform-provider-unifi'
nix build --no-link '.#packages.x86_64-linux.terraform-provider-vault'
nix build --no-link '.#packages.x86_64-linux.terraform-provider-tls'
nix build --no-link '.#packages.x86_64-linux.terraform-provider-external'
systems:
runs-on: cache.kaareskovgaard.net
steps:

View file

@ -1,32 +1,44 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.khscodes.infrastructure.mailserver;
opensslStripAsn1 = pkgs.writeTextFile {
name = "openssl-strip-asn1";
executable = true;
text = ''
#!/usr/bin/env bash
set -e
eval "$(jq -r '@sh "PUBKEY=\(.pubkey)"')"
stripped_pubkey="$(echo -n "$PUBKEY" | openssl asn1parse -in - -offset 12 -noout -out /dev/stdout | openssl base64)"
jq -n --arg result "$stripped_pubkey" '{"asn1Stripped":$result}'
'';
};
publicKeyBegin = ''"-----BEGIN PUBLIC KEY-----\n"'';
publicKeyEnd = ''"-----END PUBLIC KEY-----\n"'';
rsaKeyPath = domain: "/run/secret/dkim/${domain}.snm_rsa.key";
ed25519KeyPath = domain: "/run/secret/dkim/${domain}.snm_ed25519.key";
rsaKeyPath = domain: "/run/secret/dkim/${domain}.rsa.key";
ed25519KeyPath = domain: "/run/secret/dkim/${domain}.ed25519.key";
domainKeyPaths = lib.lists.flatten (
lib.lists.map (domain: [
(rsaKeyPath domain)
(ed25519KeyPath domain)
]) cfg.domains
);
# Currently (2025-07-25) I canot get rspamd to sign with ed25519 key,
# it appears it attempts to parse it as an RSA key
# {
# path: "${ed25519KeyPath domain}";
# selector: "snm_ed25519";
# }
dkimSigningForDomain = domain: ''
${domain} {
selectors [
{
path: "${rsaKeyPath domain}";
selector: "snm_rsa";
selector: "rsa";
},
{
path: "${ed25519KeyPath domain}";
selector: "ed25519";
}
]
}
@ -60,11 +72,18 @@ in
(
{ ... }:
{
terraform.required_providers.tls = {
terraform.required_providers = {
tls = {
source = "hashicorp/tls";
version = "4.1.0";
};
external = {
source = "hashicorp/external";
version = "2.3.5";
};
};
provider.tls = { };
provider.external = { };
khscodes.cloudflare.enable = true;
resource.tls_private_key =
@ -86,15 +105,35 @@ in
}) cfg.domains
));
data.external = lib.listToAttrs (
lib.lists.map (
domain:
let
name = "${lib.khscodes.sanitize-terraform-name domain}_dkim_ed25519";
in
{
inherit name;
value = {
program = [
"${opensslStripAsn1}"
];
query = {
pubkey = "\${ resource.tls_private_key.${name}.public_key_pem}";
};
};
}
) cfg.domains
);
khscodes.cloudflare.dns.txtRecords =
(lib.lists.map (domain: {
fqdn = "snm_rsa._domainkey.${domain}";
fqdn = "rsa._domainkey.${domain}";
content = ''"''${ join("\" \"", regexall(".{1,255}", "v=DKIM1;k=rsa;p=${dkimPublicKey "tls_private_key.${lib.khscodes.sanitize-terraform-name domain}_dkim_rsa"}" )) }"'';
ttl = 600;
}) cfg.domains)
++ (lib.lists.map (domain: {
fqdn = "snm_ed25519._domainkey.${domain}";
content = ''"''${ join("\" \"", regexall(".{1,255}", "v=DKIM1;k=ed25519;p=${dkimPublicKey "tls_private_key.${lib.khscodes.sanitize-terraform-name domain}_dkim_ed25519"}" )) }"'';
fqdn = "ed25519._domainkey.${domain}";
content = ''"''${ join("\" \"", regexall(".{1,255}", "v=DKIM1;k=ed25519;p=''${ data.external.${lib.khscodes.sanitize-terraform-name domain}_dkim_ed25519.result.asn1Stripped }" )) }"'';
ttl = 600;
}) cfg.domains);
@ -143,15 +182,25 @@ in
];
}
{
# rspamd does not like reading ed25519 keys with begin/end pairs, as they get parsed as
# rsa keys
contents = ''
{{- with secret "${cfg.dkim.vault.mount}/data/${cfg.dkim.vault.prefixPath}/${domain}/ed25519" -}}
{{ .Data.data.dkim_private_key }}
{{- end -}}
'';
destination = ed25519KeyPath domain;
destination = "${ed25519KeyPath domain}.openssl";
perms = "0600";
owner = "rspamd";
group = "rspamd";
exec = ''
${lib.getExe' pkgs.uutils-coreutils-noprefix "touch"} ${ed25519KeyPath domain}
${lib.getExe' pkgs.uutils-coreutils-noprefix "chown"} rspamd:rspamd ${ed25519KeyPath domain}
${lib.getExe' pkgs.uutils-coreutils-noprefix "chmod"} 0600 ${ed25519KeyPath domain}
${lib.getExe pkgs.khscodes.ed25519-helper} pem-private-key-to-sodium-private-key '${ed25519KeyPath domain}.openssl' \
| ${lib.getExe' pkgs.uutils-coreutils-noprefix "base64"} --wrap=0 \
> ${ed25519KeyPath domain}
'';
restartUnits = [
"rspamd.service"
];

View file

@ -0,0 +1,12 @@
{
lib,
pkgs,
inputs,
}:
(lib.khscodes.mkRust pkgs "${inputs.self}/rust").buildRustPackage {
crateName = "ed25519-helper";
replacePath = true;
runtimeInputs = [
pkgs.openssl
];
}

View file

@ -7,6 +7,12 @@ pkgs.writeShellApplication {
name = "instance-opentofu";
runtimeInputs = [
pkgs.uutils-coreutils-noprefix
]
++ [
# Needed for the data.external stuff in dkim for mailserver
pkgs.openssl
pkgs.uutils-coreutils-noprefix
pkgs.jq
];
text = ''
fqdn="$1"

View file

@ -9,4 +9,5 @@ pkgs.opentofu.withPlugins (p: [
pkgs.khscodes.terraform-provider-vault
pkgs.khscodes.terraform-provider-random
pkgs.khscodes.terraform-provider-tls
pkgs.khscodes.terraform-provider-external
])

View file

@ -0,0 +1,10 @@
{ pkgs }:
pkgs.terraform-providers.mkProvider {
hash = "sha256-rHMmGzYvsE5GT0E71UUIXjDG9+v52LI69/gdP2xuI7w=";
homepage = "https://registry.terraform.io/providers/hashicorp/external";
owner = "hashicorp";
repo = "terraform-provider-external";
rev = "v2.3.5";
spdx = "MPL-2.0";
vendorHash = "sha256-xIagZvWtlNpz5SQfxbA7r9ojAeS3CW2pwV337ObKOwU=";
}

738
rust/Cargo.lock generated
View file

@ -2,6 +2,30 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -11,6 +35,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "anstream"
version = "0.6.19"
@ -67,6 +97,15 @@ version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "base64"
version = "0.22.1"
@ -79,6 +118,21 @@ version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "cc"
version = "1.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.1"
@ -153,6 +207,107 @@ dependencies = [
"shell-quote",
]
[[package]]
name = "core2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
dependencies = [
"memchr",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "ct-codecs"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b10589d1a5e400d61f9f38f12f884cfd080ff345de8f17efda36fe0e4a02aa8"
[[package]]
name = "ctor"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec09e802f5081de6157da9a75701d6c713d8dc3ba52571fd4bd25f412644e8a6"
dependencies = [
"ctor-proc-macro",
"dtor",
]
[[package]]
name = "ctor-proc-macro"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2"
[[package]]
name = "dary_heap"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728"
[[package]]
name = "derive_arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[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 = "dtor"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97cbdf2ad6846025e8e25df05171abfb30e3ababa12ee0a0e44b9bbe570633a8"
dependencies = [
"dtor-proc-macro",
]
[[package]]
name = "dtor-proc-macro"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055"
[[package]]
name = "ed25519-helper"
version = "1.0.0"
dependencies = [
"anyhow",
"clap",
"common",
"hakari",
"libsodium-rs",
"log",
]
[[package]]
name = "env_filter"
version = "0.1.3"
@ -182,6 +337,47 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "filetime"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
dependencies = [
"cfg-if",
"libc",
"libredox",
"windows-sys",
]
[[package]]
name = "flate2"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[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 = "hakari"
version = "0.1.0"
@ -192,6 +388,16 @@ dependencies = [
"syn",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "hashbrown"
version = "0.15.4"
@ -216,6 +422,113 @@ dependencies = [
"serde",
]
[[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 = "indexmap"
version = "2.10.0"
@ -223,7 +536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.15.4",
]
[[package]]
@ -268,6 +581,73 @@ version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "libflate"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e"
dependencies = [
"adler32",
"core2",
"crc32fast",
"dary_heap",
"libflate_lz77",
]
[[package]]
name = "libflate_lz77"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d"
dependencies = [
"core2",
"hashbrown 0.14.5",
"rle-decode-fast",
]
[[package]]
name = "libredox"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "360e552c93fa0e8152ab463bc4c4837fce76a225df11dfaeea66c313de5e61f7"
dependencies = [
"bitflags",
"libc",
"redox_syscall",
]
[[package]]
name = "libsodium-rs"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02cad4b7d7628445ec5dd53a1ee32cc9222407fd32f3833ed1c9a343f6b4c646"
dependencies = [
"ct-codecs",
"ctor",
"libc",
"libsodium-sys-stable",
"pkg-config",
"thiserror",
"zeroize",
]
[[package]]
name = "libsodium-sys-stable"
version = "1.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b023d38f2afdfe36f81e15a9d7232097701d7b107e3a93ba903083985e235239"
dependencies = [
"cc",
"libc",
"libflate",
"minisign-verify",
"pkg-config",
"tar",
"ureq",
"vcpkg",
"zip",
]
[[package]]
name = "libyml"
version = "0.0.5"
@ -278,6 +658,18 @@ dependencies = [
"version_check",
]
[[package]]
name = "linux-raw-sys"
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 = "log"
version = "0.4.27"
@ -290,6 +682,21 @@ version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "minisign-verify"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e856fdd13623a2f5f2f54676a4ee49502a96a80ef4a62bcedd23d52427c44d43"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
[[package]]
name = "nix"
version = "0.30.1"
@ -302,6 +709,12 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
@ -321,6 +734,18 @@ dependencies = [
"serde",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "portable-atomic"
version = "1.11.1"
@ -336,6 +761,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 = "proc-macro2"
version = "1.0.95"
@ -354,6 +788,15 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.11.1"
@ -383,6 +826,25 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rle-decode-fast"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
[[package]]
name = "rustix"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.20"
@ -453,6 +915,30 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb502615975ae2365825521fa1529ca7648fd03ce0b0746604e0683856ecd7e4"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[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"
@ -470,18 +956,105 @@ 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 = "tar"
version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinystr"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "ureq"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
dependencies = [
"base64",
"log",
"once_cell",
"url",
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.5"
@ -560,3 +1133,166 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "writeable"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
[[package]]
name = "xattr"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909"
dependencies = [
"libc",
"rustix",
]
[[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.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
"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"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[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",
]
[[package]]
name = "zip"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"displaydoc",
"flate2",
"indexmap",
"memchr",
"thiserror",
"zopfli",
]
[[package]]
name = "zopfli"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
dependencies = [
"bumpalo",
"crc32fast",
"log",
"simd-adler32",
]

View file

@ -21,6 +21,7 @@ clap = { version = "4.5.39", default-features = false, features = [
"derive",
] }
log = { version = "0.4.27", default-features = false, features = ["std"] }
libsodium-rs = { version = "0.1.1", default-features = false, features = [] }
nix = { version = "0.30.1", default-features = false }
serde = { version = "1.0.219", default-features = false, features = [
"derive",

View file

@ -0,0 +1,13 @@
[package]
name = "ed25519-helper"
edition = "2024"
version = "1.0.0"
metadata.crane.name = "ed25519-helper"
[dependencies]
anyhow = { workspace = true }
clap = { workspace = true }
common = { path = "../../lib/common" }
log = { workspace = true }
libsodium-rs = { workspace = true }
hakari = { version = "0.1", path = "../../lib/hakari" }

View file

@ -0,0 +1,47 @@
use std::{io::Write, path::PathBuf};
use clap::{Parser, Subcommand};
fn main() {
common::entrypoint(program);
}
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct Args {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
/// Outputs the raw bytes of a libsodium private key part (as used by rspamd) from a PEM encoded
/// private key. For use with rspamd, base64 encode the output
PemPrivateKeyToSodiumPrivateKey(PemPrivateKeyToSodiumPrivateKey),
}
#[derive(Debug, Clone, clap::Args)]
pub struct PemPrivateKeyToSodiumPrivateKey {
/// Path to the file holding the PEM key
pem_file: PathBuf,
}
fn program() -> anyhow::Result<()> {
let args = Args::parse();
match args.command {
Commands::PemPrivateKeyToSodiumPrivateKey(p) => pem_private_key_to_sodium_private_key(p),
}
}
fn pem_private_key_to_sodium_private_key(p: PemPrivateKeyToSodiumPrivateKey) -> anyhow::Result<()> {
let mut proc = common::proc::Command::new("openssl");
proc.args(["pkey", "-in"]);
proc.arg(p.pem_file.as_path().display().to_string());
proc.args(["-outform", "DER"]);
let result = proc.try_spawn_to_bytes()?;
let libsodium_seed = &result[16..48];
let keypair = libsodium_rs::crypto_sign::KeyPair::from_seed(libsodium_seed)?;
let mut stdout = std::io::stdout();
stdout.write(keypair.secret_key.as_bytes())?;
Ok(())
}