ssh_agent_lib/proto/message/
credential.rs1use std::str::FromStr as _;
4
5use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
6use ssh_key::public::KeyData;
7use ssh_key::{certificate::Certificate, private::KeypairData, Algorithm};
8
9use crate::proto::{Error, PrivateKeyData, Result};
10
11#[derive(Clone, PartialEq, Debug)]
20pub enum PrivateCredential {
21 Key {
23 privkey: KeypairData,
25
26 comment: String,
28 },
29
30 Cert {
32 algorithm: Algorithm,
34
35 certificate: Box<Certificate>,
37
38 privkey: PrivateKeyData,
40
41 comment: String,
43 },
44}
45
46impl Decode for PrivateCredential {
47 type Error = Error;
48
49 fn decode(reader: &mut impl Reader) -> Result<Self> {
50 let alg = String::decode(reader)?;
51 let cert_alg = Algorithm::new_certificate(&alg);
52
53 if let Ok(algorithm) = cert_alg {
54 let certificate = reader
55 .read_prefixed(|reader| {
56 let cert = Certificate::decode(reader)?;
57 Ok::<_, Error>(cert)
58 })?
59 .into();
60 let privkey = PrivateKeyData::decode_as(reader, algorithm.clone())?;
61 let comment = String::decode(reader)?;
62
63 Ok(PrivateCredential::Cert {
64 algorithm,
65 certificate,
66 privkey,
67 comment,
68 })
69 } else {
70 let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?;
71 let privkey = KeypairData::decode_as(reader, algorithm)?;
72 let comment = String::decode(reader)?;
73 Ok(PrivateCredential::Key { privkey, comment })
74 }
75 }
76}
77
78impl Encode for PrivateCredential {
79 fn encoded_len(&self) -> ssh_encoding::Result<usize> {
80 match self {
81 Self::Key { privkey, comment } => {
82 [privkey.encoded_len()?, comment.encoded_len()?].checked_sum()
83 }
84 Self::Cert {
85 algorithm,
86 certificate,
87 privkey,
88 comment,
89 } => [
90 algorithm.to_certificate_type().encoded_len()?,
91 certificate.encoded_len_prefixed()?,
92 privkey.encoded_len()?,
93 comment.encoded_len()?,
94 ]
95 .checked_sum(),
96 }
97 }
98
99 fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
100 match self {
101 Self::Key { privkey, comment } => {
102 privkey.encode(writer)?;
103 comment.encode(writer)
104 }
105 Self::Cert {
106 algorithm,
107 certificate,
108 privkey,
109 comment,
110 } => {
111 algorithm.to_certificate_type().encode(writer)?;
112 certificate.encode_prefixed(writer)?;
113 privkey.encode(writer)?;
114 comment.encode(writer)
115 }
116 }
117 }
118}
119
120#[derive(Debug, PartialEq, Eq, Clone)]
121pub enum PublicCredential {
123 Key(KeyData),
125 Cert(Box<Certificate>),
127}
128
129impl PublicCredential {
130 pub fn key_data(&self) -> &KeyData {
132 match self {
133 Self::Key(key) => key,
134 Self::Cert(cert) => cert.public_key(),
135 }
136 }
137}
138
139impl Decode for PublicCredential {
140 type Error = Error;
141
142 fn decode(reader: &mut impl Reader) -> core::result::Result<Self, Self::Error> {
143 let alg = String::decode(reader)?;
145
146 let remaining_len = reader.remaining_len();
147 let mut buf = Vec::with_capacity(4 + alg.len() + remaining_len);
148 alg.encode(&mut buf)?;
149 let mut tail = vec![0u8; remaining_len];
150 reader.read(&mut tail)?;
151 buf.extend_from_slice(&tail);
152
153 if Algorithm::new_certificate(&alg).is_ok() {
154 let cert = Certificate::decode(&mut &buf[..])?;
155 Ok(Self::Cert(Box::new(cert)))
156 } else {
157 let key = KeyData::decode(&mut &buf[..])?;
158 Ok(Self::Key(key))
159 }
160 }
161}
162
163impl Encode for PublicCredential {
164 fn encoded_len(&self) -> std::result::Result<usize, ssh_encoding::Error> {
165 match self {
166 Self::Key(pubkey) => pubkey.encoded_len(),
167 Self::Cert(certificate) => certificate.encoded_len(),
168 }
169 }
170
171 fn encode(
172 &self,
173 writer: &mut impl ssh_encoding::Writer,
174 ) -> std::result::Result<(), ssh_encoding::Error> {
175 match self {
176 Self::Key(pubkey) => pubkey.encode(writer),
177 Self::Cert(certificate) => certificate.encode(writer),
178 }
179 }
180}
181
182impl From<KeyData> for PublicCredential {
183 fn from(value: KeyData) -> Self {
184 Self::Key(value)
185 }
186}
187
188impl From<Certificate> for PublicCredential {
189 fn from(value: Certificate) -> Self {
190 Self::Cert(value.into())
191 }
192}