CH-J Toolsupravljanje poslužiteljima preko SSH
Meni
Objavljen izvor

CH-J Tools

Pregledaj direktorije i datoteke za određeni programski izdanje.

Preuzmi ZIP izvora
CH-J / Server Manager 1704 datoteke
0.1.2-beta Dodano: · Izgrađeno:
librepgp.rs Dodano: Datum nije zabilježen 6,5 KB · 210 linije
Oznaka Preuzmi datoteku
1//! LibrePGP draft-koch-librepgp-06, not RFC 9580 V6 with a changed version.
2use super::{
3 certificate::{binding_data, certificate_data, Certificate},
4 key::{self, Key},
5 protect,
6 signature::{self, subpacket},
7 wire::*,
8};
9use crate::core::error::CoreResult;
10use pgp::types::Timestamp;
11use serde_json::{json, Value};
13pub fn expiry(created: u32, payload: &Value) -> CoreResult<Option<Vec<u8>>> {
14 let Some(v) = payload
15 .get("expiresAt")
16 .filter(|v| !v.is_null() && **v != 0)
17 else {
18 return Ok(None);
19 };
20 let at = v.as_u64().ok_or_else(invalid)?;
21 if at <= Timestamp::now().as_secs() as u64 {
22 return Err(invalid());
23 }
24 let duration = u32::try_from(at.checked_sub(created as u64).ok_or_else(invalid)?)
25 .map_err(|_| invalid())?;
26 Ok(Some(subpacket(9, &duration.to_be_bytes())?))
28pub fn hashed(key: &Key, created: u32) -> CoreResult<Vec<u8>> {
29 let mut bytes = subpacket(2, &created.to_be_bytes())?;
30 let mut issuer = vec![5];
31 issuer.extend(key.fingerprint()?);
32 bytes.extend(subpacket(33, &issuer)?);
33 Ok(bytes)
35pub fn signature(
36 key: &Key,
37 params: &Parameters,
38 typ: u8,
39 hashed: Vec<u8>,
40 data: &[u8],
41) -> CoreResult<Packet> {
42 signature::create(
43 5,
44 typ,
45 key.algorithm,
46 Timestamp::now().as_secs(),
47 &key.key_id()?,
48 hashed,
49 subpacket(16, &key.key_id()?)?,
50 data,
51 params,
52 )
54pub fn capabilities(algorithm: &str, caps: &str, primary: bool) -> CoreResult<u8> {
55 crate::core::openpgp_algorithms::validate(5, algorithm, caps)?;
56 let allowed = match algorithm {
57 "rsa3072" | "rsa4096" => {
58 if primary {
59 "CSAE"
60 } else {
61 "SAE"
62 }
63 }
64 "ed25519" => {
65 if primary {
66 "CSA"
67 } else {
68 "SA"
69 }
70 }
71 "curve25519" if !primary => "E",
72 id if crate::core::openpgp_algorithms::is_dsa(id) => {
73 if primary {
74 "CS"
75 } else {
76 "S"
77 }
78 }
79 _ => return Err(invalid()),
80 };
81 if caps.is_empty()
82 || caps.chars().any(|c| !allowed.contains(c))
83 || (primary && !caps.contains('C'))
84 {
85 return Err(invalid());
86 }
87 Ok((if caps.contains('C') { 1 } else { 0 })
88 | (if caps.contains('S') { 2 } else { 0 })
89 | (if caps.contains('A') { 32 } else { 0 })
90 | (if caps.contains('E') { 12 } else { 0 }))
92pub fn subkey(
93 primary: &Key,
94 params: &Parameters,
95 spec: &Value,
96 password: &str,
97 progress: &dyn Fn(&str) -> CoreResult<()>,
98) -> CoreResult<Vec<Packet>> {
99 let role = spec["role"].as_str().unwrap_or("sign");
100 if !["sign", "encrypt", "authenticate"].contains(&role) {
101 return Err(invalid());
102 }
103 let caps = spec["capabilities"].as_str().unwrap_or(match role {
104 "sign" => "S",
105 "authenticate" => "A",
106 _ => "E",
107 });
108 let algorithm = spec["algorithm"].as_str().unwrap_or(if role == "encrypt" {
109 "curve25519"
110 } else {
111 "ed25519"
112 });
113 let bits = capabilities(algorithm, caps, false)?;
114 let now = Timestamp::now().as_secs();
115 let expiration = expiry(now, spec)?;
116 progress("subkey")?;
117 let generated = key::generate(5, now, 0, algorithm)?;
118 let key = &generated.key;
119 let data = binding_data(primary, key)?;
120 let mut hash = hashed(primary, now)?;
121 hash.extend(subpacket(27, &[bits])?);
122 if let Some(exp) = expiration {
123 hash.extend(exp)
124 }
125 if bits & 2 != 0 {
126 let back = signature(key, &generated.parameters, 0x19, hashed(key, now)?, &data)?;
127 hash.extend(subpacket(32, &back.body)?);
128 }
129 let binding = signature(primary, params, 0x18, hash, &data)?;
130 progress("protect")?;
131 let protected = protect::seal(key, &generated.plain, password, 7)?;
132 Ok(vec![protected, binding])
134pub fn build(
135 payload: &Value,
136 uid: &str,
137 progress: &dyn Fn(&str) -> CoreResult<()>,
138) -> CoreResult<(Certificate, String)> {
139 let now = Timestamp::now().as_secs();
140 let password = payload["passphrase"].as_str().unwrap_or("");
141 let algorithm = payload["algorithm"].as_str().unwrap_or("ed25519");
142 let caps = payload["primaryCapabilities"].as_str().unwrap_or("CS");
143 let bits = capabilities(algorithm, caps, true)?;
144 let expiration = expiry(now, payload)?;
145 let specs = payload["subkeys"]
146 .as_array()
147 .cloned()
148 .unwrap_or_else(|| vec![json!({"role":"encrypt","algorithm":"curve25519"})]);
149 if specs.len() > 8 {
150 return Err(invalid());
151 }
152 for spec in &specs {
153 let role=spec["role"].as_str().unwrap_or("sign");
154 if !["sign","encrypt","authenticate"].contains(&role){return Err(invalid())}
155 let caps=spec["capabilities"].as_str().unwrap_or(match role{"encrypt"=>"E","authenticate"=>"A",_=>"S"});
156 let algorithm=spec["algorithm"].as_str().unwrap_or(if role=="encrypt"{"curve25519"}else{"ed25519"});
157 capabilities(algorithm,caps,false)?;expiry(now,spec)?;
158 }
159 progress("primary")?;
160 let generated = key::generate(5, now, 0, algorithm)?;
161 let key = &generated.key;
162 let mut hash = hashed(key, now)?;
163 hash.extend(subpacket(27, &[bits])?);
164 hash.extend(subpacket(25, &[1])?);
165 hash.extend(subpacket(11, &[9, 8, 7])?);
166 hash.extend(subpacket(21, &[10, 9, 8])?);
167 hash.extend(subpacket(22, &[2, 1, 0])?);
168 if let Some(exp) = expiration {
169 hash.extend(exp)
170 }
171 let self_sig = signature(
172 key,
173 &generated.parameters,
174 0x13,
175 hash,
176 &certificate_data(key, uid.as_bytes())?,
177 )?;
178 let mut packets = vec![
179 Packet::new(6, key.public.clone()),
180 Packet::new(13, uid.as_bytes().to_vec()),
181 self_sig,
182 ];
183 for spec in &specs {
184 packets.extend(subkey(
185 key,
186 &generated.parameters,
187 spec,
188 password,
189 progress,
190 )?);
191 }
192 progress("revocation")?;
193 let revocation = signature(
194 key,
195 &generated.parameters,
196 0x20,
197 hashed(key, now)?,
198 &key.prefix()?,
199 )?;
200 progress("protect")?;
201 packets[0] = protect::seal(key, &generated.plain, password, 5)?;
202 progress("verify")?;
203 let cert = Certificate::parse(&encode(&packets, 5)?)?;
204 if cert.metadata()?["usable"] != true {
205 return Err(invalid());
206 }
207 let mut revoked = cert.public_packets()?;
208 revoked.insert(1, revocation);
209 Ok((cert, armor("PUBLIC KEY BLOCK", &encode(&revoked, 5)?)))
SHA-256880ff87468ed7ac3850db685fd49dbe87d1812550e9ceb51ed059649b304d932

CH-J Proprietary Software License 1.14 · Izvor je osiguran pod CH-J Proprietary Software License 1.14. Njena dostupnost ne mijenja uvjete licenciranja niti daje dodatna prava.

Arhiv SHA-256ac8fe790f4ba60fc098f8c985fc2656cfcc6cdc21fb34b30e308a2b54e62258f
Datoteke