nix_compat/narinfo/
signing_keys.rs1use data_encoding::BASE64;
8use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH};
9
10use super::{SignatureRef, VerifyingKey};
11
12pub struct SigningKey<S> {
13 name: String,
14 signing_key: S,
15}
16
17impl<S> SigningKey<S>
18where
19 S: ed25519::signature::Signer<ed25519::Signature>,
20{
21 pub fn new(name: String, signing_key: S) -> Self {
23 Self { name, signing_key }
24 }
25
26 pub(crate) fn sign<'a>(&'a self, fp: &[u8]) -> SignatureRef<'a> {
28 SignatureRef::new(&self.name, self.signing_key.sign(fp).to_bytes())
29 }
30
31 pub fn name(&self) -> &str {
32 &self.name
33 }
34}
35
36pub fn parse_keypair(
38 input: &str,
39) -> Result<(SigningKey<ed25519_dalek::SigningKey>, VerifyingKey), Error> {
40 let (name, bytes64) = input.split_once(':').ok_or(Error::MissingSeparator)?;
41
42 if name.is_empty()
43 || !name
44 .chars()
45 .all(|c| char::is_alphanumeric(c) || c == '-' || c == '.')
46 {
47 return Err(Error::InvalidName(name.to_string()));
48 }
49
50 const DECODED_BYTES_LEN: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH;
51 if bytes64.len() != BASE64.encode_len(DECODED_BYTES_LEN) {
52 return Err(Error::InvalidSigningKeyLen(bytes64.len()));
53 }
54
55 let mut buf = [0; DECODED_BYTES_LEN + 2]; let mut bytes = [0; DECODED_BYTES_LEN];
57 match BASE64.decode_mut(bytes64.as_bytes(), &mut buf) {
58 Ok(len) if len == DECODED_BYTES_LEN => {
59 bytes.copy_from_slice(&buf[..DECODED_BYTES_LEN]);
60 }
61 Ok(_) => unreachable!(),
62 Err(_) => return Err(Error::DecodeError(input.to_string())),
64 }
65
66 let bytes_signing_key: [u8; SECRET_KEY_LENGTH] = {
67 let mut b = [0u8; SECRET_KEY_LENGTH];
68 b.copy_from_slice(&bytes[0..SECRET_KEY_LENGTH]);
69 b
70 };
71 let bytes_verifying_key: [u8; PUBLIC_KEY_LENGTH] = {
72 let mut b = [0u8; PUBLIC_KEY_LENGTH];
73 b.copy_from_slice(&bytes[SECRET_KEY_LENGTH..]);
74 b
75 };
76
77 let signing_key = SigningKey::new(
78 name.to_string(),
79 ed25519_dalek::SigningKey::from_bytes(&bytes_signing_key),
80 );
81
82 let verifying_key = VerifyingKey::new(
83 name.to_string(),
84 ed25519_dalek::VerifyingKey::from_bytes(&bytes_verifying_key)
85 .map_err(Error::InvalidVerifyingKey)?,
86 );
87
88 Ok((signing_key, verifying_key))
89}
90
91#[derive(Debug, thiserror::Error)]
92pub enum Error {
93 #[error("Invalid name: {0}")]
94 InvalidName(String),
95 #[error("Missing separator")]
96 MissingSeparator,
97 #[error("Invalid signing key len: {0}")]
98 InvalidSigningKeyLen(usize),
99 #[error("Unable to base64-decode signing key: {0}")]
100 DecodeError(String),
101 #[error("VerifyingKey error: {0}")]
102 InvalidVerifyingKey(ed25519_dalek::SignatureError),
103}
104
105#[cfg(test)]
106mod test {
107 use crate::narinfo::DUMMY_KEYPAIR;
108 #[test]
109 fn parse() {
110 let (_signing_key, _verifying_key) =
111 super::parse_keypair(DUMMY_KEYPAIR).expect("must succeed");
112 }
113
114 #[test]
115 fn parse_fail() {
116 assert!(super::parse_keypair("cache.example.com-1:cCta2MEsRNuYCgWYyeRXLyfoFpKhQJKn8gLMeXWAb7vIpRKKo/3JoxJ24OYa3DxT2JVV38KjK/1ywHWuMe2JE").is_err());
117 assert!(super::parse_keypair("cache.example.com-1cCta2MEsRNuYCgWYyeRXLyfoFpKhQJKn8gLMeXWAb7vIpRKKo/3JoxJ24OYa3DxT2JVV38KjK/1ywHWuMe2JE").is_err());
118 }
119}