nethsm/
key.rs

1use std::{fmt::Display, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4use signstar_crypto::key::MIN_RSA_BIT_LENGTH;
5
6use crate::TlsKeyType;
7
8/// An error that can occur when dealing with keys.
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11    /// Elliptic curve TLS keys do not support providing a length
12    #[error("Elliptic curve key ({tls_key_type}) does not support setting length")]
13    TlsKeyLengthUnsupported {
14        /// The type of TLS key.
15        tls_key_type: TlsKeyType,
16    },
17
18    /// RSA TLS key type requires setting a length
19    #[error("Generating a key of type {tls_key_type} requires setting a length")]
20    TlsKeyLengthRequired {
21        /// The type of TLS key.
22        tls_key_type: TlsKeyType,
23    },
24
25    /// RSA TLS key is generated with unsafe key length (smaller than 2048)
26    #[error(
27        "RSA keys shorter than {MIN_RSA_BIT_LENGTH} are not supported. A key length of {key_length} is unsafe!"
28    )]
29    InvalidTlsKeyLengthRsa {
30        /// The bit length of the RSA key.
31        key_length: u32,
32    },
33
34    /// One or more [`KeyId`]s are not valid.
35    #[error("Invalid Key ID{}: {}", if key_ids.len() == 1 {"s"} else { " "}, key_ids.join(", "))]
36    InvalidKeyIds {
37        /// A list of strings representing invalid [`KeyId`]s.
38        key_ids: Vec<String>,
39    },
40
41    /// A signstar_crypto key  error.
42    #[error("A signstar_crypto::key error:\n{0}")]
43    SignstarCryptoKey(#[from] signstar_crypto::key::Error),
44}
45
46/// A unique key identifier for a private key on a NetHSM.
47///
48/// A [`KeyId`]s must be in the character set `[a-z0-9]` and must not be empty.
49/// It is used in [key management] on a NetHSM and is unique in its scope.
50/// The same [`KeyId`] may exist system-wide and in one or several [namespaces], but no duplicate
51/// [`KeyId`] can exist system-wide or in the same namespace.
52///
53/// [key management]: https://docs.nitrokey.com/nethsm/operation#key-management
54/// [namespaces]: https://docs.nitrokey.com/nethsm/administration#namespaces
55#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
56#[serde(into = "String", try_from = "String")]
57pub struct KeyId(String);
58
59impl KeyId {
60    /// Constructs a new Key ID from a `String`.
61    ///
62    /// Validates the input string and returns [`crate::Error::Key`]
63    /// if it is invalid.
64    ///
65    /// # Errors
66    ///
67    /// Returns an [`Error`][`crate::Error`] if
68    /// * string contains characters outside of the allowed range (`[a-z0-9]`)
69    /// * string is empty
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use nethsm::KeyId;
75    ///
76    /// assert!(KeyId::new("key1".into()).is_ok());
77    /// assert!(KeyId::new("key".into()).is_ok());
78    ///
79    /// // the input can not contain invalid chars
80    /// assert!(KeyId::new("key1#".into()).is_err());
81    /// assert!(KeyId::new("key~1".into()).is_err());
82    ///
83    /// // the key must be non-empty
84    /// assert!(KeyId::new("".into()).is_err());
85    /// ```
86    pub fn new(key_id: String) -> Result<Self, Error> {
87        if key_id.is_empty()
88            || !key_id.chars().all(|char| {
89                char.is_numeric() || (char.is_ascii_lowercase() && char.is_ascii_alphabetic())
90            })
91        {
92            return Err(Error::InvalidKeyIds {
93                key_ids: vec![key_id],
94            });
95        }
96
97        Ok(Self(key_id))
98    }
99}
100
101impl AsRef<str> for KeyId {
102    fn as_ref(&self) -> &str {
103        &self.0
104    }
105}
106
107impl From<KeyId> for String {
108    fn from(value: KeyId) -> Self {
109        value.0
110    }
111}
112
113impl FromStr for KeyId {
114    type Err = Error;
115    fn from_str(s: &str) -> Result<Self, Self::Err> {
116        Self::new(s.into())
117    }
118}
119
120impl Display for KeyId {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        self.0.fmt(f)
123    }
124}
125
126impl TryFrom<&str> for KeyId {
127    type Error = Error;
128
129    fn try_from(value: &str) -> Result<Self, Self::Error> {
130        Self::from_str(value)
131    }
132}
133
134impl TryFrom<&String> for KeyId {
135    type Error = Error;
136
137    fn try_from(value: &String) -> Result<Self, Self::Error> {
138        Self::from_str(value)
139    }
140}
141
142impl TryFrom<String> for KeyId {
143    type Error = Error;
144
145    fn try_from(value: String) -> Result<Self, Self::Error> {
146        Self::new(value)
147    }
148}
149
150/// Ensures that a [`TlsKeyType`] is compatible with an optional key length
151///
152/// # Errors
153///
154/// Returns an [`Error::Key`][`crate::Error::Key`] if
155/// * `tls_key_type` is one of [`TlsKeyType::Curve25519`], [`TlsKeyType::EcP224`],
156///   [`TlsKeyType::EcP256`], [`TlsKeyType::EcP384`] or [`TlsKeyType::EcP521`] and `length` is
157///   [`Some`].
158/// * `tls_key_type` is [`TlsKeyType::Rsa`] and `length` is [`None`].
159/// * `tls_key_type` is [`TlsKeyType::Rsa`] and `length` is not [`Some`] value equal to or greater
160///   than [`MIN_RSA_BIT_LENGTH`].
161///
162/// # Examples
163///
164/// ```
165/// use nethsm::{TlsKeyType, tls_key_type_matches_length};
166///
167/// # fn main() -> testresult::TestResult {
168/// tls_key_type_matches_length(TlsKeyType::Curve25519, None)?;
169/// tls_key_type_matches_length(TlsKeyType::EcP224, None)?;
170/// tls_key_type_matches_length(TlsKeyType::Rsa, Some(2048))?;
171///
172/// // this fails because elliptic curve keys have their length set intrinsically
173/// assert!(tls_key_type_matches_length(TlsKeyType::Curve25519, Some(2048)).is_err());
174/// // this fails because a bit length of 1024 is unsafe to use for RSA keys
175/// assert!(tls_key_type_matches_length(TlsKeyType::Rsa, Some(1024)).is_err());
176/// # Ok(())
177/// # }
178/// ```
179pub fn tls_key_type_matches_length(
180    tls_key_type: TlsKeyType,
181    length: Option<u32>,
182) -> Result<(), Error> {
183    match tls_key_type {
184        TlsKeyType::Curve25519
185        | TlsKeyType::EcP224
186        | TlsKeyType::EcP256
187        | TlsKeyType::EcP384
188        | TlsKeyType::EcP521 => {
189            if length.is_some() {
190                Err(Error::TlsKeyLengthUnsupported { tls_key_type })
191            } else {
192                Ok(())
193            }
194        }
195        TlsKeyType::Rsa => match length {
196            None => Err(Error::TlsKeyLengthRequired { tls_key_type }),
197            Some(length) => {
198                if length < MIN_RSA_BIT_LENGTH {
199                    Err(Error::InvalidTlsKeyLengthRsa { key_length: length })
200                } else {
201                    Ok(())
202                }
203            }
204        },
205    }
206}