sequoia_openpgp/packet/signature/
v6.rs1use std::cmp::Ordering;
4use std::convert::TryFrom;
5use std::fmt;
6use std::ops::{Deref, DerefMut};
7
8use crate::{
9 Error,
10 HashAlgorithm,
11 Packet,
12 PublicKeyAlgorithm,
13 Result,
14 SignatureType,
15 crypto::mpi,
16 packet::{
17 Signature,
18 signature::{
19 Signature4,
20 subpacket::{
21 SubpacketArea,
22 },
23 },
24 },
25};
26
27#[derive(Clone)]
38pub struct Signature6 {
39 pub(crate) common: Signature4,
40 salt: Vec<u8>,
41}
42assert_send_and_sync!(Signature6);
43
44impl TryFrom<Signature> for Signature6 {
45 type Error = anyhow::Error;
46
47 fn try_from(sig: Signature) -> Result<Self> {
48 match sig {
49 Signature::V6(sig) => Ok(sig),
50 sig => Err(
51 Error::InvalidArgument(
52 format!(
53 "Got a v{}, require a v6 signature",
54 sig.version()))
55 .into()),
56 }
57 }
58}
59
60impl Deref for Signature6 {
64 type Target = Signature4;
65
66 fn deref(&self) -> &Self::Target {
67 &self.common
68 }
69}
70
71impl DerefMut for Signature6 {
72 fn deref_mut(&mut self) -> &mut Self::Target {
73 &mut self.common
74 }
75}
76
77impl fmt::Debug for Signature6 {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 f.debug_struct("Signature6")
80 .field("version", &self.version())
81 .field("typ", &self.typ())
82 .field("pk_algo", &self.pk_algo())
83 .field("hash_algo", &self.hash_algo())
84 .field("hashed_area", self.hashed_area())
85 .field("unhashed_area", self.unhashed_area())
86 .field("additional_issuers", &self.additional_issuers)
87 .field("digest_prefix",
88 &crate::fmt::to_hex(&self.digest_prefix, false))
89 .field("salt", &crate::fmt::hex::encode(&self.salt))
90 .field(
91 "computed_digest",
92 &self
93 .computed_digest
94 .get()
95 .map(|hash| crate::fmt::to_hex(&hash[..], false)),
96 )
97 .field("level", &self.level)
98 .field("mpis", &self.mpis)
99 .finish()
100 }
101}
102
103impl PartialEq for Signature6 {
104 fn eq(&self, other: &Signature6) -> bool {
114 self.cmp(other) == Ordering::Equal
115 }
116}
117
118impl Eq for Signature6 {}
119
120impl PartialOrd for Signature6 {
121 fn partial_cmp(&self, other: &Signature6) -> Option<Ordering> {
122 Some(self.cmp(other))
123 }
124}
125
126impl Ord for Signature6 {
127 fn cmp(&self, other: &Signature6) -> Ordering {
128 self.common.cmp(&other.common)
129 .then_with(|| self.salt.cmp(&other.salt))
130 }
131}
132
133impl std::hash::Hash for Signature6 {
134 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
135 use std::hash::Hash as StdHash;
136 StdHash::hash(&self.common, state);
137 StdHash::hash(&self.salt, state);
138 }
139}
140
141impl Signature6 {
142 pub(crate) fn from_common(mut common: Signature4, salt: Vec<u8>)
144 -> Result<Self>
145 {
146 common.fields.version = 6;
147 Ok(Signature6 { common, salt })
148 }
149
150 pub fn new(typ: SignatureType, pk_algo: PublicKeyAlgorithm,
157 hash_algo: HashAlgorithm, hashed_area: SubpacketArea,
158 unhashed_area: SubpacketArea,
159 digest_prefix: [u8; 2],
160 salt: Vec<u8>,
161 mpis: mpi::Signature) -> Result<Self> {
162 Signature6::from_common(
163 Signature4::new(typ, pk_algo, hash_algo,
164 hashed_area, unhashed_area,
165 digest_prefix, mpis),
166 salt)
167 }
168
169 pub fn pk_algo(&self) -> PublicKeyAlgorithm {
174 self.fields.pk_algo()
175 }
176
177 pub fn digest_prefix(&self) -> &[u8; 2] {
179 &self.digest_prefix
180 }
181
182 #[allow(dead_code)]
184 pub(crate) fn set_digest_prefix(&mut self, prefix: [u8; 2]) -> [u8; 2] {
185 ::std::mem::replace(&mut self.digest_prefix, prefix)
186 }
187
188 pub fn salt(&self) -> &[u8] {
190 &self.salt
191 }
192
193 #[allow(dead_code)]
195 pub(crate) fn set_salt(&mut self, salt: Vec<u8>) -> Vec<u8> {
196 ::std::mem::replace(&mut self.salt, salt)
197 }
198
199 pub fn mpis(&self) -> &mpi::Signature {
201 &self.mpis
202 }
203
204 #[allow(dead_code)]
206 pub(crate) fn set_mpis(&mut self, mpis: mpi::Signature) -> mpi::Signature
207 {
208 ::std::mem::replace(&mut self.mpis, mpis)
209 }
210
211 pub fn computed_digest(&self) -> Option<&[u8]> {
217 self.computed_digest.get().map(|d| &d[..])
218 }
219
220 pub fn level(&self) -> usize {
226 self.level
227 }
228
229 pub fn exportable(&self) -> Result<()> {
239 if ! self.exportable_certification().unwrap_or(true) {
240 return Err(Error::InvalidOperation(
241 "Cannot export non-exportable certification".into()).into());
242 }
243
244 if self.revocation_keys().any(|r| r.sensitive()) {
245 return Err(Error::InvalidOperation(
246 "Cannot export signature with sensitive designated revoker"
247 .into()).into());
248 }
249
250 Ok(())
251 }
252}
253
254impl From<Signature6> for Packet {
255 fn from(s: Signature6) -> Self {
256 Packet::Signature(s.into())
257 }
258}
259
260impl From<Signature6> for super::Signature {
261 fn from(s: Signature6) -> Self {
262 super::Signature::V6(s)
263 }
264}
265
266#[cfg(test)]
267use quickcheck::{Arbitrary, Gen};
268#[cfg(test)]
269use crate::packet::signature::ArbitraryBounded;
270
271#[cfg(test)]
272impl ArbitraryBounded for Signature6 {
273 fn arbitrary_bounded(g: &mut Gen, depth: usize) -> Self {
274 let common = Signature4::arbitrary_bounded(g, depth);
275 let salt_size = common.hash_algo().salt_size().unwrap_or(16);
276 let mut salt = vec![0u8; salt_size];
277 salt.iter_mut().for_each(|p| *p = u8::arbitrary(g));
278 Self::from_common(common, salt)
279 .expect("salt has the right size")
280 }
281}
282
283#[cfg(test)]
284impl_arbitrary_with_bound!(Signature6);