1use std::{fmt::Display, io::Read};
2
3use crate::{
4 errors::Result, prehash, signature::Signature, ErrorKind, SError, SignatureBox, ALG_SIZE,
5 COMPONENT_SIZE, KEY_SIG_ALG, KID_SIZE,
6};
7use base64::Engine;
8use ed25519_dalek::ed25519::{self, ComponentBytes};
9#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct PublicKeyBox<'s> {
14 pub(crate) untrusted_comment: Option<&'s str>,
15 pub(crate) public_key: PublicKey,
16}
17
18impl<'s> PublicKeyBox<'s> {
19 pub(crate) fn new(untrusted_comment: Option<&'s str>, public_key: PublicKey) -> Self {
20 Self {
21 untrusted_comment,
22 public_key,
23 }
24 }
25 pub fn from_verifying_key(
26 key: ed25519_dalek::VerifyingKey,
27 key_id: &[u8; 8],
28 untrusted_comment: Option<&'s str>,
29 ) -> Result<Self> {
30 let pk = RawPk::new(key.to_bytes());
31 let public_key = PublicKey::new(KEY_SIG_ALG, *key_id, pk);
32 Ok(Self::new(untrusted_comment, public_key))
33 }
34 #[allow(clippy::should_implement_trait)]
38 pub fn from_str(s: &'s str) -> Result<Self> {
39 parse_public_key(s)
40 }
41 pub fn from_raw_str(s: &'s str) -> Result<Self> {
44 let public_key = s.trim();
45 let decoder = base64::engine::general_purpose::STANDARD;
46 let pk_format = decoder
47 .decode(public_key.as_bytes())
48 .map_err(|e| SError::new(crate::ErrorKind::PublicKey, e))?;
49 if pk_format.len() != ALG_SIZE + KID_SIZE + COMPONENT_SIZE {
50 return Err(SError::new(
51 crate::ErrorKind::PublicKey,
52 "invalid public key length",
53 ));
54 }
55 let pk_sig_alg = &pk_format[..ALG_SIZE];
56 let pk_key_id = &pk_format[ALG_SIZE..ALG_SIZE + KID_SIZE];
57 let pk_key = &pk_format[ALG_SIZE + KID_SIZE..];
58 let pk = RawPk::new(pk_key.try_into().unwrap());
59 let public_key = PublicKey::new(
60 pk_sig_alg.try_into().unwrap(),
61 pk_key_id.try_into().unwrap(),
62 pk,
63 );
64 Ok(PublicKeyBox::new(None, public_key))
65 }
66 pub fn untrusted_comment(&self) -> Option<&'s str> {
68 self.untrusted_comment
69 }
70 pub(crate) fn verify_mini(
71 &self,
72 msg: &[u8],
73 sig: &Signature,
74 trusted_comment: Option<&str>,
75 ) -> Result<bool> {
76 if !(self.public_key.key.verify(msg, &sig.sig)?) {
77 return Err(SError::new(
78 crate::ErrorKind::PublicKey,
79 "verify sig failed",
80 ));
81 }
82 let mut global_data = vec![];
83 global_data.extend_from_slice(&sig.sig.to_bytes());
84 global_data.extend_from_slice(trusted_comment.unwrap_or("").as_bytes());
85 if !(self.public_key.key.verify(&global_data, &sig.global_sig)?) {
86 return Err(SError::new(
87 crate::ErrorKind::PublicKey,
88 "verify global sig failed",
89 ));
90 }
91 Ok(true)
92 }
93 pub(crate) fn self_verify(&self) -> Result<bool> {
94 if self.public_key.sig_alg != KEY_SIG_ALG {
95 return Err(SError::new(
96 crate::ErrorKind::PublicKey,
97 "invalid public key signature algorithm",
98 ));
99 }
100 Ok(true)
101 }
102 pub fn key_id(&self) -> &[u8; 8] {
104 &self.public_key.key_id
105 }
106 pub fn sig_alg(&self) -> &[u8; 2] {
108 &self.public_key.sig_alg
109 }
110 pub fn verify<R>(&self, signature_box: &SignatureBox, mut data_reader: R) -> Result<bool>
122 where
123 R: Read,
124 {
125 let prehashed = prehash(&mut data_reader)?;
126 verify_prehashed(self, signature_box, &prehashed)
127 }
128}
129pub(crate) fn verify_prehashed(
130 pk: &PublicKeyBox,
131 signature_box: &SignatureBox,
132 prehashed: &[u8],
133) -> Result<bool> {
134 if !signature_box.is_prehashed() {
135 return Err(SError::new(
136 ErrorKind::PrehashedMismatch,
137 "SignatureBox is not prehashed",
138 ));
139 }
140 if !pk.self_verify()? {
141 return Err(SError::new(
142 ErrorKind::PublicKey,
143 "public key self verification failed",
144 ));
145 }
146 if pk.public_key.key_id != *signature_box.key_id() {
147 return Err(SError::new(
148 ErrorKind::PublicKey,
149 "public key key_id mismatch",
150 ));
151 }
152 pk.verify_mini(
153 prehashed,
154 &signature_box.signature,
155 signature_box.trusted_comment(),
156 )
157}
158
159impl Display for PublicKeyBox<'_> {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 let mut s = String::new();
162 s.push_str("untrusted comment: ");
163 if let Some(c) = self.untrusted_comment {
164 s.push_str(c);
165 }
166 s.push('\n');
167 let encoder = base64::engine::general_purpose::STANDARD;
168 let mut pk_format = vec![];
169 pk_format.extend_from_slice(&self.public_key.sig_alg);
170 pk_format.extend_from_slice(&self.public_key.key_id);
171 pk_format.extend_from_slice(&self.public_key.key.0);
172 let pk = encoder.encode(&pk_format);
173 s.push_str(&pk);
174 s.push('\n');
175 write!(f, "{}", s)
176 }
177}
178fn parse_raw_public_key(public_key: &str) -> Result<PublicKey> {
179 let decoder = base64::engine::general_purpose::STANDARD;
180 let pk_format = decoder
181 .decode(public_key.as_bytes())
182 .map_err(|e| SError::new(crate::ErrorKind::PublicKey, e))?;
183 if pk_format.len() != ALG_SIZE + KID_SIZE + COMPONENT_SIZE {
184 return Err(SError::new(
185 crate::ErrorKind::PublicKey,
186 "invalid public key length",
187 ));
188 }
189 let pk_sig_alg = &pk_format[..ALG_SIZE];
190 let pk_key_id = &pk_format[ALG_SIZE..ALG_SIZE + KID_SIZE];
191 let pk_key = &pk_format[ALG_SIZE + KID_SIZE..];
192 let pk = RawPk::new(pk_key.try_into().unwrap());
193 let public_key = PublicKey::new(
194 pk_sig_alg.try_into().unwrap(),
195 pk_key_id.try_into().unwrap(),
196 pk,
197 );
198 Ok(public_key)
199}
200fn parse_public_key(s: &str) -> Result<PublicKeyBox<'_>> {
201 let mut lines = s.lines();
202 if let Some(c) = lines.next() {
203 let untrusted_comment = c.strip_prefix("untrusted comment: ");
204 let public_key = lines
205 .next()
206 .ok_or_else(|| SError::new(crate::ErrorKind::PublicKey, "missing public key"))?;
207 Ok(PublicKeyBox::new(
208 untrusted_comment,
209 parse_raw_public_key(public_key)?,
210 ))
211 } else {
212 Err(SError::new(crate::ErrorKind::PublicKey, "empty public key"))
213 }
214}
215#[cfg(test)]
216#[test]
217fn test_parse_public_key() {
218 use crate::KeyPairBox;
219 let password = b"password";
220 let k = KeyPairBox::generate(Some(password), None, None).unwrap();
221 let file = k.public_key_box.to_string();
222 let pk = parse_public_key(&file).unwrap();
223 assert_eq!(file, pk.to_string());
224}
225#[derive(Clone, Debug, PartialEq, Eq)]
227pub(crate) struct PublicKey {
228 pub sig_alg: [u8; 2],
229 pub key_id: [u8; 8],
230 pub key: RawPk,
231}
232impl PublicKey {
233 pub fn new(sig_alg: [u8; 2], key_id: [u8; 8], key: RawPk) -> Self {
234 Self {
235 sig_alg,
236 key_id,
237 key,
238 }
239 }
240}
241#[derive(Clone, Debug, PartialEq, Eq)]
242pub(crate) struct RawPk(pub ComponentBytes);
243impl RawPk {
244 pub fn new(key: ComponentBytes) -> Self {
245 Self(key)
246 }
247 pub fn verify(&self, msg: &[u8], sig: &ed25519::Signature) -> Result<bool> {
248 let pk = ed25519_dalek::VerifyingKey::from_bytes(&self.0)?;
249 Ok(pk.verify_strict(msg, sig).map(|_| true)?)
250 }
251}