ssh_key/public/
key_data.rs

1//! Public key data.
2
3use super::{Ed25519PublicKey, SkEd25519};
4use crate::{
5    checked::CheckedSum, decode::Decode, encode::Encode, reader::Reader, writer::Writer, Algorithm,
6    Error, Result,
7};
8
9#[cfg(feature = "alloc")]
10use super::{DsaPublicKey, RsaPublicKey};
11
12#[cfg(feature = "ecdsa")]
13use super::{EcdsaPublicKey, SkEcdsaSha2NistP256};
14
15#[cfg(feature = "fingerprint")]
16use crate::{Fingerprint, HashAlg};
17
18/// Public key data.
19#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
20#[non_exhaustive]
21pub enum KeyData {
22    /// Digital Signature Algorithm (DSA) public key data.
23    #[cfg(feature = "alloc")]
24    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
25    Dsa(DsaPublicKey),
26
27    /// Elliptic Curve Digital Signature Algorithm (ECDSA) public key data.
28    #[cfg(feature = "ecdsa")]
29    #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
30    Ecdsa(EcdsaPublicKey),
31
32    /// Ed25519 public key data.
33    Ed25519(Ed25519PublicKey),
34
35    /// RSA public key data.
36    #[cfg(feature = "alloc")]
37    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
38    Rsa(RsaPublicKey),
39
40    /// Security Key (FIDO/U2F) using ECDSA/NIST P-256 as specified in [PROTOCOL.u2f].
41    ///
42    /// [PROTOCOL.u2f]: https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.u2f?annotate=HEAD
43    #[cfg(feature = "ecdsa")]
44    #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
45    SkEcdsaSha2NistP256(SkEcdsaSha2NistP256),
46
47    /// Security Key (FIDO/U2F) using Ed25519 as specified in [PROTOCOL.u2f].
48    ///
49    /// [PROTOCOL.u2f]: https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.u2f?annotate=HEAD
50    SkEd25519(SkEd25519),
51}
52
53impl KeyData {
54    /// Get the [`Algorithm`] for this public key.
55    pub fn algorithm(&self) -> Algorithm {
56        match self {
57            #[cfg(feature = "alloc")]
58            Self::Dsa(_) => Algorithm::Dsa,
59            #[cfg(feature = "ecdsa")]
60            Self::Ecdsa(key) => key.algorithm(),
61            Self::Ed25519(_) => Algorithm::Ed25519,
62            #[cfg(feature = "alloc")]
63            Self::Rsa(_) => Algorithm::Rsa { hash: None },
64            #[cfg(feature = "ecdsa")]
65            Self::SkEcdsaSha2NistP256(_) => Algorithm::SkEcdsaSha2NistP256,
66            Self::SkEd25519(_) => Algorithm::SkEd25519,
67        }
68    }
69
70    /// Get DSA public key if this key is the correct type.
71    #[cfg(feature = "alloc")]
72    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
73    pub fn dsa(&self) -> Option<&DsaPublicKey> {
74        match self {
75            Self::Dsa(key) => Some(key),
76            _ => None,
77        }
78    }
79
80    /// Get ECDSA public key if this key is the correct type.
81    #[cfg(feature = "ecdsa")]
82    #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
83    pub fn ecdsa(&self) -> Option<&EcdsaPublicKey> {
84        match self {
85            Self::Ecdsa(key) => Some(key),
86            _ => None,
87        }
88    }
89
90    /// Get Ed25519 public key if this key is the correct type.
91    pub fn ed25519(&self) -> Option<&Ed25519PublicKey> {
92        match self {
93            Self::Ed25519(key) => Some(key),
94            #[allow(unreachable_patterns)]
95            _ => None,
96        }
97    }
98
99    /// Compute key fingerprint.
100    ///
101    /// Use [`Default::default()`] to use the default hash function (SHA-256).
102    #[cfg(feature = "fingerprint")]
103    #[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))]
104    pub fn fingerprint(&self, hash_alg: HashAlg) -> Fingerprint {
105        Fingerprint::new(hash_alg, self)
106    }
107
108    /// Get RSA public key if this key is the correct type.
109    #[cfg(feature = "alloc")]
110    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
111    pub fn rsa(&self) -> Option<&RsaPublicKey> {
112        match self {
113            Self::Rsa(key) => Some(key),
114            _ => None,
115        }
116    }
117
118    /// Get FIDO/U2F ECDSA/NIST P-256 public key if this key is the correct type.
119    #[cfg(feature = "ecdsa")]
120    #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
121    pub fn sk_ecdsa_p256(&self) -> Option<&SkEcdsaSha2NistP256> {
122        match self {
123            Self::SkEcdsaSha2NistP256(sk) => Some(sk),
124            _ => None,
125        }
126    }
127
128    /// Get FIDO/U2F Ed25519 public key if this key is the correct type.
129    pub fn sk_ed25519(&self) -> Option<&SkEd25519> {
130        match self {
131            Self::SkEd25519(sk) => Some(sk),
132            _ => None,
133        }
134    }
135
136    /// Is this key a DSA key?
137    #[cfg(feature = "alloc")]
138    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
139    pub fn is_dsa(&self) -> bool {
140        matches!(self, Self::Dsa(_))
141    }
142
143    /// Is this key an ECDSA key?
144    #[cfg(feature = "ecdsa")]
145    #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
146    pub fn is_ecdsa(&self) -> bool {
147        matches!(self, Self::Ecdsa(_))
148    }
149
150    /// Is this key an Ed25519 key?
151    pub fn is_ed25519(&self) -> bool {
152        matches!(self, Self::Ed25519(_))
153    }
154
155    /// Is this key an RSA key?
156    #[cfg(feature = "alloc")]
157    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
158    pub fn is_rsa(&self) -> bool {
159        matches!(self, Self::Rsa(_))
160    }
161
162    /// Is this key a FIDO/U2F ECDSA/NIST P-256 key?
163    #[cfg(feature = "ecdsa")]
164    #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
165    pub fn is_sk_ecdsa_p256(&self) -> bool {
166        matches!(self, Self::SkEcdsaSha2NistP256(_))
167    }
168
169    /// Is this key a FIDO/U2F Ed25519 key?
170    pub fn is_sk_ed25519(&self) -> bool {
171        matches!(self, Self::SkEd25519(_))
172    }
173
174    /// Decode [`KeyData`] for the specified algorithm.
175    pub(crate) fn decode_as(reader: &mut impl Reader, algorithm: Algorithm) -> Result<Self> {
176        match algorithm {
177            #[cfg(feature = "alloc")]
178            Algorithm::Dsa => DsaPublicKey::decode(reader).map(Self::Dsa),
179            #[cfg(feature = "ecdsa")]
180            Algorithm::Ecdsa { curve } => match EcdsaPublicKey::decode(reader)? {
181                key if key.curve() == curve => Ok(Self::Ecdsa(key)),
182                _ => Err(Error::Algorithm),
183            },
184            Algorithm::Ed25519 => Ed25519PublicKey::decode(reader).map(Self::Ed25519),
185            #[cfg(feature = "alloc")]
186            Algorithm::Rsa { .. } => RsaPublicKey::decode(reader).map(Self::Rsa),
187            #[cfg(feature = "ecdsa")]
188            Algorithm::SkEcdsaSha2NistP256 => {
189                SkEcdsaSha2NistP256::decode(reader).map(Self::SkEcdsaSha2NistP256)
190            }
191            Algorithm::SkEd25519 => SkEd25519::decode(reader).map(Self::SkEd25519),
192            #[allow(unreachable_patterns)]
193            _ => Err(Error::Algorithm),
194        }
195    }
196
197    /// Get the encoded length of this key data without a leading algorithm
198    /// identifier.
199    pub(crate) fn encoded_key_data_len(&self) -> Result<usize> {
200        match self {
201            #[cfg(feature = "alloc")]
202            Self::Dsa(key) => key.encoded_len(),
203            #[cfg(feature = "ecdsa")]
204            Self::Ecdsa(key) => key.encoded_len(),
205            Self::Ed25519(key) => key.encoded_len(),
206            #[cfg(feature = "alloc")]
207            Self::Rsa(key) => key.encoded_len(),
208            #[cfg(feature = "ecdsa")]
209            Self::SkEcdsaSha2NistP256(sk) => sk.encoded_len(),
210            Self::SkEd25519(sk) => sk.encoded_len(),
211        }
212    }
213
214    /// Encode the key data without a leading algorithm identifier.
215    pub(crate) fn encode_key_data(&self, writer: &mut impl Writer) -> Result<()> {
216        match self {
217            #[cfg(feature = "alloc")]
218            Self::Dsa(key) => key.encode(writer),
219            #[cfg(feature = "ecdsa")]
220            Self::Ecdsa(key) => key.encode(writer),
221            Self::Ed25519(key) => key.encode(writer),
222            #[cfg(feature = "alloc")]
223            Self::Rsa(key) => key.encode(writer),
224            #[cfg(feature = "ecdsa")]
225            Self::SkEcdsaSha2NistP256(sk) => sk.encode(writer),
226            Self::SkEd25519(sk) => sk.encode(writer),
227        }
228    }
229}
230
231impl Decode for KeyData {
232    fn decode(reader: &mut impl Reader) -> Result<Self> {
233        let algorithm = Algorithm::decode(reader)?;
234        Self::decode_as(reader, algorithm)
235    }
236}
237
238impl Encode for KeyData {
239    fn encoded_len(&self) -> Result<usize> {
240        [
241            self.algorithm().encoded_len()?,
242            self.encoded_key_data_len()?,
243        ]
244        .checked_sum()
245    }
246
247    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
248        self.algorithm().encode(writer)?;
249        self.encode_key_data(writer)
250    }
251}
252
253#[cfg(feature = "alloc")]
254#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
255impl From<DsaPublicKey> for KeyData {
256    fn from(public_key: DsaPublicKey) -> KeyData {
257        Self::Dsa(public_key)
258    }
259}
260
261#[cfg(feature = "ecdsa")]
262#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
263impl From<EcdsaPublicKey> for KeyData {
264    fn from(public_key: EcdsaPublicKey) -> KeyData {
265        Self::Ecdsa(public_key)
266    }
267}
268
269impl From<Ed25519PublicKey> for KeyData {
270    fn from(public_key: Ed25519PublicKey) -> KeyData {
271        Self::Ed25519(public_key)
272    }
273}
274
275#[cfg(feature = "alloc")]
276#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
277impl From<RsaPublicKey> for KeyData {
278    fn from(public_key: RsaPublicKey) -> KeyData {
279        Self::Rsa(public_key)
280    }
281}
282
283#[cfg(feature = "ecdsa")]
284#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
285impl From<SkEcdsaSha2NistP256> for KeyData {
286    fn from(public_key: SkEcdsaSha2NistP256) -> KeyData {
287        Self::SkEcdsaSha2NistP256(public_key)
288    }
289}
290
291impl From<SkEd25519> for KeyData {
292    fn from(public_key: SkEd25519) -> KeyData {
293        Self::SkEd25519(public_key)
294    }
295}