1use std::fmt::Display;
2
3use crate::{
4 errors::Result, signature::Signature, SError, ALG_SIZE, COMPONENT_SIZE, KEY_SIG_ALG, KID_SIZE,
5};
6use base64::Engine;
7use ed25519_dalek::ed25519::{self, ComponentBytes};
8#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct PublicKeyBox<'s> {
13 pub(crate) untrusted_comment: Option<&'s str>,
14 pub(crate) public_key: PublicKey,
15}
16
17impl<'s> PublicKeyBox<'s> {
18 pub(crate) fn new(untrusted_comment: Option<&'s str>, public_key: PublicKey) -> Self {
19 Self {
20 untrusted_comment,
21 public_key,
22 }
23 }
24 pub fn from_verifying_key(
25 key: ed25519_dalek::VerifyingKey,
26 key_id: &[u8; 8],
27 untrusted_comment: Option<&'s str>,
28 ) -> Result<Self> {
29 let pk = RawPk::new(key.to_bytes());
30 let public_key = PublicKey::new(KEY_SIG_ALG, *key_id, pk);
31 Ok(Self::new(untrusted_comment, public_key))
32 }
33 #[allow(clippy::should_implement_trait)]
37 pub fn from_str(s: &'s str) -> Result<Self> {
38 parse_public_key(s)
39 }
40 pub fn from_raw_str(s: &'s str) -> Result<Self> {
43 let public_key = s.trim();
44 let decoder = base64::engine::general_purpose::STANDARD;
45 let pk_format = decoder
46 .decode(public_key.as_bytes())
47 .map_err(|e| SError::new(crate::ErrorKind::PublicKey, e))?;
48 if pk_format.len() != ALG_SIZE + KID_SIZE + COMPONENT_SIZE {
49 return Err(SError::new(
50 crate::ErrorKind::PublicKey,
51 "invalid public key length",
52 ));
53 }
54 let pk_sig_alg = &pk_format[..ALG_SIZE];
55 let pk_key_id = &pk_format[ALG_SIZE..ALG_SIZE + KID_SIZE];
56 let pk_key = &pk_format[ALG_SIZE + KID_SIZE..];
57 let pk = RawPk::new(pk_key.try_into().unwrap());
58 let public_key = PublicKey::new(
59 pk_sig_alg.try_into().unwrap(),
60 pk_key_id.try_into().unwrap(),
61 pk,
62 );
63 Ok(PublicKeyBox::new(None, public_key))
64 }
65 pub fn untrusted_comment(&self) -> Option<&'s str> {
67 self.untrusted_comment
68 }
69 pub(crate) fn verify(
70 &self,
71 msg: &[u8],
72 sig: &Signature,
73 trusted_comment: Option<&str>,
74 ) -> Result<bool> {
75 if !(self.public_key.key.verify(msg, &sig.sig)?) {
76 return Err(SError::new(
77 crate::ErrorKind::PublicKey,
78 "verify sig failed",
79 ));
80 }
81 let mut global_data = vec![];
82 global_data.extend_from_slice(&sig.sig.to_bytes());
83 global_data.extend_from_slice(trusted_comment.unwrap_or("").as_bytes());
84 if !(self.public_key.key.verify(&global_data, &sig.global_sig)?) {
85 return Err(SError::new(
86 crate::ErrorKind::PublicKey,
87 "verify global sig failed",
88 ));
89 }
90 Ok(true)
91 }
92 pub(crate) fn self_verify(&self) -> Result<bool> {
93 if self.public_key.sig_alg != KEY_SIG_ALG {
94 return Err(SError::new(
95 crate::ErrorKind::PublicKey,
96 "invalid public key signature algorithm",
97 ));
98 }
99 Ok(true)
100 }
101}
102impl Display for PublicKeyBox<'_> {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 let mut s = String::new();
105 s.push_str("untrusted comment: ");
106 if let Some(c) = self.untrusted_comment {
107 s.push_str(c);
108 }
109 s.push('\n');
110 let encoder = base64::engine::general_purpose::STANDARD;
111 let mut pk_format = vec![];
112 pk_format.extend_from_slice(&self.public_key.sig_alg);
113 pk_format.extend_from_slice(&self.public_key.key_id);
114 pk_format.extend_from_slice(&self.public_key.key.0);
115 let pk = encoder.encode(&pk_format);
116 s.push_str(&pk);
117 s.push('\n');
118 write!(f, "{}", s)
119 }
120}
121fn parse_raw_public_key(public_key: &str) -> Result<PublicKey> {
122 let decoder = base64::engine::general_purpose::STANDARD;
123 let pk_format = decoder
124 .decode(public_key.as_bytes())
125 .map_err(|e| SError::new(crate::ErrorKind::PublicKey, e))?;
126 if pk_format.len() != ALG_SIZE + KID_SIZE + COMPONENT_SIZE {
127 return Err(SError::new(
128 crate::ErrorKind::PublicKey,
129 "invalid public key length",
130 ));
131 }
132 let pk_sig_alg = &pk_format[..ALG_SIZE];
133 let pk_key_id = &pk_format[ALG_SIZE..ALG_SIZE + KID_SIZE];
134 let pk_key = &pk_format[ALG_SIZE + KID_SIZE..];
135 let pk = RawPk::new(pk_key.try_into().unwrap());
136 let public_key = PublicKey::new(
137 pk_sig_alg.try_into().unwrap(),
138 pk_key_id.try_into().unwrap(),
139 pk,
140 );
141 Ok(public_key)
142}
143fn parse_public_key(s: &str) -> Result<PublicKeyBox> {
144 let mut lines = s.lines();
145 if let Some(c) = lines.next() {
146 let untrusted_comment = c.strip_prefix("untrusted comment: ");
147 let public_key = lines
148 .next()
149 .ok_or_else(|| SError::new(crate::ErrorKind::PublicKey, "missing public key"))?;
150 Ok(PublicKeyBox::new(
151 untrusted_comment,
152 parse_raw_public_key(public_key)?,
153 ))
154 } else {
155 Err(SError::new(crate::ErrorKind::PublicKey, "empty public key"))
156 }
157}
158#[cfg(test)]
159#[test]
160fn test_parse_public_key() {
161 use crate::KeyPairBox;
162 let password = b"password";
163 let k = KeyPairBox::generate(Some(password), None, None).unwrap();
164 let file = k.public_key_box.to_string();
165 let pk = parse_public_key(&file).unwrap();
166 assert_eq!(file, pk.to_string());
167}
168#[derive(Clone, Debug, PartialEq, Eq)]
170pub(crate) struct PublicKey {
171 pub sig_alg: [u8; 2],
172 pub key_id: [u8; 8],
173 pub key: RawPk,
174}
175impl PublicKey {
176 pub fn new(sig_alg: [u8; 2], key_id: [u8; 8], key: RawPk) -> Self {
177 Self {
178 sig_alg,
179 key_id,
180 key,
181 }
182 }
183}
184#[derive(Clone, Debug, PartialEq, Eq)]
185pub(crate) struct RawPk(pub ComponentBytes);
186impl RawPk {
187 pub fn new(key: ComponentBytes) -> Self {
188 Self(key)
189 }
190 pub fn verify(&self, msg: &[u8], sig: &ed25519::Signature) -> Result<bool> {
191 let pk = ed25519_dalek::VerifyingKey::from_bytes(&self.0)?;
192 Ok(pk.verify_strict(msg, sig).map(|_| true)?)
193 }
194}