ssh_key/public/
key_data.rs

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