1use crate::{Algorithm, AssociatedHashAlg, Error, HashAlg, Result, Signature, SigningKey, public};
4use alloc::{string::String, string::ToString, vec::Vec};
5use core::str::FromStr;
6use encoding::{
7 CheckedSum, Decode, DecodePem, Encode, EncodePem, Reader, Writer,
8 pem::{LineEnding, PemLabel},
9};
10use sha2::Digest;
11use signature::Verifier;
12
13#[cfg(doc)]
14use crate::{PrivateKey, PublicKey};
15
16type Version = u32;
17
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize, de, ser};
20
21#[derive(Clone, Debug, Eq, PartialEq)]
39pub struct SshSig {
40 version: Version,
41 public_key: public::KeyData,
42 namespace: String,
43 reserved: Vec<u8>,
44 hash_alg: HashAlg,
45 signature: Signature,
46}
47
48impl SshSig {
49 pub const VERSION: Version = 1;
51
52 const MAGIC_PREAMBLE: &'static [u8] = b"SSHSIG";
57
58 pub fn new(
61 public_key: public::KeyData,
62 namespace: impl Into<String>,
63 hash_alg: HashAlg,
64 signature: Signature,
65 ) -> Result<Self> {
66 let version = Self::VERSION;
67 let namespace = namespace.into();
68 let reserved = Vec::new();
69
70 if namespace.is_empty() {
71 return Err(Error::Namespace);
72 }
73
74 Ok(Self {
75 version,
76 public_key,
77 namespace,
78 reserved,
79 hash_alg,
80 signature,
81 })
82 }
83
84 pub fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self> {
90 Self::decode_pem(pem)
91 }
92
93 pub fn to_pem(&self, line_ending: LineEnding) -> Result<String> {
99 Ok(self.encode_pem_string(line_ending)?)
100 }
101
102 pub fn sign<S: SigningKey>(
106 signing_key: &S,
107 namespace: &str,
108 hash_alg: HashAlg,
109 msg: &[u8],
110 ) -> Result<Self> {
111 Self::sign_prehash(
112 signing_key,
113 namespace,
114 hash_alg,
115 hash_alg.digest(msg).as_slice(),
116 )
117 }
118
119 pub fn sign_digest<S: SigningKey, D: AssociatedHashAlg + Digest>(
121 signing_key: &S,
122 namespace: &str,
123 digest: D,
124 ) -> Result<Self> {
125 Self::sign_prehash(
126 signing_key,
127 namespace,
128 D::HASH_ALG,
129 digest.finalize().as_slice(),
130 )
131 }
132
133 pub fn sign_prehash<S: SigningKey>(
135 signing_key: &S,
136 namespace: &str,
137 hash_alg: HashAlg,
138 prehash: &[u8],
139 ) -> Result<Self> {
140 if namespace.is_empty() {
141 return Err(Error::Namespace);
142 }
143
144 if signing_key.public_key().is_sk_ed25519() {
145 return Err(Algorithm::SkEd25519.unsupported_error());
146 }
147
148 #[cfg(feature = "ecdsa")]
149 if signing_key.public_key().is_sk_ecdsa_p256() {
150 return Err(Algorithm::SkEcdsaSha2NistP256.unsupported_error());
151 }
152
153 let signed_data = Self::signed_data_for_prehash(namespace, hash_alg, prehash)?;
154 let signature = signing_key.try_sign(&signed_data)?;
155 Self::new(signing_key.public_key(), namespace, hash_alg, signature)
156 }
157
158 pub fn signed_data(namespace: &str, hash_alg: HashAlg, msg: &[u8]) -> Result<Vec<u8>> {
168 Self::signed_data_for_prehash(namespace, hash_alg, hash_alg.digest(msg).as_slice())
169 }
170
171 pub fn signed_data_for_prehash(
174 namespace: &str,
175 hash_alg: HashAlg,
176 prehash: &[u8],
177 ) -> Result<Vec<u8>> {
178 if prehash.len() != hash_alg.digest_size() {
179 return Err(Error::HashSize);
180 }
181
182 if namespace.is_empty() {
183 return Err(Error::Namespace);
184 }
185
186 SignedData {
187 namespace,
188 reserved: &[],
189 hash_alg,
190 hash: prehash,
191 }
192 .to_bytes()
193 }
194
195 pub(crate) fn verify_prehash(&self, prehash: &[u8]) -> Result<()> {
201 if prehash.len() != self.hash_alg.digest_size() {
202 return Err(Error::HashSize);
203 }
204
205 let signed_data = SignedData {
206 namespace: self.namespace.as_str(),
207 reserved: self.reserved.as_slice(),
208 hash_alg: self.hash_alg,
209 hash: prehash,
210 }
211 .to_bytes()?;
212
213 Ok(self.public_key.verify(&signed_data, &self.signature)?)
214 }
215
216 pub fn algorithm(&self) -> Algorithm {
218 self.signature.algorithm()
219 }
220
221 pub fn version(&self) -> Version {
226 self.version
227 }
228
229 pub fn public_key(&self) -> &public::KeyData {
232 &self.public_key
233 }
234
235 pub fn namespace(&self) -> &str {
243 &self.namespace
244 }
245
246 pub fn reserved(&self) -> &[u8] {
252 &self.reserved
253 }
254
255 pub fn hash_alg(&self) -> HashAlg {
263 self.hash_alg
264 }
265
266 pub fn signature(&self) -> &Signature {
268 &self.signature
269 }
270
271 pub fn signature_bytes(&self) -> &[u8] {
273 self.signature.as_bytes()
274 }
275}
276
277impl Decode for SshSig {
278 type Error = Error;
279
280 fn decode(reader: &mut impl Reader) -> Result<Self> {
281 let mut magic_preamble = [0u8; Self::MAGIC_PREAMBLE.len()];
282 reader.read(&mut magic_preamble)?;
283
284 if magic_preamble != Self::MAGIC_PREAMBLE {
285 return Err(Error::FormatEncoding);
286 }
287
288 let version = Version::decode(reader)?;
289
290 if version > Self::VERSION {
291 return Err(Error::Version { number: version });
292 }
293
294 let public_key = reader.read_prefixed(public::KeyData::decode)?;
295 let namespace = String::decode(reader)?;
296
297 if namespace.is_empty() {
298 return Err(Error::Namespace);
299 }
300
301 let reserved = Vec::decode(reader)?;
302 let hash_alg = HashAlg::decode(reader)?;
303 let signature = reader.read_prefixed(Signature::decode)?;
304
305 Ok(Self {
306 version,
307 public_key,
308 namespace,
309 reserved,
310 hash_alg,
311 signature,
312 })
313 }
314}
315
316impl Encode for SshSig {
317 fn encoded_len(&self) -> encoding::Result<usize> {
318 [
319 Self::MAGIC_PREAMBLE.len(),
320 self.version.encoded_len()?,
321 self.public_key.encoded_len_prefixed()?,
322 self.namespace.encoded_len()?,
323 self.reserved.encoded_len()?,
324 self.hash_alg.encoded_len()?,
325 self.signature.encoded_len_prefixed()?,
326 ]
327 .checked_sum()
328 }
329
330 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
331 writer.write(Self::MAGIC_PREAMBLE)?;
332 self.version.encode(writer)?;
333 self.public_key.encode_prefixed(writer)?;
334 self.namespace.encode(writer)?;
335 self.reserved.encode(writer)?;
336 self.hash_alg.encode(writer)?;
337 self.signature.encode_prefixed(writer)?;
338 Ok(())
339 }
340}
341
342impl FromStr for SshSig {
343 type Err = Error;
344
345 fn from_str(s: &str) -> Result<Self> {
346 Self::from_pem(s)
347 }
348}
349
350impl PemLabel for SshSig {
351 const PEM_LABEL: &'static str = "SSH SIGNATURE";
352}
353
354#[allow(clippy::to_string_trait_impl)]
355impl ToString for SshSig {
356 fn to_string(&self) -> String {
357 self.to_pem(LineEnding::default())
358 .expect("SSH signature encoding error")
359 }
360}
361
362#[derive(Clone, Copy, Debug, Eq, PartialEq)]
364struct SignedData<'a> {
365 namespace: &'a str,
366 reserved: &'a [u8],
367 hash_alg: HashAlg,
368 hash: &'a [u8],
369}
370
371impl SignedData<'_> {
372 fn to_bytes(self) -> Result<Vec<u8>> {
373 let mut signed_bytes = Vec::with_capacity(self.encoded_len()?);
374 self.encode(&mut signed_bytes)?;
375 Ok(signed_bytes)
376 }
377}
378
379impl Encode for SignedData<'_> {
380 fn encoded_len(&self) -> encoding::Result<usize> {
381 [
382 SshSig::MAGIC_PREAMBLE.len(),
383 self.namespace.encoded_len()?,
384 self.reserved.encoded_len()?,
385 self.hash_alg.encoded_len()?,
386 self.hash.encoded_len()?,
387 ]
388 .checked_sum()
389 }
390
391 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
392 writer.write(SshSig::MAGIC_PREAMBLE)?;
393 self.namespace.encode(writer)?;
394 self.reserved.encode(writer)?;
395 self.hash_alg.encode(writer)?;
396 self.hash.encode(writer)?;
397 Ok(())
398 }
399}
400
401#[cfg(feature = "serde")]
402impl<'de> Deserialize<'de> for SshSig {
403 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
404 where
405 D: de::Deserializer<'de>,
406 {
407 if deserializer.is_human_readable() {
408 let string = String::deserialize(deserializer)?;
409 string.parse::<SshSig>().map_err(de::Error::custom)
410 } else {
411 let bytes = Vec::<u8>::deserialize(deserializer)?;
412 Self::decode(&mut bytes.as_slice()).map_err(de::Error::custom)
413 }
414 }
415}
416
417#[cfg(feature = "serde")]
418impl Serialize for SshSig {
419 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
420 where
421 S: ser::Serializer,
422 {
423 if serializer.is_human_readable() {
424 self.to_pem(LineEnding::LF)
425 .map_err(ser::Error::custom)?
426 .serialize(serializer)
427 } else {
428 let bytes = self.encode_vec().map_err(ser::Error::custom)?;
429 bytes.serialize(serializer)
430 }
431 }
432}