CH-J Toolsserverhåndtering over SSH
Menu
Offentliggjort kilde

CH-J Tools

Gennemse mapper og filer til en specifik applikationsudgivelse.

Download kilde ZIP
CH-J / Server Manager 1704 filer
0.1.2-beta Tilføjet: · Bygget:
signature.rs Tilføjet: Dato ikke registreret 7,0 KB · 218 linjer
Kode Download fil
1//! The signature formats are protocol data, not alternate crypto primitives.
2use super::wire::*;
3use crate::core::error::CoreResult;
4use pgp::types::KeyDetails;
6#[derive(Clone)]
7pub struct Signature {
8 pub version: u8,
9 pub typ: u8,
10 pub algorithm: u8,
11 pub hash_algorithm: u8,
12 pub created: u32,
13 pub hashed: Vec<u8>,
14 pub digest_prefix: [u8; 2],
15 pub value: Vec<u8>,
16 pub head: Vec<u8>,
18pub fn subpacket(typ: u8, data: &[u8]) -> CoreResult<Vec<u8>> {
19 let mut v = Vec::new();
20 write_len(&mut v, data.len() + 1)?;
21 v.push(typ);
22 v.extend(data);
23 Ok(v)
25pub fn subpackets(data: &[u8]) -> CoreResult<Vec<(u8, &[u8])>> {
26 let mut r = Reader::new(data);
27 let mut out = Vec::new();
28 while !r.rest().is_empty() {
29 if out.len() >= 128 {
30 return Err(invalid());
31 }
32 let n = packet_len(&mut r)?;
33 let typ = r.u8()?;
34 if n == 0 {
35 return Err(invalid());
36 }
37 out.push((typ, r.take(n - 1)?));
38 }
39 Ok(out)
41impl Signature {
42 pub fn parse(bytes: &[u8]) -> CoreResult<Self> {
43 let mut r = Reader::new(bytes);
44 let version = r.u8()?;
45 let (typ, algorithm, hash_algorithm, created, hashed, _unhashed, head) = if version <= 3 {
46 if ![2, 3].contains(&version) || r.u8()? != 5 {
47 return Err(invalid());
48 }
49 let typ = r.u8()?;
50 let created = r.u32()?;
51 r.take(8)?;
52 let alg = r.u8()?;
53 let hash = r.u8()?;
54 (
55 typ,
56 alg,
57 hash,
58 created,
59 Vec::new(),
60 Vec::new(),
61 bytes[2..7].to_vec(),
62 )
63 } else if version == 5 {
64 let typ = r.u8()?;
65 let alg = r.u8()?;
66 let hash = r.u8()?;
67 let n = r.u16()? as usize;
68 let hashed = r.take(n)?.to_vec();
69 let head = bytes[..r.pos].to_vec();
70 let n = r.u16()? as usize;
71 let unhashed = r.take(n)?.to_vec();
72 let packets = subpackets(&hashed)?;
73 let created = packets
74 .iter()
75 .rev()
76 .find_map(|(t, b)| {
77 (*t & 127 == 2 && b.len() == 4)
78 .then(|| u32::from_be_bytes((*b).try_into().unwrap_or([0; 4])))
79 })
80 .ok_or_else(invalid)?;
81 subpackets(&unhashed)?;
82 (typ, alg, hash, created, hashed, unhashed, head)
83 } else {
84 return Err(invalid());
85 };
86 if ![1, 3, 17, 19, 22].contains(&algorithm)
87 || (version == 5
88 && ![8, 9, 10, 11].contains(&hash_algorithm)
89 && !(algorithm == 17 && hash_algorithm == 2))
90 {
91 return Err(invalid());
92 }
93 let digest_prefix = r.take(2)?.try_into().map_err(|_| invalid())?;
94 let value = r.rest().to_vec();
95 if value.is_empty() {
96 return Err(invalid());
97 }
98 Ok(Self {
99 version,
100 typ,
101 algorithm,
102 hash_algorithm,
103 created,
104 hashed,
105 digest_prefix,
106 value,
107 head,
108 })
109 }
110 pub fn digest(&self, data: &[u8]) -> CoreResult<Vec<u8>> {
111 if self.version <= 3 {
112 return hash(self.hash_algorithm, &[data, &self.head]);
113 }
114 let mut trailer = vec![5, 255];
115 trailer.extend((self.head.len() as u64).to_be_bytes());
116 if [0, 1].contains(&self.typ) {
117 hash(self.hash_algorithm, &[data, &self.head, &[0; 6], &trailer])
118 } else {
119 hash(self.hash_algorithm, &[data, &self.head, &trailer])
120 }
121 }
122 pub fn verify(&self, params: &Parameters, data: &[u8]) -> CoreResult<()> {
123 // Unknown critical subpackets must never grant capabilities or authorize signing.
124 if subpackets(&self.hashed)?.iter().any(|(t, _)| {
125 t & 128 != 0 && ![2, 3, 9, 11, 16, 21, 22, 25, 27, 29, 30, 32, 33].contains(&(t & 127))
126 }) {
127 return Err(invalid());
128 }
129 for (typ, bytes) in subpackets(&self.hashed)? {
130 let valid = match typ & 127 {
131 2 | 3 | 9 => bytes.len() == 4,
132 16 => bytes.len() == 8,
133 25 => bytes.len() == 1,
134 27 => !bytes.is_empty(),
135 33 => bytes.len() == 33 && bytes[0] == 5,
136 32 => !bytes.is_empty(),
137 _ => true,
138 };
139 if !valid {
140 return Err(invalid());
141 }
142 }
143 let digest = self.digest(data)?;
144 if digest[..2] != self.digest_prefix {
145 return Err(invalid());
146 }
147 params.verify(self.hash_algorithm, &digest, self.algorithm, &self.value)
148 }
149 pub fn field(&self, typ: u8) -> Option<&[u8]> {
150 subpackets(&self.hashed)
151 .ok()?
152 .into_iter()
153 .rev()
154 .find_map(|(t, b)| (t & 127 == typ).then_some(b))
155 }
156 pub fn duration(&self, typ: u8) -> Option<u32> {
157 self.field(typ)
158 .filter(|b| b.len() == 4)
159 .map(|b| u32::from_be_bytes(b.try_into().unwrap_or([0; 4])))
160 }
161 pub fn current(&self, now: u32) -> bool {
162 self.created <= now.saturating_add(300)
163 && self
164 .duration(3)
165 .is_none_or(|duration| duration == 0 || self.created.saturating_add(duration) > now)
166 }
168pub fn create(
169 version: u8,
170 typ: u8,
171 algorithm: u8,
172 created: u32,
173 key_id: &[u8],
174 hashed: Vec<u8>,
175 unhashed: Vec<u8>,
176 data: &[u8],
177 params: &Parameters,
178) -> CoreResult<Packet> {
179 let hash_algorithm = if version <= 3 {
180 1
181 } else if algorithm == 17 {
182 crate::core::openpgp_algorithms::signing_hash(params.public.public_params()).into()
183 } else if algorithm == 22 {
184 10
185 } else {
186 8
187 };
188 let mut body = vec![version];
189 if version <= 3 {
190 if key_id.len() != 8 {
191 return Err(invalid());
192 }
193 body.push(5);
194 body.push(typ);
195 body.extend(created.to_be_bytes());
196 body.extend(key_id);
197 body.extend([algorithm, hash_algorithm]);
198 } else {
199 if version != 5 || hashed.len() > u16::MAX as usize || unhashed.len() > u16::MAX as usize {
200 return Err(invalid());
201 }
202 body.extend([typ, algorithm, hash_algorithm]);
203 body.extend((hashed.len() as u16).to_be_bytes());
204 body.extend(&hashed);
205 body.extend((unhashed.len() as u16).to_be_bytes());
206 body.extend(&unhashed);
207 }
208 // Parse the framing first so generation and verification share the exact spec trailer.
209 let mut framing = body.clone();
210 framing.extend([0, 0, 0]);
211 let signature = Signature::parse(&framing)?;
212 let digest = signature.digest(data)?;
213 body.extend(&digest[..2]);
214 body.extend(params.sign(hash_algorithm, &digest)?);
215 let packet = Packet::new(2, body);
216 Signature::parse(&packet.body)?.verify(params, data)?;
217 Ok(packet)
SHA-2562598e9b9899a7634df092ab555d31e12c4ecd7117d4405fe01d77454374917fd

CH-J Proprietary Software License 1.14 · Kilden leveres under CH-J Proprietary Software License 1.14. Dens tilgængelighed ændrer ikke licensbetingelserne eller giver yderligere rettigheder.

Arkiv SHA-256ac8fe790f4ba60fc098f8c985fc2656cfcc6cdc21fb34b30e308a2b54e62258f
Filer