ssh_agent_lib/proto/
privatekey.rs1use core::fmt;
4
5use ssh_encoding::{Decode, Encode, Reader, Writer};
6use ssh_key::{
7 private::{self, DsaPrivateKey, Ed25519Keypair, RsaPrivateKey},
8 Algorithm, EcdsaCurve, Error, Result,
9};
10use subtle::{Choice, ConstantTimeEq};
11
12#[derive(Clone, Debug)]
14pub enum EcdsaPrivateKey {
15 NistP256(private::EcdsaPrivateKey<32>),
17
18 NistP384(private::EcdsaPrivateKey<48>),
20
21 NistP521(private::EcdsaPrivateKey<66>),
23}
24
25impl ConstantTimeEq for EcdsaPrivateKey {
26 fn ct_eq(&self, other: &Self) -> Choice {
27 let private_key_a = match self {
28 Self::NistP256(private) => private.as_slice(),
29 Self::NistP384(private) => private.as_slice(),
30 Self::NistP521(private) => private.as_slice(),
31 };
32
33 let private_key_b = match other {
34 Self::NistP256(private) => private.as_slice(),
35 Self::NistP384(private) => private.as_slice(),
36 Self::NistP521(private) => private.as_slice(),
37 };
38
39 private_key_a.ct_eq(private_key_b)
40 }
41}
42
43impl Eq for EcdsaPrivateKey {}
44
45impl PartialEq for EcdsaPrivateKey {
46 fn eq(&self, other: &Self) -> bool {
47 self.ct_eq(other).into()
48 }
49}
50
51impl EcdsaPrivateKey {
52 fn decode_as(reader: &mut impl Reader, curve: EcdsaCurve) -> Result<Self> {
53 match curve {
54 EcdsaCurve::NistP256 => {
55 private::EcdsaPrivateKey::<32>::decode(reader).map(Self::NistP256)
56 }
57 EcdsaCurve::NistP384 => {
58 private::EcdsaPrivateKey::<48>::decode(reader).map(Self::NistP384)
59 }
60 EcdsaCurve::NistP521 => {
61 private::EcdsaPrivateKey::<66>::decode(reader).map(Self::NistP521)
62 }
63 }
64 }
65}
66
67impl Encode for EcdsaPrivateKey {
68 fn encoded_len(&self) -> ssh_encoding::Result<usize> {
69 match self {
70 Self::NistP256(private) => private.encoded_len(),
71 Self::NistP384(private) => private.encoded_len(),
72 Self::NistP521(private) => private.encoded_len(),
73 }
74 }
75
76 fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
77 match self {
78 Self::NistP256(private) => private.encode(writer),
79 Self::NistP384(private) => private.encode(writer),
80 Self::NistP521(private) => private.encode(writer),
81 }
82 }
83}
84
85#[derive(Clone)]
87#[non_exhaustive]
88pub enum PrivateKeyData {
89 Dsa(DsaPrivateKey),
91
92 Ecdsa(EcdsaPrivateKey),
94
95 Ed25519(Ed25519Keypair),
99
100 Rsa(RsaPrivateKey),
102}
103
104impl PrivateKeyData {
105 pub fn decode_as(reader: &mut impl Reader, algorithm: Algorithm) -> Result<Self> {
107 match algorithm {
108 Algorithm::Dsa => DsaPrivateKey::decode(reader).map(Self::Dsa),
109 Algorithm::Ecdsa { curve } => {
110 EcdsaPrivateKey::decode_as(reader, curve).map(Self::Ecdsa)
111 }
112 Algorithm::Ed25519 => Ed25519Keypair::decode(reader).map(Self::Ed25519),
113 Algorithm::Rsa { .. } => RsaPrivateKey::decode(reader).map(Self::Rsa),
114 #[allow(unreachable_patterns)]
115 _ => Err(Error::AlgorithmUnknown),
116 }
117 }
118}
119
120impl fmt::Debug for PrivateKeyData {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self {
123 Self::Dsa(_) => write!(f, "PrivateKeyData::Dsa"),
124 Self::Ecdsa(_) => write!(f, "PrivateKeyData::Ecdsa"),
125 Self::Ed25519(_) => write!(f, "PrivateKeyData::Ed25519"),
126 Self::Rsa(_) => write!(f, "PrivateKeyData::Rsa"),
127 }
128 }
129}
130
131impl Encode for PrivateKeyData {
132 fn encoded_len(&self) -> ssh_encoding::Result<usize> {
133 match self {
134 Self::Dsa(key) => key.encoded_len(),
135 Self::Ecdsa(key) => key.encoded_len(),
136 Self::Ed25519(key) => key.encoded_len(),
137 Self::Rsa(key) => key.encoded_len(),
138 }
139 }
140
141 fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
142 match self {
143 Self::Dsa(key) => key.encode(writer)?,
144 Self::Ecdsa(key) => key.encode(writer)?,
145 Self::Ed25519(key) => key.encode(writer)?,
146 Self::Rsa(key) => key.encode(writer)?,
147 }
148
149 Ok(())
150 }
151}
152
153impl ConstantTimeEq for PrivateKeyData {
154 fn ct_eq(&self, other: &Self) -> Choice {
155 match (self, other) {
157 (Self::Dsa(a), Self::Dsa(b)) => a.ct_eq(b),
158 (Self::Ecdsa(a), Self::Ecdsa(b)) => a.ct_eq(b),
159 (Self::Ed25519(a), Self::Ed25519(b)) => a.ct_eq(b),
160 (Self::Rsa(a), Self::Rsa(b)) => a.ct_eq(b),
161 #[allow(unreachable_patterns)]
162 _ => Choice::from(0),
163 }
164 }
165}
166
167impl Eq for PrivateKeyData {}
168
169impl PartialEq for PrivateKeyData {
170 fn eq(&self, other: &Self) -> bool {
171 self.ct_eq(other).into()
172 }
173}