Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2017-2024 [Ribose Inc](https://www.ribose.com). |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without modification, |
6 | | * are permitted provided that the following conditions are met: |
7 | | * |
8 | | * 1. Redistributions of source code must retain the above copyright notice, |
9 | | * this list of conditions and the following disclaimer. |
10 | | * |
11 | | * 2. Redistributions in binary form must reproduce the above copyright notice, |
12 | | * this list of conditions and the following disclaimer in the documentation |
13 | | * and/or other materials provided with the distribution. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
16 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
17 | | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
18 | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
19 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
21 | | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
22 | | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
23 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
24 | | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | */ |
26 | | |
27 | | #include "key.hpp" |
28 | | #include "utils.h" |
29 | | #include <librekey/key_store_g10.h> |
30 | | #include "crypto/s2k.h" |
31 | | #include "crypto/mem.h" |
32 | | #include "crypto/signatures.h" |
33 | | #include "keygen.hpp" |
34 | | |
35 | | #include <librepgp/stream-packet.h> |
36 | | #include <librepgp/stream-key.h> |
37 | | #include <librepgp/stream-sig.h> |
38 | | #include <librepgp/stream-armor.h> |
39 | | |
40 | | #include <stdio.h> |
41 | | #include <string.h> |
42 | | #include <stdlib.h> |
43 | | #include <cassert> |
44 | | #include <time.h> |
45 | | #include <algorithm> |
46 | | #include <stdexcept> |
47 | | #include "defaults.h" |
48 | | |
49 | | void |
50 | | pgp_validity_t::mark_valid() |
51 | 0 | { |
52 | 0 | validated = true; |
53 | 0 | valid = true; |
54 | 0 | expired = false; |
55 | 0 | } |
56 | | |
57 | | void |
58 | | pgp_validity_t::reset() |
59 | 234 | { |
60 | 234 | validated = false; |
61 | 234 | valid = false; |
62 | 234 | expired = false; |
63 | 234 | } |
64 | | |
65 | | namespace rnp { |
66 | | |
67 | | pgp_key_pkt_t * |
68 | | pgp_decrypt_seckey_pgp(const RawPacket &raw, const pgp_key_pkt_t &pubkey, const char *password) |
69 | 0 | { |
70 | 0 | try { |
71 | 0 | MemorySource src(raw.data()); |
72 | 0 | auto res = std::unique_ptr<pgp_key_pkt_t>(new pgp_key_pkt_t()); |
73 | 0 | if (res->parse(src.src()) || decrypt_secret_key(res.get(), password)) { |
74 | 0 | return NULL; |
75 | 0 | } |
76 | 0 | return res.release(); |
77 | 0 | } catch (const std::exception &e) { |
78 | 0 | RNP_LOG("%s", e.what()); |
79 | 0 | return NULL; |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | | /* Note that this function essentially serves two purposes. |
84 | | * - In the case of a protected key, it requests a password and |
85 | | * uses it to decrypt the key and fill in key->key.seckey. |
86 | | * - In the case of an unprotected key, it simply re-loads |
87 | | * key->key.seckey by parsing the key data in packets[0]. |
88 | | */ |
89 | | pgp_key_pkt_t * |
90 | | pgp_decrypt_seckey(const Key & key, |
91 | | const pgp_password_provider_t &provider, |
92 | | const pgp_password_ctx_t & ctx) |
93 | 0 | { |
94 | | // sanity checks |
95 | 0 | if (!key.is_secret()) { |
96 | 0 | RNP_LOG("invalid args"); |
97 | 0 | return NULL; |
98 | 0 | } |
99 | | // ask the provider for a password |
100 | 0 | secure_array<char, MAX_PASSWORD_LENGTH> password; |
101 | 0 | if (key.is_protected() && |
102 | 0 | !pgp_request_password(&provider, &ctx, password.data(), password.size())) { |
103 | 0 | return NULL; |
104 | 0 | } |
105 | | // attempt to decrypt with the provided password |
106 | 0 | switch (key.format) { |
107 | 0 | case KeyFormat::GPG: |
108 | 0 | case KeyFormat::KBX: |
109 | 0 | return pgp_decrypt_seckey_pgp(key.rawpkt(), key.pkt(), password.data()); |
110 | 0 | case KeyFormat::G10: |
111 | 0 | return g10_decrypt_seckey(key.rawpkt(), key.pkt(), password.data()); |
112 | 0 | default: |
113 | 0 | RNP_LOG("unexpected format: %d", static_cast<int>(key.format)); |
114 | 0 | return NULL; |
115 | 0 | } |
116 | 0 | } |
117 | | |
118 | | bool |
119 | | Key::write_sec_pgp(pgp_dest_t & dst, |
120 | | pgp_key_pkt_t & seckey, |
121 | | const std::string &password, |
122 | | RNG & rng) |
123 | 0 | { |
124 | 0 | bool res = false; |
125 | 0 | pgp_pkt_type_t oldtag = seckey.tag; |
126 | |
|
127 | 0 | seckey.tag = type(); |
128 | 0 | if (encrypt_secret_key(&seckey, password.c_str(), rng)) { |
129 | 0 | goto done; |
130 | 0 | } |
131 | 0 | try { |
132 | 0 | seckey.write(dst); |
133 | 0 | res = !dst.werr; |
134 | 0 | } catch (const std::exception &e) { |
135 | 0 | RNP_LOG("%s", e.what()); |
136 | 0 | } |
137 | 0 | done: |
138 | 0 | seckey.tag = oldtag; |
139 | 0 | return res; |
140 | 0 | } |
141 | | |
142 | | bool |
143 | | Key::write_sec_rawpkt(pgp_key_pkt_t &seckey, const std::string &password, SecurityContext &ctx) |
144 | 0 | { |
145 | | // encrypt+write the key in the appropriate format |
146 | 0 | try { |
147 | 0 | MemoryDest memdst; |
148 | 0 | switch (format) { |
149 | 0 | case KeyFormat::GPG: |
150 | 0 | case KeyFormat::KBX: |
151 | 0 | if (!write_sec_pgp(memdst.dst(), seckey, password, ctx.rng)) { |
152 | 0 | RNP_LOG("failed to write secret key"); |
153 | 0 | return false; |
154 | 0 | } |
155 | 0 | break; |
156 | 0 | case KeyFormat::G10: |
157 | 0 | if (!g10_write_seckey(&memdst.dst(), &seckey, password.c_str(), ctx)) { |
158 | 0 | RNP_LOG("failed to write g10 secret key"); |
159 | 0 | return false; |
160 | 0 | } |
161 | 0 | break; |
162 | 0 | default: |
163 | 0 | RNP_LOG("invalid format"); |
164 | 0 | return false; |
165 | 0 | } |
166 | | |
167 | 0 | rawpkt_ = RawPacket((uint8_t *) memdst.memory(), memdst.writeb(), type()); |
168 | 0 | return true; |
169 | 0 | } catch (const std::exception &e) { |
170 | 0 | RNP_LOG("%s", e.what()); |
171 | 0 | return false; |
172 | 0 | } |
173 | 0 | } |
174 | | |
175 | | static bool |
176 | | update_sig_expiration(pgp::pkt::Signature * dst, |
177 | | const pgp::pkt::Signature *src, |
178 | | uint64_t create, |
179 | | uint32_t expiry, |
180 | | SecurityContext & ctx) |
181 | 0 | { |
182 | 0 | try { |
183 | 0 | *dst = *src; |
184 | | // Upgrade old hashes to the more secure one |
185 | 0 | SecurityRule rule(FeatureType::Hash, dst->halg, ctx.profile.def_level()); |
186 | 0 | if (ctx.profile.has_rule( |
187 | 0 | FeatureType::Hash, dst->halg, ctx.time(), SecurityAction::Any)) { |
188 | 0 | rule = ctx.profile.get_rule( |
189 | 0 | FeatureType::Hash, dst->halg, ctx.time(), SecurityAction::Any); |
190 | 0 | } |
191 | |
|
192 | 0 | if (rule.level != SecurityLevel::Default) { |
193 | 0 | RNP_LOG("Warning: Weak hash algorithm, authomatically upgrading to SHA256"); |
194 | 0 | dst->halg = PGP_HASH_SHA256; |
195 | 0 | } |
196 | 0 | if (!expiry) { |
197 | 0 | dst->remove_subpkt(dst->find_subpkt(pgp::pkt::sigsub::Type::KeyExpirationTime)); |
198 | 0 | ; |
199 | 0 | } else { |
200 | 0 | dst->set_key_expiration(expiry); |
201 | 0 | } |
202 | 0 | dst->set_creation(create); |
203 | 0 | return true; |
204 | 0 | } catch (const std::exception &e) { |
205 | 0 | RNP_LOG("%s", e.what()); |
206 | 0 | return false; |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | | bool |
211 | | pgp_key_set_expiration(Key * key, |
212 | | Key * seckey, |
213 | | uint32_t expiry, |
214 | | const pgp_password_provider_t &prov, |
215 | | SecurityContext & ctx) |
216 | 0 | { |
217 | 0 | if (!key->is_primary()) { |
218 | 0 | RNP_LOG("Not a primary key"); |
219 | 0 | return false; |
220 | 0 | } |
221 | | |
222 | 0 | pgp::SigIDs sigs; |
223 | | /* update expiration for the latest direct-key signature and self-signature for each userid |
224 | | */ |
225 | 0 | auto sig = key->latest_selfsig(UserID::None, false); |
226 | 0 | if (sig) { |
227 | 0 | sigs.push_back(sig->sigid); |
228 | 0 | } |
229 | 0 | for (size_t uid = 0; uid < key->uid_count(); uid++) { |
230 | 0 | sig = key->latest_selfsig(uid, false); |
231 | 0 | if (sig) { |
232 | 0 | sigs.push_back(sig->sigid); |
233 | 0 | } |
234 | 0 | } |
235 | 0 | if (sigs.empty()) { |
236 | 0 | RNP_LOG("No valid self-signature(s)"); |
237 | 0 | return false; |
238 | 0 | } |
239 | | |
240 | 0 | KeyLocker seclock(*seckey); |
241 | 0 | for (const auto &sigid : sigs) { |
242 | 0 | auto &sig = key->get_sig(sigid); |
243 | | /* update signature and re-sign it */ |
244 | 0 | if (!expiry && !sig.sig.has_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY)) { |
245 | 0 | continue; |
246 | 0 | } |
247 | | |
248 | | /* unlock secret key if needed */ |
249 | 0 | if (seckey->is_locked() && !seckey->unlock(prov)) { |
250 | 0 | RNP_LOG("Failed to unlock secret key"); |
251 | 0 | return false; |
252 | 0 | } |
253 | | |
254 | 0 | pgp::pkt::Signature newsig; |
255 | 0 | auto oldsigid = sigid; |
256 | 0 | if (!update_sig_expiration(&newsig, &sig.sig, ctx.time(), expiry, ctx)) { |
257 | 0 | return false; |
258 | 0 | } |
259 | 0 | try { |
260 | 0 | if (sig.is_cert()) { |
261 | 0 | if (sig.uid >= key->uid_count()) { |
262 | 0 | RNP_LOG("uid not found"); |
263 | 0 | return false; |
264 | 0 | } |
265 | 0 | seckey->sign_cert(key->pkt(), key->get_uid(sig.uid).pkt, newsig, ctx); |
266 | 0 | } else { |
267 | | /* direct-key signature case */ |
268 | 0 | seckey->sign_direct(key->pkt(), newsig, ctx); |
269 | 0 | } |
270 | | /* replace signature, first for secret key since it may be replaced in public */ |
271 | 0 | if (seckey->has_sig(oldsigid)) { |
272 | 0 | seckey->replace_sig(oldsigid, newsig); |
273 | 0 | } |
274 | 0 | if (key != seckey) { |
275 | 0 | key->replace_sig(oldsigid, newsig); |
276 | 0 | } |
277 | 0 | } catch (const std::exception &e) { |
278 | 0 | RNP_LOG("failed to calculate or add signature: %s", e.what()); |
279 | 0 | return false; |
280 | 0 | } |
281 | 0 | } |
282 | | |
283 | 0 | if (!seckey->refresh_data(ctx)) { |
284 | 0 | RNP_LOG("Failed to refresh seckey data."); |
285 | 0 | return false; |
286 | 0 | } |
287 | 0 | if ((key != seckey) && !key->refresh_data(ctx)) { |
288 | 0 | RNP_LOG("Failed to refresh key data."); |
289 | 0 | return false; |
290 | 0 | } |
291 | 0 | return true; |
292 | 0 | } |
293 | | |
294 | | bool |
295 | | pgp_subkey_set_expiration(Key * sub, |
296 | | Key * primsec, |
297 | | Key * secsub, |
298 | | uint32_t expiry, |
299 | | const pgp_password_provider_t &prov, |
300 | | SecurityContext & ctx) |
301 | 0 | { |
302 | 0 | if (!sub->is_subkey()) { |
303 | 0 | RNP_LOG("Not a subkey"); |
304 | 0 | return false; |
305 | 0 | } |
306 | | |
307 | | /* find the latest valid subkey binding */ |
308 | 0 | auto subsig = sub->latest_binding(false); |
309 | 0 | if (!subsig) { |
310 | 0 | RNP_LOG("No valid subkey binding"); |
311 | 0 | return false; |
312 | 0 | } |
313 | 0 | if (!expiry && !subsig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY)) { |
314 | 0 | return true; |
315 | 0 | } |
316 | | |
317 | 0 | KeyLocker primlock(*primsec); |
318 | 0 | if (primsec->is_locked() && !primsec->unlock(prov)) { |
319 | 0 | RNP_LOG("Failed to unlock primary key"); |
320 | 0 | return false; |
321 | 0 | } |
322 | 0 | bool subsign = secsub->can_sign(); |
323 | 0 | KeyLocker sublock(*secsub); |
324 | 0 | if (subsign && secsub->is_locked() && !secsub->unlock(prov)) { |
325 | 0 | RNP_LOG("Failed to unlock subkey"); |
326 | 0 | return false; |
327 | 0 | } |
328 | | |
329 | 0 | try { |
330 | | /* update signature and re-sign */ |
331 | 0 | pgp::pkt::Signature newsig; |
332 | 0 | auto oldsigid = subsig->sigid; |
333 | 0 | if (!update_sig_expiration(&newsig, &subsig->sig, ctx.time(), expiry, ctx)) { |
334 | 0 | return false; |
335 | 0 | } |
336 | 0 | primsec->sign_subkey_binding(*secsub, newsig, ctx); |
337 | | /* replace signature, first for the secret key since it may be replaced in public */ |
338 | 0 | if (secsub->has_sig(oldsigid)) { |
339 | 0 | secsub->replace_sig(oldsigid, newsig); |
340 | 0 | if (!secsub->refresh_data(primsec, ctx)) { |
341 | 0 | return false; |
342 | 0 | } |
343 | 0 | } |
344 | 0 | if (sub == secsub) { |
345 | 0 | return true; |
346 | 0 | } |
347 | 0 | sub->replace_sig(oldsigid, newsig); |
348 | 0 | return sub->refresh_data(primsec, ctx); |
349 | 0 | } catch (const std::exception &e) { |
350 | 0 | RNP_LOG("%s", e.what()); |
351 | 0 | return false; |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | | Key * |
356 | | find_suitable_key( |
357 | | pgp_op_t op, Key *key, KeyProvider *key_provider, bool no_primary, bool pref_pqc_sub) |
358 | 0 | { |
359 | 0 | if (!key || !key_provider) { |
360 | 0 | return NULL; |
361 | 0 | } |
362 | 0 | bool secret = false; |
363 | 0 | switch (op) { |
364 | 0 | case PGP_OP_ENCRYPT: |
365 | 0 | break; |
366 | 0 | case PGP_OP_SIGN: |
367 | 0 | case PGP_OP_CERTIFY: |
368 | 0 | secret = true; |
369 | 0 | break; |
370 | 0 | default: |
371 | 0 | RNP_LOG("Unsupported operation: %d", (int) op); |
372 | 0 | return NULL; |
373 | 0 | } |
374 | | /* Return if specified primary key fits our needs */ |
375 | 0 | if (!no_primary && key->usable_for(op)) { |
376 | 0 | return key; |
377 | 0 | } |
378 | | /* Check for the case when we need to look up for a secret key */ |
379 | 0 | if (!no_primary && secret && key->is_public() && key->usable_for(op, true)) { |
380 | 0 | KeyFingerprintSearch search(key->fp()); |
381 | 0 | Key * sec = key_provider->request_key(search, op, secret); |
382 | 0 | if (sec && sec->usable_for(op)) { |
383 | 0 | return sec; |
384 | 0 | } |
385 | 0 | } |
386 | | /* Now look up for subkeys */ |
387 | 0 | Key *subkey = NULL; |
388 | 0 | for (auto &fp : key->subkey_fps()) { |
389 | 0 | KeyFingerprintSearch search(fp); |
390 | 0 | Key * cur = key_provider->request_key(search, op, secret); |
391 | 0 | if (!cur || !cur->usable_for(op)) { |
392 | 0 | continue; |
393 | 0 | } |
394 | 0 | #if defined(ENABLE_PQC) |
395 | 0 | if (pref_pqc_sub && op == PGP_OP_ENCRYPT) { |
396 | | /* prefer PQC encryption over non-PQC encryption. Assume non-PQC key is only there |
397 | | * for backwards compatibility. */ |
398 | 0 | if (subkey && subkey->is_pqc_alg() && !cur->is_pqc_alg()) { |
399 | | /* do not override already found PQC key with non-PQC key */ |
400 | 0 | continue; |
401 | 0 | } |
402 | 0 | if (subkey && cur->is_pqc_alg() && !subkey->is_pqc_alg()) { |
403 | | /* override non-PQC key with PQC key */ |
404 | 0 | subkey = cur; |
405 | 0 | continue; |
406 | 0 | } |
407 | 0 | } |
408 | 0 | #endif |
409 | 0 | if (!subkey || (cur->creation() > subkey->creation())) { |
410 | 0 | subkey = cur; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | return subkey; |
414 | 0 | } |
415 | | |
416 | 0 | Key::Key(const pgp_key_pkt_t &keypkt) : pkt_(keypkt) |
417 | 0 | { |
418 | 0 | if (!is_key_pkt(pkt_.tag) || !pkt_.material->alg()) { |
419 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
420 | 0 | } |
421 | 0 | fingerprint_ = pgp::Fingerprint(pkt_); |
422 | 0 | grip_ = pkt_.material->grip(); |
423 | | |
424 | | /* parse secret key if not encrypted */ |
425 | 0 | if (is_secret_key_pkt(pkt_.tag)) { |
426 | 0 | bool cleartext = pkt_.sec_protection.s2k.usage == PGP_S2KU_NONE; |
427 | 0 | if (cleartext && decrypt_secret_key(&pkt_, NULL)) { |
428 | 0 | RNP_LOG("failed to setup key fields"); |
429 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
430 | 0 | } |
431 | | /* decryption resets validity */ |
432 | 0 | pkt_.material->set_validity(keypkt.material->validity()); |
433 | 0 | } |
434 | | /* add rawpacket */ |
435 | 0 | rawpkt_ = RawPacket(pkt_); |
436 | 0 | format = KeyFormat::GPG; |
437 | 0 | } |
438 | | |
439 | 0 | Key::Key(const pgp_key_pkt_t &pkt, Key &primary) : Key(pkt) |
440 | 0 | { |
441 | 0 | primary.link_subkey_fp(*this); |
442 | 0 | } |
443 | | |
444 | | Key::Key(const Key &src, bool pubonly) |
445 | 117 | { |
446 | | /* Do some checks for g10 keys */ |
447 | 117 | if (src.format == KeyFormat::G10) { |
448 | 117 | if (pubonly) { |
449 | 0 | RNP_LOG("attempt to copy public part from g10 key"); |
450 | 0 | throw std::invalid_argument("pubonly"); |
451 | 0 | } |
452 | 117 | } |
453 | | |
454 | 117 | if (pubonly) { |
455 | 0 | pkt_ = pgp_key_pkt_t(src.pkt_, true); |
456 | 0 | rawpkt_ = RawPacket(pkt_); |
457 | 117 | } else { |
458 | 117 | pkt_ = src.pkt_; |
459 | 117 | rawpkt_ = src.rawpkt_; |
460 | 117 | } |
461 | | |
462 | 117 | uids_ = src.uids_; |
463 | 117 | sigs_ = src.sigs_; |
464 | 117 | sigs_map_ = src.sigs_map_; |
465 | 117 | keysigs_ = src.keysigs_; |
466 | 117 | subkey_fps_ = src.subkey_fps_; |
467 | 117 | primary_fp_set_ = src.primary_fp_set_; |
468 | 117 | primary_fp_ = src.primary_fp_; |
469 | 117 | expiration_ = src.expiration_; |
470 | 117 | flags_ = src.flags_; |
471 | 117 | fingerprint_ = src.fingerprint_; |
472 | 117 | grip_ = src.grip_; |
473 | 117 | uid0_ = src.uid0_; |
474 | 117 | uid0_set_ = src.uid0_set_; |
475 | 117 | revoked_ = src.revoked_; |
476 | 117 | revocation_ = src.revocation_; |
477 | 117 | revokers_ = src.revokers_; |
478 | 117 | format = src.format; |
479 | 117 | validity_ = src.validity_; |
480 | 117 | valid_till_ = src.valid_till_; |
481 | 117 | } |
482 | | |
483 | 0 | Key::Key(const pgp_transferable_key_t &src) : Key(src.key) |
484 | 0 | { |
485 | | /* add direct-key signatures */ |
486 | 0 | for (auto &sig : src.signatures) { |
487 | 0 | add_sig(sig); |
488 | 0 | } |
489 | | |
490 | | /* add userids and their signatures */ |
491 | 0 | for (auto &uid : src.userids) { |
492 | 0 | add_uid(uid); |
493 | 0 | } |
494 | 0 | } |
495 | | |
496 | 0 | Key::Key(const pgp_transferable_subkey_t &src, Key *primary) : Key(src.subkey) |
497 | 0 | { |
498 | | /* add subkey binding signatures */ |
499 | 0 | for (auto &sig : src.signatures) { |
500 | 0 | add_sig(sig); |
501 | 0 | } |
502 | | |
503 | | /* setup key grips if primary is available */ |
504 | 0 | if (primary) { |
505 | 0 | primary->link_subkey_fp(*this); |
506 | 0 | } |
507 | 0 | } |
508 | | |
509 | | size_t |
510 | | Key::sig_count() const |
511 | 0 | { |
512 | 0 | return sigs_.size(); |
513 | 0 | } |
514 | | |
515 | | Signature & |
516 | | Key::get_sig(size_t idx) |
517 | 0 | { |
518 | 0 | return get_sig(sigs_.at(idx)); |
519 | 0 | } |
520 | | |
521 | | const Signature & |
522 | | Key::get_sig(size_t idx) const |
523 | 0 | { |
524 | 0 | return get_sig(sigs_.at(idx)); |
525 | 0 | } |
526 | | |
527 | | bool |
528 | | Key::has_sig(const pgp::SigID &id) const |
529 | 0 | { |
530 | 0 | return sigs_map_.count(id); |
531 | 0 | } |
532 | | |
533 | | Signature & |
534 | | Key::get_sig(const pgp::SigID &id) |
535 | 0 | { |
536 | 0 | if (!has_sig(id)) { |
537 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
538 | 0 | } |
539 | 0 | return sigs_map_.at(id); |
540 | 0 | } |
541 | | |
542 | | const Signature & |
543 | | Key::get_sig(const pgp::SigID &id) const |
544 | 0 | { |
545 | 0 | if (!has_sig(id)) { |
546 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
547 | 0 | } |
548 | 0 | return sigs_map_.at(id); |
549 | 0 | } |
550 | | |
551 | | Signature & |
552 | | Key::replace_sig(const pgp::SigID &id, const pgp::pkt::Signature &newsig) |
553 | 0 | { |
554 | | /* save oldsig's uid */ |
555 | 0 | size_t uid = get_sig(id).uid; |
556 | | /* delete first old sig since we may have theoretically the same sigid */ |
557 | 0 | auto oldid = id; |
558 | 0 | sigs_map_.erase(oldid); |
559 | 0 | auto &res = sigs_map_.emplace(std::make_pair(newsig.get_id(), newsig)).first->second; |
560 | 0 | res.uid = uid; |
561 | 0 | auto it = std::find(sigs_.begin(), sigs_.end(), oldid); |
562 | 0 | if (it == sigs_.end()) { |
563 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
564 | 0 | } |
565 | 0 | *it = res.sigid; |
566 | 0 | if (uid == UserID::None) { |
567 | 0 | auto it = std::find(keysigs_.begin(), keysigs_.end(), oldid); |
568 | 0 | if (it == keysigs_.end()) { |
569 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
570 | 0 | } |
571 | 0 | *it = res.sigid; |
572 | 0 | } else { |
573 | 0 | uids_[uid].replace_sig(oldid, res.sigid); |
574 | 0 | } |
575 | 0 | return res; |
576 | 0 | } |
577 | | |
578 | | Signature & |
579 | | Key::add_sig(const pgp::pkt::Signature &sig, size_t uid, bool begin) |
580 | 0 | { |
581 | 0 | auto sigid = sig.get_id(); |
582 | 0 | sigs_map_.erase(sigid); |
583 | 0 | auto &res = sigs_map_.emplace(std::make_pair(sigid, sig)).first->second; |
584 | 0 | res.uid = uid; |
585 | 0 | if (uid == UserID::None) { |
586 | 0 | size_t idx = begin ? 0 : keysigs_.size(); |
587 | 0 | sigs_.insert(sigs_.begin() + idx, sigid); |
588 | 0 | keysigs_.insert(keysigs_.begin() + idx, sigid); |
589 | 0 | return res; |
590 | 0 | } |
591 | | |
592 | | /* Calculate correct position in sigs_ */ |
593 | 0 | size_t idx = keysigs_.size(); |
594 | 0 | for (size_t u = 0; u < uid; u++) { |
595 | 0 | idx += uids_[u].sig_count(); |
596 | 0 | } |
597 | 0 | if (!begin) { |
598 | 0 | idx += uids_[uid].sig_count(); |
599 | 0 | } |
600 | 0 | sigs_.insert(sigs_.begin() + idx, sigid); |
601 | 0 | uids_[uid].add_sig(sigid, begin); |
602 | 0 | return res; |
603 | 0 | } |
604 | | |
605 | | bool |
606 | | Key::del_sig(const pgp::SigID &sigid) |
607 | 0 | { |
608 | 0 | if (!has_sig(sigid)) { |
609 | 0 | return false; |
610 | 0 | } |
611 | 0 | uint32_t uid = get_sig(sigid).uid; |
612 | 0 | if (uid == UserID::None) { |
613 | | /* signature over the key itself */ |
614 | 0 | auto it = std::find(keysigs_.begin(), keysigs_.end(), sigid); |
615 | 0 | if (it != keysigs_.end()) { |
616 | 0 | keysigs_.erase(it); |
617 | 0 | } |
618 | 0 | } else if (uid < uids_.size()) { |
619 | | /* userid-related signature */ |
620 | 0 | uids_[uid].del_sig(sigid); |
621 | 0 | } |
622 | 0 | auto it = std::find(sigs_.begin(), sigs_.end(), sigid); |
623 | 0 | if (it != sigs_.end()) { |
624 | 0 | sigs_.erase(it); |
625 | 0 | } |
626 | 0 | return sigs_map_.erase(sigid); |
627 | 0 | } |
628 | | |
629 | | size_t |
630 | | Key::del_sigs(const pgp::SigIDs &sigs) |
631 | 0 | { |
632 | | /* delete actual signatures */ |
633 | 0 | size_t res = 0; |
634 | 0 | for (auto &sig : sigs) { |
635 | 0 | res += sigs_map_.erase(sig); |
636 | 0 | } |
637 | | /* rebuild vectors with signatures order */ |
638 | 0 | keysigs_.clear(); |
639 | 0 | for (auto &uid : uids_) { |
640 | 0 | uid.clear_sigs(); |
641 | 0 | } |
642 | 0 | pgp::SigIDs newsigs; |
643 | 0 | newsigs.reserve(sigs_map_.size()); |
644 | 0 | for (auto &sigid : sigs_) { |
645 | 0 | if (!sigs_map_.count(sigid)) { |
646 | 0 | continue; |
647 | 0 | } |
648 | 0 | newsigs.push_back(sigid); |
649 | 0 | uint32_t uid = get_sig(sigid).uid; |
650 | 0 | if (uid == UserID::None) { |
651 | 0 | keysigs_.push_back(sigid); |
652 | 0 | } else { |
653 | 0 | uids_[uid].add_sig(sigid); |
654 | 0 | } |
655 | 0 | } |
656 | 0 | sigs_ = std::move(newsigs); |
657 | 0 | return res; |
658 | 0 | } |
659 | | |
660 | | size_t |
661 | | Key::keysig_count() const |
662 | 0 | { |
663 | 0 | return keysigs_.size(); |
664 | 0 | } |
665 | | |
666 | | Signature & |
667 | | Key::get_keysig(size_t idx) |
668 | 0 | { |
669 | 0 | return get_sig(keysigs_.at(idx)); |
670 | 0 | } |
671 | | |
672 | | size_t |
673 | | Key::uid_count() const |
674 | 0 | { |
675 | 0 | return uids_.size(); |
676 | 0 | } |
677 | | |
678 | | UserID & |
679 | | Key::get_uid(size_t idx) |
680 | 0 | { |
681 | 0 | return uids_.at(idx); |
682 | 0 | } |
683 | | |
684 | | const UserID & |
685 | | Key::get_uid(size_t idx) const |
686 | 0 | { |
687 | 0 | return uids_.at(idx); |
688 | 0 | } |
689 | | |
690 | | bool |
691 | | Key::has_uid(const std::string &uidstr) const |
692 | 0 | { |
693 | 0 | for (auto &userid : uids_) { |
694 | 0 | if (!userid.valid) { |
695 | 0 | continue; |
696 | 0 | } |
697 | 0 | if (userid.str == uidstr) { |
698 | 0 | return true; |
699 | 0 | } |
700 | 0 | } |
701 | 0 | return false; |
702 | 0 | } |
703 | | |
704 | | uint32_t |
705 | | Key::uid_idx(const pgp_userid_pkt_t &uid) const |
706 | 0 | { |
707 | 0 | for (uint32_t idx = 0; idx < uids_.size(); idx++) { |
708 | 0 | if (uids_[idx].pkt == uid) { |
709 | 0 | return idx; |
710 | 0 | } |
711 | 0 | } |
712 | 0 | return UserID::None; |
713 | 0 | } |
714 | | |
715 | | void |
716 | | Key::del_uid(size_t idx) |
717 | 0 | { |
718 | 0 | if (idx >= uids_.size()) { |
719 | 0 | throw std::out_of_range("idx"); |
720 | 0 | } |
721 | | |
722 | 0 | pgp::SigIDs newsigs; |
723 | | /* copy sigs which do not belong to uid */ |
724 | 0 | newsigs.reserve(sigs_.size()); |
725 | 0 | for (auto &id : sigs_) { |
726 | 0 | if (get_sig(id).uid == idx) { |
727 | 0 | sigs_map_.erase(id); |
728 | 0 | continue; |
729 | 0 | } |
730 | 0 | newsigs.push_back(id); |
731 | 0 | } |
732 | 0 | sigs_ = std::move(newsigs); |
733 | 0 | uids_.erase(uids_.begin() + idx); |
734 | | /* update uids */ |
735 | 0 | if (idx == uids_.size()) { |
736 | 0 | return; |
737 | 0 | } |
738 | 0 | for (auto &sig : sigs_map_) { |
739 | 0 | if ((sig.second.uid == UserID::None) || (sig.second.uid <= idx)) { |
740 | 0 | continue; |
741 | 0 | } |
742 | 0 | sig.second.uid--; |
743 | 0 | } |
744 | 0 | } |
745 | | |
746 | | bool |
747 | | Key::has_primary_uid() const |
748 | 0 | { |
749 | 0 | return uid0_set_; |
750 | 0 | } |
751 | | |
752 | | uint32_t |
753 | | Key::get_primary_uid() const |
754 | 0 | { |
755 | 0 | if (!uid0_set_) { |
756 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
757 | 0 | } |
758 | 0 | return uid0_; |
759 | 0 | } |
760 | | |
761 | | UserID & |
762 | | Key::add_uid(const pgp_transferable_userid_t &uid) |
763 | 0 | { |
764 | | /* construct userid */ |
765 | 0 | uids_.emplace_back(uid.uid); |
766 | | /* add certifications */ |
767 | 0 | for (auto &sig : uid.signatures) { |
768 | 0 | add_sig(sig, uid_count() - 1); |
769 | 0 | } |
770 | 0 | return uids_.back(); |
771 | 0 | } |
772 | | |
773 | | bool |
774 | | Key::revoked() const |
775 | 0 | { |
776 | 0 | return revoked_; |
777 | 0 | } |
778 | | |
779 | | const Revocation & |
780 | | Key::revocation() const |
781 | 0 | { |
782 | 0 | if (!revoked_) { |
783 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
784 | 0 | } |
785 | 0 | return revocation_; |
786 | 0 | } |
787 | | |
788 | | void |
789 | | Key::clear_revokes() |
790 | 0 | { |
791 | 0 | revoked_ = false; |
792 | 0 | revocation_ = {}; |
793 | 0 | for (auto &uid : uids_) { |
794 | 0 | uid.revoked = false; |
795 | 0 | uid.revocation = {}; |
796 | 0 | } |
797 | 0 | } |
798 | | |
799 | | void |
800 | | Key::add_revoker(const pgp::Fingerprint &revoker) |
801 | 0 | { |
802 | 0 | if (std::find(revokers_.begin(), revokers_.end(), revoker) == revokers_.end()) { |
803 | 0 | revokers_.push_back(revoker); |
804 | 0 | } |
805 | 0 | } |
806 | | |
807 | | bool |
808 | | Key::has_revoker(const pgp::Fingerprint &revoker) const |
809 | 0 | { |
810 | 0 | return std::find(revokers_.begin(), revokers_.end(), revoker) != revokers_.end(); |
811 | 0 | } |
812 | | |
813 | | size_t |
814 | | Key::revoker_count() const |
815 | 0 | { |
816 | 0 | return revokers_.size(); |
817 | 0 | } |
818 | | |
819 | | const pgp::Fingerprint & |
820 | | Key::get_revoker(size_t idx) const |
821 | 0 | { |
822 | 0 | return revokers_.at(idx); |
823 | 0 | } |
824 | | |
825 | | const pgp_key_pkt_t & |
826 | | Key::pkt() const noexcept |
827 | 0 | { |
828 | 0 | return pkt_; |
829 | 0 | } |
830 | | |
831 | | pgp_key_pkt_t & |
832 | | Key::pkt() noexcept |
833 | 0 | { |
834 | 0 | return pkt_; |
835 | 0 | } |
836 | | |
837 | | void |
838 | | Key::set_pkt(const pgp_key_pkt_t &pkt) |
839 | 117 | { |
840 | 117 | pkt_ = pkt; |
841 | 117 | } |
842 | | |
843 | | const pgp::KeyMaterial * |
844 | | Key::material() const noexcept |
845 | 0 | { |
846 | 0 | return pkt_.material.get(); |
847 | 0 | } |
848 | | |
849 | | pgp::KeyMaterial * |
850 | | Key::material() noexcept |
851 | 0 | { |
852 | 0 | return pkt_.material.get(); |
853 | 0 | } |
854 | | |
855 | | pgp_pubkey_alg_t |
856 | | Key::alg() const noexcept |
857 | 0 | { |
858 | 0 | return pkt_.alg; |
859 | 0 | } |
860 | | |
861 | | pgp_curve_t |
862 | | Key::curve() const |
863 | 0 | { |
864 | 0 | return material() ? material()->curve() : PGP_CURVE_UNKNOWN; |
865 | 0 | } |
866 | | |
867 | | pgp_version_t |
868 | | Key::version() const noexcept |
869 | 0 | { |
870 | 0 | return pkt().version; |
871 | 0 | } |
872 | | |
873 | | pgp_pkt_type_t |
874 | | Key::type() const noexcept |
875 | 0 | { |
876 | 0 | return pkt().tag; |
877 | 0 | } |
878 | | |
879 | | bool |
880 | | Key::encrypted() const noexcept |
881 | 0 | { |
882 | 0 | return is_secret() && material() && !material()->secret(); |
883 | 0 | } |
884 | | |
885 | | uint8_t |
886 | | Key::flags() const noexcept |
887 | 0 | { |
888 | 0 | return flags_; |
889 | 0 | } |
890 | | |
891 | | bool |
892 | | Key::can_sign() const noexcept |
893 | 0 | { |
894 | 0 | return flags_ & PGP_KF_SIGN; |
895 | 0 | } |
896 | | |
897 | | bool |
898 | | Key::can_certify() const noexcept |
899 | 0 | { |
900 | 0 | return flags_ & PGP_KF_CERTIFY; |
901 | 0 | } |
902 | | |
903 | | bool |
904 | | Key::can_encrypt() const noexcept |
905 | 0 | { |
906 | 0 | return flags_ & PGP_KF_ENCRYPT; |
907 | 0 | } |
908 | | |
909 | | bool |
910 | | Key::has_secret() const noexcept |
911 | 0 | { |
912 | 0 | if (!is_secret()) { |
913 | 0 | return false; |
914 | 0 | } |
915 | 0 | if ((format == KeyFormat::GPG) && pkt_.sec_data.empty()) { |
916 | 0 | return false; |
917 | 0 | } |
918 | 0 | if (pkt_.sec_protection.s2k.usage == PGP_S2KU_NONE) { |
919 | 0 | return true; |
920 | 0 | } |
921 | 0 | switch (pkt_.sec_protection.s2k.specifier) { |
922 | 0 | case PGP_S2KS_SIMPLE: |
923 | 0 | case PGP_S2KS_SALTED: |
924 | 0 | case PGP_S2KS_ITERATED_AND_SALTED: |
925 | 0 | return true; |
926 | 0 | default: |
927 | 0 | return false; |
928 | 0 | } |
929 | 0 | } |
930 | | |
931 | | #if defined(ENABLE_PQC) |
932 | | bool |
933 | | Key::is_pqc_alg() const |
934 | 0 | { |
935 | 0 | switch (alg()) { |
936 | 0 | case PGP_PKA_KYBER768_X25519: |
937 | 0 | FALLTHROUGH_STATEMENT; |
938 | 0 | case PGP_PKA_KYBER768_P256: |
939 | 0 | FALLTHROUGH_STATEMENT; |
940 | 0 | case PGP_PKA_KYBER1024_P384: |
941 | 0 | FALLTHROUGH_STATEMENT; |
942 | 0 | case PGP_PKA_KYBER768_BP256: |
943 | 0 | FALLTHROUGH_STATEMENT; |
944 | 0 | case PGP_PKA_KYBER1024_BP384: |
945 | 0 | FALLTHROUGH_STATEMENT; |
946 | 0 | case PGP_PKA_DILITHIUM3_ED25519: |
947 | 0 | FALLTHROUGH_STATEMENT; |
948 | 0 | case PGP_PKA_DILITHIUM3_P256: |
949 | 0 | FALLTHROUGH_STATEMENT; |
950 | 0 | case PGP_PKA_DILITHIUM5_P384: |
951 | 0 | FALLTHROUGH_STATEMENT; |
952 | 0 | case PGP_PKA_DILITHIUM3_BP256: |
953 | 0 | FALLTHROUGH_STATEMENT; |
954 | 0 | case PGP_PKA_DILITHIUM5_BP384: |
955 | 0 | FALLTHROUGH_STATEMENT; |
956 | 0 | case PGP_PKA_SPHINCSPLUS_SHA2: |
957 | 0 | FALLTHROUGH_STATEMENT; |
958 | 0 | case PGP_PKA_SPHINCSPLUS_SHAKE: |
959 | 0 | return true; |
960 | 0 | default: |
961 | 0 | return false; |
962 | 0 | } |
963 | 0 | } |
964 | | #endif |
965 | | |
966 | | bool |
967 | | Key::usable_for(pgp_op_t op, bool if_secret) const |
968 | 0 | { |
969 | 0 | switch (op) { |
970 | 0 | case PGP_OP_ADD_SUBKEY: |
971 | 0 | return is_primary() && can_sign() && (if_secret || has_secret()); |
972 | 0 | case PGP_OP_SIGN: |
973 | 0 | return can_sign() && valid() && (if_secret || has_secret()); |
974 | 0 | case PGP_OP_CERTIFY: |
975 | 0 | return can_certify() && valid() && (if_secret || has_secret()); |
976 | 0 | case PGP_OP_DECRYPT: |
977 | 0 | return can_encrypt() && valid() && (if_secret || has_secret()); |
978 | 0 | case PGP_OP_UNLOCK: |
979 | 0 | case PGP_OP_PROTECT: |
980 | 0 | case PGP_OP_UNPROTECT: |
981 | 0 | return has_secret(); |
982 | 0 | case PGP_OP_VERIFY: |
983 | 0 | return can_sign() && valid(); |
984 | 0 | case PGP_OP_ADD_USERID: |
985 | 0 | return is_primary() && can_sign() && (if_secret || has_secret()); |
986 | 0 | case PGP_OP_ENCRYPT: |
987 | 0 | return can_encrypt() && valid(); |
988 | 0 | default: |
989 | 0 | return false; |
990 | 0 | } |
991 | 0 | } |
992 | | |
993 | | uint32_t |
994 | | Key::expiration() const noexcept |
995 | 0 | { |
996 | 0 | if (pkt_.version >= 4) { |
997 | 0 | return expiration_; |
998 | 0 | } |
999 | | /* too large value for pkt.v3_days may overflow uint32_t */ |
1000 | 0 | if (pkt_.v3_days > (0xffffffffu / 86400)) { |
1001 | 0 | return 0xffffffffu; |
1002 | 0 | } |
1003 | 0 | return (uint32_t) pkt_.v3_days * 86400; |
1004 | 0 | } |
1005 | | |
1006 | | bool |
1007 | | Key::expired() const noexcept |
1008 | 0 | { |
1009 | 0 | return validity_.expired; |
1010 | 0 | } |
1011 | | |
1012 | | uint32_t |
1013 | | Key::creation() const noexcept |
1014 | 0 | { |
1015 | 0 | return pkt_.creation_time; |
1016 | 0 | } |
1017 | | |
1018 | | bool |
1019 | | Key::is_public() const noexcept |
1020 | 0 | { |
1021 | 0 | return is_public_key_pkt(pkt_.tag); |
1022 | 0 | } |
1023 | | |
1024 | | bool |
1025 | | Key::is_secret() const noexcept |
1026 | 0 | { |
1027 | 0 | return is_secret_key_pkt(pkt_.tag); |
1028 | 0 | } |
1029 | | |
1030 | | bool |
1031 | | Key::is_primary() const noexcept |
1032 | 117 | { |
1033 | 117 | return is_primary_key_pkt(pkt_.tag); |
1034 | 117 | } |
1035 | | |
1036 | | bool |
1037 | | Key::is_subkey() const noexcept |
1038 | 585 | { |
1039 | 585 | return is_subkey_pkt(pkt_.tag); |
1040 | 585 | } |
1041 | | |
1042 | | bool |
1043 | | Key::is_locked() const noexcept |
1044 | 0 | { |
1045 | 0 | if (!is_secret()) { |
1046 | 0 | RNP_LOG("key is not a secret key"); |
1047 | 0 | return false; |
1048 | 0 | } |
1049 | 0 | return encrypted(); |
1050 | 0 | } |
1051 | | |
1052 | | bool |
1053 | | Key::is_protected() const noexcept |
1054 | 0 | { |
1055 | | // sanity check |
1056 | 0 | if (!is_secret()) { |
1057 | 0 | RNP_LOG("Warning: this is not a secret key"); |
1058 | 0 | } |
1059 | 0 | return pkt_.sec_protection.s2k.usage != PGP_S2KU_NONE; |
1060 | 0 | } |
1061 | | |
1062 | | bool |
1063 | | Key::valid() const noexcept |
1064 | 0 | { |
1065 | 0 | return validity_.validated && validity_.valid && !validity_.expired; |
1066 | 0 | } |
1067 | | |
1068 | | bool |
1069 | | Key::validated() const noexcept |
1070 | 117 | { |
1071 | 117 | return validity_.validated; |
1072 | 117 | } |
1073 | | |
1074 | | uint64_t |
1075 | | Key::valid_till_common(bool expiry) const |
1076 | 0 | { |
1077 | 0 | if (!validated()) { |
1078 | 0 | return 0; |
1079 | 0 | } |
1080 | 0 | uint64_t till = expiration() ? (uint64_t) creation() + expiration() : UINT64_MAX; |
1081 | 0 | if (valid()) { |
1082 | 0 | return till; |
1083 | 0 | } |
1084 | 0 | if (revoked()) { |
1085 | | /* we should not believe to the compromised key at all */ |
1086 | 0 | if (revocation_.code == PGP_REVOCATION_COMPROMISED) { |
1087 | 0 | return 0; |
1088 | 0 | } |
1089 | 0 | auto &revsig = get_sig(revocation_.sigid); |
1090 | 0 | if (revsig.sig.creation() > creation()) { |
1091 | | /* pick less time from revocation time and expiration time */ |
1092 | 0 | return std::min((uint64_t) revsig.sig.creation(), till); |
1093 | 0 | } |
1094 | 0 | return 0; |
1095 | 0 | } |
1096 | | /* if key is not marked as expired then it wasn't valid at all */ |
1097 | 0 | return expiry ? till : 0; |
1098 | 0 | } |
1099 | | |
1100 | | uint64_t |
1101 | | Key::valid_till() const noexcept |
1102 | 0 | { |
1103 | 0 | return valid_till_; |
1104 | 0 | } |
1105 | | |
1106 | | bool |
1107 | | Key::valid_at(uint64_t timestamp) const noexcept |
1108 | 0 | { |
1109 | | /* TODO: consider implementing more sophisticated checks, as key validity time could |
1110 | | * possibly be non-continuous */ |
1111 | 0 | return (timestamp >= creation()) && timestamp && (timestamp <= valid_till()); |
1112 | 0 | } |
1113 | | |
1114 | | const pgp::KeyID & |
1115 | | Key::keyid() const noexcept |
1116 | 0 | { |
1117 | 0 | return fingerprint_.keyid(); |
1118 | 0 | } |
1119 | | |
1120 | | const pgp::Fingerprint & |
1121 | | Key::fp() const noexcept |
1122 | 234 | { |
1123 | 234 | return fingerprint_; |
1124 | 234 | } |
1125 | | |
1126 | | const pgp::KeyGrip & |
1127 | | Key::grip() const noexcept |
1128 | 0 | { |
1129 | 0 | return grip_; |
1130 | 0 | } |
1131 | | |
1132 | | const pgp::Fingerprint & |
1133 | | Key::primary_fp() const |
1134 | 0 | { |
1135 | 0 | if (!primary_fp_set_) { |
1136 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
1137 | 0 | } |
1138 | 0 | return primary_fp_; |
1139 | 0 | } |
1140 | | |
1141 | | bool |
1142 | | Key::has_primary_fp() const noexcept |
1143 | 0 | { |
1144 | 0 | return primary_fp_set_; |
1145 | 0 | } |
1146 | | |
1147 | | void |
1148 | | Key::unset_primary_fp() noexcept |
1149 | 0 | { |
1150 | 0 | primary_fp_set_ = false; |
1151 | 0 | primary_fp_ = {}; |
1152 | 0 | } |
1153 | | |
1154 | | void |
1155 | | Key::link_subkey_fp(Key &subkey) |
1156 | 0 | { |
1157 | 0 | if (!is_primary() || !subkey.is_subkey()) { |
1158 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
1159 | 0 | } |
1160 | 0 | subkey.primary_fp_ = fp(); |
1161 | 0 | subkey.primary_fp_set_ = true; |
1162 | 0 | add_subkey_fp(subkey.fp()); |
1163 | 0 | } |
1164 | | |
1165 | | void |
1166 | | Key::add_subkey_fp(const pgp::Fingerprint &fp) |
1167 | 0 | { |
1168 | 0 | if (std::find(subkey_fps_.begin(), subkey_fps_.end(), fp) == subkey_fps_.end()) { |
1169 | 0 | subkey_fps_.push_back(fp); |
1170 | 0 | } |
1171 | 0 | } |
1172 | | |
1173 | | size_t |
1174 | | Key::subkey_count() const noexcept |
1175 | 117 | { |
1176 | 117 | return subkey_fps_.size(); |
1177 | 117 | } |
1178 | | |
1179 | | void |
1180 | | Key::remove_subkey_fp(const pgp::Fingerprint &fp) |
1181 | 0 | { |
1182 | 0 | auto it = std::find(subkey_fps_.begin(), subkey_fps_.end(), fp); |
1183 | 0 | if (it != subkey_fps_.end()) { |
1184 | 0 | subkey_fps_.erase(it); |
1185 | 0 | } |
1186 | 0 | } |
1187 | | |
1188 | | const pgp::Fingerprint & |
1189 | | Key::get_subkey_fp(size_t idx) const |
1190 | 0 | { |
1191 | 0 | return subkey_fps_[idx]; |
1192 | 0 | } |
1193 | | |
1194 | | const pgp::Fingerprints & |
1195 | | Key::subkey_fps() const |
1196 | 0 | { |
1197 | 0 | return subkey_fps_; |
1198 | 0 | } |
1199 | | |
1200 | | size_t |
1201 | | Key::rawpkt_count() const |
1202 | 0 | { |
1203 | 0 | if (format == KeyFormat::G10) { |
1204 | 0 | return 1; |
1205 | 0 | } |
1206 | 0 | return 1 + uid_count() + sig_count(); |
1207 | 0 | } |
1208 | | |
1209 | | RawPacket & |
1210 | | Key::rawpkt() |
1211 | 0 | { |
1212 | 0 | return rawpkt_; |
1213 | 0 | } |
1214 | | |
1215 | | const RawPacket & |
1216 | | Key::rawpkt() const |
1217 | 0 | { |
1218 | 0 | return rawpkt_; |
1219 | 0 | } |
1220 | | |
1221 | | void |
1222 | | Key::set_rawpkt(const RawPacket &src) |
1223 | 117 | { |
1224 | 117 | rawpkt_ = src; |
1225 | 117 | } |
1226 | | |
1227 | | bool |
1228 | | Key::unlock(const pgp_password_provider_t &provider, pgp_op_t op) |
1229 | 0 | { |
1230 | | // sanity checks |
1231 | 0 | if (!usable_for(PGP_OP_UNLOCK)) { |
1232 | 0 | return false; |
1233 | 0 | } |
1234 | | // see if it's already unlocked |
1235 | 0 | if (!is_locked()) { |
1236 | 0 | return true; |
1237 | 0 | } |
1238 | | |
1239 | 0 | pgp_password_ctx_t ctx(op, this); |
1240 | 0 | pgp_key_pkt_t * decrypted_seckey = pgp_decrypt_seckey(*this, provider, ctx); |
1241 | 0 | if (!decrypted_seckey) { |
1242 | 0 | return false; |
1243 | 0 | } |
1244 | | |
1245 | | // move the decrypted mpis into the Key |
1246 | 0 | pkt_.material = std::move(decrypted_seckey->material); |
1247 | 0 | delete decrypted_seckey; |
1248 | 0 | return true; |
1249 | 0 | } |
1250 | | |
1251 | | bool |
1252 | | Key::lock() noexcept |
1253 | 0 | { |
1254 | | // sanity checks |
1255 | 0 | if (!is_secret()) { |
1256 | 0 | RNP_LOG("invalid args"); |
1257 | 0 | return false; |
1258 | 0 | } |
1259 | | |
1260 | | // see if it's already locked |
1261 | 0 | if (is_locked()) { |
1262 | 0 | return true; |
1263 | 0 | } |
1264 | | |
1265 | 0 | assert(material()); |
1266 | 0 | if (material()) { |
1267 | 0 | material()->clear_secret(); |
1268 | 0 | } |
1269 | 0 | return true; |
1270 | 0 | } |
1271 | | |
1272 | | bool |
1273 | | Key::protect(const rnp_key_protection_params_t &protection, |
1274 | | const pgp_password_provider_t & password_provider, |
1275 | | SecurityContext & sctx) |
1276 | 0 | { |
1277 | 0 | pgp_password_ctx_t ctx(PGP_OP_PROTECT, this); |
1278 | | |
1279 | | // ask the provider for a password |
1280 | 0 | secure_array<char, MAX_PASSWORD_LENGTH> password; |
1281 | 0 | if (!pgp_request_password(&password_provider, &ctx, password.data(), password.size())) { |
1282 | 0 | return false; |
1283 | 0 | } |
1284 | 0 | return protect(pkt_, protection, password.data(), sctx); |
1285 | 0 | } |
1286 | | |
1287 | | bool |
1288 | | Key::protect(pgp_key_pkt_t & decrypted, |
1289 | | const rnp_key_protection_params_t &protection, |
1290 | | const std::string & new_password, |
1291 | | SecurityContext & ctx) |
1292 | 0 | { |
1293 | 0 | if (!is_secret()) { |
1294 | 0 | RNP_LOG("Warning: this is not a secret key"); |
1295 | 0 | return false; |
1296 | 0 | } |
1297 | 0 | bool ownpkt = &decrypted == &pkt_; |
1298 | 0 | if (!decrypted.material->secret()) { |
1299 | 0 | RNP_LOG("Decrypted secret key must be provided"); |
1300 | 0 | return false; |
1301 | 0 | } |
1302 | | |
1303 | | /* force encrypted-and-hashed and iterated-and-salted as it's the only method we support*/ |
1304 | 0 | pkt_.sec_protection.s2k.usage = PGP_S2KU_ENCRYPTED_AND_HASHED; |
1305 | 0 | pkt_.sec_protection.s2k.specifier = PGP_S2KS_ITERATED_AND_SALTED; |
1306 | | /* use default values where needed */ |
1307 | 0 | pkt_.sec_protection.symm_alg = |
1308 | 0 | protection.symm_alg ? protection.symm_alg : DEFAULT_PGP_SYMM_ALG; |
1309 | 0 | pkt_.sec_protection.cipher_mode = |
1310 | 0 | protection.cipher_mode ? protection.cipher_mode : DEFAULT_PGP_CIPHER_MODE; |
1311 | 0 | pkt_.sec_protection.s2k.hash_alg = |
1312 | 0 | protection.hash_alg ? protection.hash_alg : DEFAULT_PGP_HASH_ALG; |
1313 | 0 | auto iter = protection.iterations; |
1314 | 0 | if (!iter) { |
1315 | 0 | iter = ctx.s2k_iterations(pkt_.sec_protection.s2k.hash_alg); |
1316 | 0 | } |
1317 | 0 | pkt_.sec_protection.s2k.iterations = pgp_s2k_round_iterations(iter); |
1318 | 0 | if (!ownpkt) { |
1319 | | /* decrypted is assumed to be temporary variable so we may modify it */ |
1320 | 0 | decrypted.sec_protection = pkt_.sec_protection; |
1321 | 0 | } |
1322 | | |
1323 | | /* write the protected key to raw packet */ |
1324 | 0 | return write_sec_rawpkt(decrypted, new_password, ctx); |
1325 | 0 | } |
1326 | | |
1327 | | bool |
1328 | | Key::unprotect(const pgp_password_provider_t &password_provider, SecurityContext &secctx) |
1329 | 0 | { |
1330 | | /* sanity check */ |
1331 | 0 | if (!is_secret()) { |
1332 | 0 | RNP_LOG("Warning: this is not a secret key"); |
1333 | 0 | return false; |
1334 | 0 | } |
1335 | | /* already unprotected */ |
1336 | 0 | if (!is_protected()) { |
1337 | 0 | return true; |
1338 | 0 | } |
1339 | | /* simple case */ |
1340 | 0 | if (!encrypted()) { |
1341 | 0 | pkt_.sec_protection.s2k.usage = PGP_S2KU_NONE; |
1342 | 0 | return write_sec_rawpkt(pkt_, "", secctx); |
1343 | 0 | } |
1344 | | |
1345 | 0 | pgp_password_ctx_t ctx(PGP_OP_UNPROTECT, this); |
1346 | |
|
1347 | 0 | pgp_key_pkt_t *decrypted_seckey = pgp_decrypt_seckey(*this, password_provider, ctx); |
1348 | 0 | if (!decrypted_seckey) { |
1349 | 0 | return false; |
1350 | 0 | } |
1351 | 0 | decrypted_seckey->sec_protection.s2k.usage = PGP_S2KU_NONE; |
1352 | 0 | if (!write_sec_rawpkt(*decrypted_seckey, "", secctx)) { |
1353 | 0 | delete decrypted_seckey; |
1354 | 0 | return false; |
1355 | 0 | } |
1356 | 0 | pkt_ = std::move(*decrypted_seckey); |
1357 | | /* current logic is that unprotected key should be additionally unlocked */ |
1358 | 0 | assert(material()); |
1359 | 0 | if (material()) { |
1360 | 0 | material()->clear_secret(); |
1361 | 0 | } |
1362 | 0 | delete decrypted_seckey; |
1363 | 0 | return true; |
1364 | 0 | } |
1365 | | |
1366 | | void |
1367 | | Key::write(pgp_dest_t &dst) const |
1368 | 0 | { |
1369 | | /* write key rawpacket */ |
1370 | 0 | rawpkt_.write(dst); |
1371 | |
|
1372 | 0 | if (format == KeyFormat::G10) { |
1373 | 0 | return; |
1374 | 0 | } |
1375 | | |
1376 | | /* write signatures on key */ |
1377 | 0 | for (auto &sigid : keysigs_) { |
1378 | 0 | get_sig(sigid).raw.write(dst); |
1379 | 0 | } |
1380 | | |
1381 | | /* write uids and their signatures */ |
1382 | 0 | for (const auto &uid : uids_) { |
1383 | 0 | uid.rawpkt.write(dst); |
1384 | 0 | for (size_t idx = 0; idx < uid.sig_count(); idx++) { |
1385 | 0 | get_sig(uid.get_sig(idx)).raw.write(dst); |
1386 | 0 | } |
1387 | 0 | } |
1388 | 0 | } |
1389 | | |
1390 | | void |
1391 | | Key::write_xfer(pgp_dest_t &dst, const KeyStore *keyring) const |
1392 | 0 | { |
1393 | 0 | write(dst); |
1394 | 0 | if (dst.werr) { |
1395 | 0 | RNP_LOG("Failed to export primary key"); |
1396 | 0 | return; |
1397 | 0 | } |
1398 | | |
1399 | 0 | if (!keyring) { |
1400 | 0 | return; |
1401 | 0 | } |
1402 | | |
1403 | | // Export subkeys |
1404 | 0 | for (auto &fp : subkey_fps_) { |
1405 | 0 | const Key *subkey = keyring->get_key(fp); |
1406 | 0 | if (!subkey) { |
1407 | 0 | std::string fphex = bin_to_hex(fp.data(), fp.size(), HexFormat::Lowercase); |
1408 | 0 | RNP_LOG("Warning! Subkey %s not found.", fphex.c_str()); |
1409 | 0 | continue; |
1410 | 0 | } |
1411 | 0 | subkey->write(dst); |
1412 | 0 | if (dst.werr) { |
1413 | 0 | RNP_LOG("Error occurred when exporting a subkey"); |
1414 | 0 | return; |
1415 | 0 | } |
1416 | 0 | } |
1417 | 0 | } |
1418 | | |
1419 | | bool |
1420 | | Key::write_autocrypt(pgp_dest_t &dst, Key &sub, uint32_t uid) |
1421 | 0 | { |
1422 | 0 | auto cert = latest_uid_selfcert(uid); |
1423 | 0 | if (!cert) { |
1424 | 0 | RNP_LOG("No valid uid certification"); |
1425 | 0 | return false; |
1426 | 0 | } |
1427 | 0 | auto binding = sub.latest_binding(); |
1428 | 0 | if (!binding) { |
1429 | 0 | RNP_LOG("No valid binding for subkey"); |
1430 | 0 | return false; |
1431 | 0 | } |
1432 | 0 | if (is_secret() || sub.is_secret()) { |
1433 | 0 | RNP_LOG("Public key required"); |
1434 | 0 | return false; |
1435 | 0 | } |
1436 | | |
1437 | 0 | try { |
1438 | | /* write all or nothing */ |
1439 | 0 | MemoryDest memdst; |
1440 | 0 | pkt().write(memdst.dst()); |
1441 | 0 | get_uid(uid).pkt.write(memdst.dst()); |
1442 | 0 | cert->sig.write(memdst.dst()); |
1443 | 0 | sub.pkt().write(memdst.dst()); |
1444 | 0 | binding->sig.write(memdst.dst()); |
1445 | 0 | dst_write(&dst, memdst.memory(), memdst.writeb()); |
1446 | 0 | return !dst.werr; |
1447 | 0 | } catch (const std::exception &e) { |
1448 | 0 | RNP_LOG("%s", e.what()); |
1449 | 0 | return false; |
1450 | 0 | } |
1451 | 0 | } |
1452 | | |
1453 | | std::vector<uint8_t> |
1454 | | Key::write_vec() const |
1455 | 0 | { |
1456 | 0 | MemoryDest dst; |
1457 | 0 | write(dst.dst()); |
1458 | 0 | return dst.to_vector(); |
1459 | 0 | } |
1460 | | |
1461 | | Signature * |
1462 | | Key::latest_selfsig(uint32_t uid, bool validated) |
1463 | 351 | { |
1464 | 351 | uint32_t latest = 0; |
1465 | 351 | Signature *res = nullptr; |
1466 | | |
1467 | 351 | for (auto &sigid : sigs_) { |
1468 | 0 | auto &sig = get_sig(sigid); |
1469 | 0 | if (validated && !sig.validity.valid()) { |
1470 | 0 | continue; |
1471 | 0 | } |
1472 | 0 | bool skip = false; |
1473 | 0 | switch (uid) { |
1474 | 0 | case UserID::None: |
1475 | 0 | skip = (sig.uid != UserID::None) || !is_direct_self(sig); |
1476 | 0 | break; |
1477 | 0 | case UserID::Primary: { |
1478 | 0 | skip = !is_self_cert(sig) || |
1479 | 0 | !sig.sig.get_subpkt(pgp::pkt::sigsub::Type::PrimaryUserID) || |
1480 | 0 | !sig.sig.primary_uid() || (sig.uid == UserID::None); |
1481 | 0 | break; |
1482 | 0 | } |
1483 | 0 | case UserID::Any: |
1484 | 0 | skip = !is_self_cert(sig) || (sig.uid == UserID::None); |
1485 | 0 | break; |
1486 | 0 | default: |
1487 | 0 | skip = (sig.uid != uid) || !is_self_cert(sig); |
1488 | 0 | break; |
1489 | 0 | } |
1490 | 0 | if (skip) { |
1491 | 0 | continue; |
1492 | 0 | } |
1493 | | |
1494 | 0 | uint32_t creation = sig.sig.creation(); |
1495 | 0 | if (creation >= latest) { |
1496 | 0 | latest = creation; |
1497 | 0 | res = &sig; |
1498 | 0 | } |
1499 | 0 | } |
1500 | | |
1501 | | /* if there is later self-sig for the same uid without primary flag, then drop res */ |
1502 | 351 | if ((uid == UserID::Primary) && res) { |
1503 | 0 | auto overres = latest_selfsig(res->uid, validated); |
1504 | 0 | if (overres && (overres->sig.creation() > res->sig.creation())) { |
1505 | 0 | res = nullptr; |
1506 | 0 | } |
1507 | 0 | } |
1508 | 351 | return res; |
1509 | 351 | } |
1510 | | |
1511 | | Signature * |
1512 | | Key::latest_binding(bool validated) |
1513 | 0 | { |
1514 | 0 | uint32_t latest = 0; |
1515 | 0 | Signature *res = nullptr; |
1516 | |
|
1517 | 0 | for (auto &sigid : sigs_) { |
1518 | 0 | auto &sig = get_sig(sigid); |
1519 | 0 | if (validated && !sig.validity.valid()) { |
1520 | 0 | continue; |
1521 | 0 | } |
1522 | 0 | if (!is_binding(sig)) { |
1523 | 0 | continue; |
1524 | 0 | } |
1525 | | |
1526 | 0 | uint32_t creation = sig.sig.creation(); |
1527 | 0 | if (creation >= latest) { |
1528 | 0 | latest = creation; |
1529 | 0 | res = &sig; |
1530 | 0 | } |
1531 | 0 | } |
1532 | 0 | return res; |
1533 | 0 | } |
1534 | | |
1535 | | Signature * |
1536 | | Key::latest_uid_selfcert(uint32_t uid) |
1537 | 0 | { |
1538 | 0 | uint32_t latest = 0; |
1539 | 0 | Signature *res = nullptr; |
1540 | |
|
1541 | 0 | if (uid >= uids_.size()) { |
1542 | 0 | return NULL; |
1543 | 0 | } |
1544 | | |
1545 | 0 | for (size_t idx = 0; idx < uids_[uid].sig_count(); idx++) { |
1546 | 0 | auto &sig = get_sig(uids_[uid].get_sig(idx)); |
1547 | 0 | if (!sig.validity.valid() || (sig.uid != uid)) { |
1548 | 0 | continue; |
1549 | 0 | } |
1550 | 0 | if (!is_self_cert(sig)) { |
1551 | 0 | continue; |
1552 | 0 | } |
1553 | | |
1554 | 0 | uint32_t creation = sig.sig.creation(); |
1555 | 0 | if (creation >= latest) { |
1556 | 0 | latest = creation; |
1557 | 0 | res = &sig; |
1558 | 0 | } |
1559 | 0 | } |
1560 | 0 | return res; |
1561 | 0 | } |
1562 | | |
1563 | | bool |
1564 | | Key::is_signer(const Signature &sig) const |
1565 | 0 | { |
1566 | | /* if we have fingerprint let's check it */ |
1567 | 0 | if (sig.sig.has_keyfp()) { |
1568 | 0 | return sig.sig.keyfp() == fp(); |
1569 | 0 | } |
1570 | 0 | if (!sig.sig.has_keyid()) { |
1571 | 0 | return false; |
1572 | 0 | } |
1573 | 0 | return keyid() == sig.sig.keyid(); |
1574 | 0 | } |
1575 | | |
1576 | | bool |
1577 | | Key::expired_with(const Signature &sig, uint64_t at) const |
1578 | 0 | { |
1579 | | /* key expiration: absence of subpkt or 0 means it never expires */ |
1580 | 0 | uint64_t expiration = sig.sig.key_expiration(); |
1581 | 0 | if (!expiration) { |
1582 | 0 | return false; |
1583 | 0 | } |
1584 | 0 | return expiration + creation() < at; |
1585 | 0 | } |
1586 | | |
1587 | | bool |
1588 | | Key::is_self_cert(const Signature &sig) const |
1589 | 0 | { |
1590 | 0 | return is_primary() && sig.is_cert() && is_signer(sig); |
1591 | 0 | } |
1592 | | |
1593 | | bool |
1594 | | Key::is_direct_self(const Signature &sig) const |
1595 | 0 | { |
1596 | 0 | return is_primary() && (sig.sig.type() == PGP_SIG_DIRECT) && is_signer(sig); |
1597 | 0 | } |
1598 | | |
1599 | | bool |
1600 | | Key::is_revocation(const Signature &sig) const |
1601 | 0 | { |
1602 | 0 | return is_primary() ? (sig.sig.type() == PGP_SIG_REV_KEY) : |
1603 | 0 | (sig.sig.type() == PGP_SIG_REV_SUBKEY); |
1604 | 0 | } |
1605 | | |
1606 | | bool |
1607 | | Key::is_uid_revocation(const Signature &sig) const |
1608 | 0 | { |
1609 | 0 | return is_primary() && (sig.sig.type() == PGP_SIG_REV_CERT); |
1610 | 0 | } |
1611 | | |
1612 | | bool |
1613 | | Key::is_binding(const Signature &sig) const |
1614 | 0 | { |
1615 | 0 | return is_subkey() && (sig.sig.type() == PGP_SIG_SUBKEY); |
1616 | 0 | } |
1617 | | |
1618 | | void |
1619 | | Key::validate_sig(const Key &key, Signature &sig, const SecurityContext &ctx) const noexcept |
1620 | 0 | { |
1621 | 0 | sig.validity.reset(); |
1622 | |
|
1623 | 0 | SignatureInfo sinfo; |
1624 | 0 | sinfo.sig = &sig.sig; |
1625 | 0 | sinfo.signer_valid = true; |
1626 | 0 | sinfo.ignore_expiry = key.is_self_cert(sig) || key.is_binding(sig); |
1627 | 0 | sinfo.ignore_sig_expiry = sig.is_revocation(); |
1628 | |
|
1629 | 0 | pgp_sig_type_t stype = sig.sig.type(); |
1630 | 0 | try { |
1631 | 0 | switch (stype) { |
1632 | 0 | case PGP_SIG_BINARY: |
1633 | 0 | case PGP_SIG_TEXT: |
1634 | 0 | case PGP_SIG_STANDALONE: |
1635 | 0 | case PGP_SIG_PRIMARY: |
1636 | 0 | RNP_LOG("Invalid key signature type: %d", (int) stype); |
1637 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_WRONG_KEY_SIG); |
1638 | 0 | break; |
1639 | 0 | case PGP_CERT_GENERIC: |
1640 | 0 | case PGP_CERT_PERSONA: |
1641 | 0 | case PGP_CERT_CASUAL: |
1642 | 0 | case PGP_CERT_POSITIVE: |
1643 | 0 | case PGP_SIG_REV_CERT: { |
1644 | 0 | if (sig.uid >= key.uid_count()) { |
1645 | 0 | RNP_LOG("Userid not found"); |
1646 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_UID_MISSING); |
1647 | 0 | break; |
1648 | 0 | } |
1649 | 0 | validate_cert(sinfo, key.pkt(), key.get_uid(sig.uid).pkt, ctx); |
1650 | 0 | break; |
1651 | 0 | } |
1652 | 0 | case PGP_SIG_SUBKEY: |
1653 | 0 | if (!is_signer(sig)) { |
1654 | 0 | RNP_LOG("Invalid subkey binding's signer."); |
1655 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_WRONG_BINDING); |
1656 | 0 | break; |
1657 | 0 | } |
1658 | 0 | validate_binding(sinfo, key, ctx); |
1659 | 0 | break; |
1660 | 0 | case PGP_SIG_DIRECT: |
1661 | 0 | if (!is_signer(sig)) { |
1662 | 0 | RNP_LOG("Invalid direct key signer."); |
1663 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_WRONG_DIRECT); |
1664 | 0 | break; |
1665 | 0 | } |
1666 | 0 | validate_direct(sinfo, ctx); |
1667 | 0 | break; |
1668 | 0 | case PGP_SIG_REV_KEY: |
1669 | 0 | if (!is_signer(sig)) { |
1670 | 0 | RNP_LOG("Invalid key revocation signer."); |
1671 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_WRONG_REV); |
1672 | 0 | break; |
1673 | 0 | } |
1674 | 0 | validate_key_rev(sinfo, key.pkt(), ctx); |
1675 | 0 | break; |
1676 | 0 | case PGP_SIG_REV_SUBKEY: |
1677 | 0 | if (!is_signer(sig)) { |
1678 | 0 | RNP_LOG("Invalid subkey revocation's signer."); |
1679 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_WRONG_REV); |
1680 | 0 | break; |
1681 | 0 | } |
1682 | 0 | validate_sub_rev(sinfo, key.pkt(), ctx); |
1683 | 0 | break; |
1684 | 0 | default: |
1685 | 0 | RNP_LOG("Unsupported key signature type: %d", (int) stype); |
1686 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_UNSUPPORTED); |
1687 | 0 | break; |
1688 | 0 | } |
1689 | 0 | } catch (const std::exception &e) { |
1690 | 0 | RNP_LOG("Key signature validation failed: %s", e.what()); |
1691 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_ERROR); |
1692 | 0 | } |
1693 | | |
1694 | 0 | sinfo.validity.mark_validated(); |
1695 | 0 | sig.validity = std::move(sinfo.validity); |
1696 | 0 | } |
1697 | | |
1698 | | void |
1699 | | Key::validate_sig(SignatureInfo & sinfo, |
1700 | | Hash & hash, |
1701 | | const SecurityContext & ctx, |
1702 | | const pgp_literal_hdr_t *hdr) const noexcept |
1703 | 0 | { |
1704 | | /* Validate signature itself */ |
1705 | 0 | auto res = signature_validate(*sinfo.sig, *pkt_.material, hash, ctx, hdr); |
1706 | 0 | if (!sinfo.signer_valid && !valid_at(sinfo.sig->creation())) { |
1707 | 0 | RNP_LOG("invalid or untrusted key"); |
1708 | 0 | res.add_error(RNP_ERROR_SIG_SIGNER_UNTRUSTED); |
1709 | 0 | } |
1710 | | |
1711 | | /* Check signature's expiration time */ |
1712 | 0 | uint32_t now = ctx.time(); |
1713 | 0 | uint32_t create = sinfo.sig->creation(); |
1714 | 0 | uint32_t expiry = sinfo.sig->expiration(); |
1715 | 0 | if (create > now) { |
1716 | | /* signature created later then now */ |
1717 | 0 | RNP_LOG("signature created %d seconds in future", (int) (create - now)); |
1718 | 0 | if (!sinfo.ignore_sig_expiry) { |
1719 | 0 | res.add_error(RNP_ERROR_SIG_FROM_FUTURE); |
1720 | 0 | } |
1721 | 0 | } |
1722 | 0 | if (create && expiry && (create + expiry < now)) { |
1723 | | /* signature expired */ |
1724 | 0 | RNP_LOG("signature expired"); |
1725 | 0 | if (!sinfo.ignore_sig_expiry) { |
1726 | 0 | res.add_error(RNP_ERROR_SIG_EXPIRED); |
1727 | 0 | } |
1728 | 0 | } |
1729 | | |
1730 | | /* check key creation time vs signature creation */ |
1731 | 0 | if (creation() > create) { |
1732 | 0 | RNP_LOG("key is newer than signature"); |
1733 | 0 | res.add_error(RNP_ERROR_SIG_OLDER_KEY); |
1734 | 0 | } |
1735 | | |
1736 | | /* check whether key was not expired when sig created */ |
1737 | 0 | if (!sinfo.ignore_expiry && expiration() && (creation() + expiration() < create)) { |
1738 | 0 | RNP_LOG("signature made after key expiration"); |
1739 | 0 | res.add_error(RNP_ERROR_SIG_EXPIRED_KEY); |
1740 | 0 | } |
1741 | | |
1742 | | /* Check signer's fingerprint */ |
1743 | 0 | if (sinfo.sig->has_keyfp() && (sinfo.sig->keyfp() != fp())) { |
1744 | 0 | RNP_LOG("issuer fingerprint doesn't match signer's one"); |
1745 | 0 | res.add_error(RNP_ERROR_SIG_FP_MISMATCH); |
1746 | 0 | } |
1747 | | |
1748 | | /* Check for unknown critical notations */ |
1749 | 0 | for (auto &subpkt : sinfo.sig->subpkts) { |
1750 | 0 | if (!subpkt->critical() || (subpkt->type() != pgp::pkt::sigsub::Type::NotationData)) { |
1751 | 0 | continue; |
1752 | 0 | } |
1753 | 0 | auto ¬ation = dynamic_cast<pgp::pkt::sigsub::NotationData &>(*subpkt); |
1754 | 0 | RNP_LOG("unknown critical notation: %s", notation.name().c_str()); |
1755 | 0 | res.add_error(RNP_ERROR_SIG_UNKNOWN_NOTATION); |
1756 | 0 | } |
1757 | |
|
1758 | 0 | for (auto &err : res.errors()) { |
1759 | 0 | sinfo.validity.add_error(err); |
1760 | 0 | } |
1761 | 0 | sinfo.validity.mark_validated(); |
1762 | 0 | } |
1763 | | |
1764 | | void |
1765 | | Key::validate_cert(SignatureInfo & sinfo, |
1766 | | const pgp_key_pkt_t & key, |
1767 | | const pgp_userid_pkt_t &uid, |
1768 | | const SecurityContext & ctx) const |
1769 | 0 | { |
1770 | 0 | auto hash = signature_hash_certification(*sinfo.sig, key, uid); |
1771 | 0 | validate_sig(sinfo, *hash, ctx); |
1772 | 0 | } |
1773 | | |
1774 | | void |
1775 | | Key::validate_binding(SignatureInfo & sinfo, |
1776 | | const Key & subkey, |
1777 | | const SecurityContext &ctx) const |
1778 | 0 | { |
1779 | 0 | if (!is_primary() || !subkey.is_subkey()) { |
1780 | 0 | RNP_LOG("Invalid binding signature key type(s)"); |
1781 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_ERROR); |
1782 | 0 | sinfo.validity.mark_validated(); |
1783 | 0 | return; |
1784 | 0 | } |
1785 | 0 | auto hash = signature_hash_binding(*sinfo.sig, pkt(), subkey.pkt()); |
1786 | 0 | validate_sig(sinfo, *hash, ctx); |
1787 | | /* Check whether subkey is capable of signing and return otherwise */ |
1788 | 0 | if (!sinfo.validity.valid() || !(sinfo.sig->key_flags() & PGP_KF_SIGN)) { |
1789 | 0 | return; |
1790 | 0 | } |
1791 | | |
1792 | | /* check primary key binding signature if any */ |
1793 | 0 | auto sub = dynamic_cast<pgp::pkt::sigsub::EmbeddedSignature *>( |
1794 | 0 | sinfo.sig->get_subpkt(pgp::pkt::sigsub::Type::EmbeddedSignature, false)); |
1795 | 0 | if (!sub) { |
1796 | 0 | RNP_LOG("error! no primary key binding signature"); |
1797 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_NO_PRIMARY_BINDING); |
1798 | 0 | return; |
1799 | 0 | } |
1800 | 0 | if (!sub->signature()) { |
1801 | 0 | RNP_LOG("invalid embedded signature subpacket"); |
1802 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_BINDING_PARSE); |
1803 | 0 | return; |
1804 | 0 | } |
1805 | 0 | if (sub->signature()->type() != PGP_SIG_PRIMARY) { |
1806 | 0 | RNP_LOG("invalid primary key binding signature"); |
1807 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_WRONG_BIND_TYPE); |
1808 | 0 | return; |
1809 | 0 | } |
1810 | 0 | if (sub->signature()->version < PGP_V4) { |
1811 | 0 | RNP_LOG("invalid primary key binding signature version"); |
1812 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_WRONG_BIND_TYPE); |
1813 | 0 | return; |
1814 | 0 | } |
1815 | | |
1816 | 0 | hash = signature_hash_binding(*sub->signature(), pkt(), subkey.pkt()); |
1817 | 0 | SignatureInfo bindinfo; |
1818 | 0 | bindinfo.sig = sub->signature(); |
1819 | 0 | bindinfo.signer_valid = true; |
1820 | 0 | bindinfo.ignore_expiry = true; |
1821 | 0 | subkey.validate_sig(bindinfo, *hash, ctx); |
1822 | 0 | if (!bindinfo.validity.valid()) { |
1823 | 0 | sinfo.validity.add_error(RNP_ERROR_SIG_INVALID_BINDING); |
1824 | 0 | for (auto &err : bindinfo.validity.errors()) { |
1825 | 0 | sinfo.validity.add_error(err); |
1826 | 0 | } |
1827 | 0 | } |
1828 | 0 | } |
1829 | | |
1830 | | void |
1831 | | Key::validate_sub_rev(SignatureInfo & sinfo, |
1832 | | const pgp_key_pkt_t & subkey, |
1833 | | const SecurityContext &ctx) const |
1834 | 0 | { |
1835 | 0 | auto hash = signature_hash_binding(*sinfo.sig, pkt(), subkey); |
1836 | 0 | validate_sig(sinfo, *hash, ctx); |
1837 | 0 | } |
1838 | | |
1839 | | void |
1840 | | Key::validate_direct(SignatureInfo &sinfo, const SecurityContext &ctx) const |
1841 | 0 | { |
1842 | 0 | auto hash = signature_hash_direct(*sinfo.sig, pkt()); |
1843 | 0 | validate_sig(sinfo, *hash, ctx); |
1844 | 0 | } |
1845 | | |
1846 | | void |
1847 | | Key::validate_key_rev(SignatureInfo & sinfo, |
1848 | | const pgp_key_pkt_t & key, |
1849 | | const SecurityContext &ctx) const |
1850 | 0 | { |
1851 | 0 | auto hash = signature_hash_direct(*sinfo.sig, key); |
1852 | 0 | validate_sig(sinfo, *hash, ctx); |
1853 | 0 | } |
1854 | | |
1855 | | void |
1856 | | Key::validate_self_signatures(const SecurityContext &ctx) |
1857 | 117 | { |
1858 | 117 | for (auto &sigid : sigs_) { |
1859 | 0 | auto &sig = get_sig(sigid); |
1860 | 0 | if (sig.validity.validated()) { |
1861 | 0 | continue; |
1862 | 0 | } |
1863 | 0 | if (!is_signer(sig)) { |
1864 | 0 | continue; |
1865 | 0 | } |
1866 | | |
1867 | 0 | if (is_direct_self(sig) || is_self_cert(sig) || is_uid_revocation(sig) || |
1868 | 0 | is_revocation(sig)) { |
1869 | 0 | validate_sig(*this, sig, ctx); |
1870 | 0 | } |
1871 | 0 | } |
1872 | 117 | } |
1873 | | |
1874 | | void |
1875 | | Key::validate_self_signatures(Key &primary, const SecurityContext &ctx) |
1876 | 0 | { |
1877 | 0 | for (auto &sigid : sigs_) { |
1878 | 0 | auto &sig = get_sig(sigid); |
1879 | 0 | if (sig.validity.validated()) { |
1880 | 0 | continue; |
1881 | 0 | } |
1882 | | |
1883 | 0 | if (is_binding(sig) || is_revocation(sig)) { |
1884 | 0 | primary.validate_sig(*this, sig, ctx); |
1885 | 0 | } |
1886 | 0 | } |
1887 | 0 | } |
1888 | | |
1889 | | bool |
1890 | | Key::validate_desig_revokes(KeyStore &keyring) |
1891 | 117 | { |
1892 | 117 | if (revokers_.empty()) { |
1893 | 117 | return false; |
1894 | 117 | } |
1895 | 0 | bool refresh = false; |
1896 | 0 | for (auto &sigid : sigs_) { |
1897 | 0 | auto &sig = get_sig(sigid); |
1898 | 0 | if (!is_revocation(sig) || is_signer(sig)) { |
1899 | 0 | continue; |
1900 | 0 | } |
1901 | | /* Don't think we should deal with sigs without issuer's fingerprint */ |
1902 | 0 | if (!sig.sig.has_keyfp() || !has_revoker(sig.sig.keyfp())) { |
1903 | 0 | continue; |
1904 | 0 | } |
1905 | | /* If signature was validated and valid, do not re-validate it */ |
1906 | 0 | if (sig.validity.valid()) { |
1907 | 0 | continue; |
1908 | 0 | } |
1909 | | |
1910 | 0 | auto revoker = keyring.get_signer(sig.sig); |
1911 | 0 | if (!revoker) { |
1912 | 0 | continue; |
1913 | 0 | } |
1914 | | |
1915 | 0 | revoker->validate_sig(*this, sig, keyring.secctx); |
1916 | 0 | if (sig.validity.valid()) { |
1917 | | /* return true only if new valid revocation was added */ |
1918 | 0 | refresh = true; |
1919 | 0 | } |
1920 | 0 | } |
1921 | |
|
1922 | 0 | return refresh; |
1923 | 117 | } |
1924 | | |
1925 | | void |
1926 | | Key::validate_primary(KeyStore &keyring) |
1927 | 117 | { |
1928 | | /* validate signatures if needed */ |
1929 | 117 | validate_self_signatures(keyring.secctx); |
1930 | | |
1931 | | /* consider public key as valid on this level if it is not expired and has at least one |
1932 | | * valid self-signature, and is not revoked */ |
1933 | 117 | validity_.reset(); |
1934 | 117 | validity_.validated = true; |
1935 | 117 | bool has_cert = false; |
1936 | 117 | bool has_expired = false; |
1937 | | /* check whether key is revoked */ |
1938 | 117 | for (auto &sigid : sigs_) { |
1939 | 0 | auto &sig = get_sig(sigid); |
1940 | 0 | if (!sig.validity.valid()) { |
1941 | 0 | continue; |
1942 | 0 | } |
1943 | 0 | if (is_revocation(sig)) { |
1944 | 0 | return; |
1945 | 0 | } |
1946 | 0 | } |
1947 | | /* if we have direct-key signature, then it has higher priority for expiration check */ |
1948 | 117 | uint64_t now = keyring.secctx.time(); |
1949 | 117 | auto dirsig = latest_selfsig(UserID::None); |
1950 | 117 | if (dirsig) { |
1951 | 0 | has_expired = expired_with(*dirsig, now); |
1952 | 0 | has_cert = !has_expired; |
1953 | 0 | } |
1954 | | /* if we have primary uid and it is more restrictive, then use it as well */ |
1955 | 117 | Signature *prisig = nullptr; |
1956 | 117 | if (!has_expired && (prisig = latest_selfsig(UserID::Primary))) { |
1957 | 0 | has_expired = expired_with(*prisig, now); |
1958 | 0 | has_cert = !has_expired; |
1959 | 0 | } |
1960 | | /* if we don't have direct-key sig and primary uid, use the latest self-cert */ |
1961 | 117 | Signature *latest = nullptr; |
1962 | 117 | if (!dirsig && !prisig && (latest = latest_selfsig(UserID::Any))) { |
1963 | 0 | has_expired = expired_with(*latest, now); |
1964 | 0 | has_cert = !has_expired; |
1965 | 0 | } |
1966 | | |
1967 | | /* we have at least one non-expiring key self-signature */ |
1968 | 117 | if (has_cert) { |
1969 | 0 | validity_.valid = true; |
1970 | 0 | return; |
1971 | 0 | } |
1972 | | /* we have valid self-signature which expires key */ |
1973 | 117 | if (has_expired) { |
1974 | 0 | validity_.expired = true; |
1975 | 0 | return; |
1976 | 0 | } |
1977 | | |
1978 | | /* let's check whether key has at least one valid subkey binding */ |
1979 | 117 | for (size_t i = 0; i < subkey_count(); i++) { |
1980 | 0 | Key *sub = keyring.get_subkey(*this, i); |
1981 | 0 | if (!sub) { |
1982 | 0 | continue; |
1983 | 0 | } |
1984 | 0 | sub->validate_self_signatures(*this, keyring.secctx); |
1985 | 0 | auto sig = sub->latest_binding(); |
1986 | 0 | if (!sig) { |
1987 | 0 | continue; |
1988 | 0 | } |
1989 | | /* check whether subkey is expired - then do not mark key as valid */ |
1990 | 0 | if (sub->expired_with(*sig, now)) { |
1991 | 0 | continue; |
1992 | 0 | } |
1993 | 0 | validity_.valid = true; |
1994 | 0 | return; |
1995 | 0 | } |
1996 | 117 | } |
1997 | | |
1998 | | void |
1999 | | Key::validate_subkey(Key *primary, const SecurityContext &ctx) |
2000 | 0 | { |
2001 | | /* consider subkey as valid on this level if it has valid primary key, has at least one |
2002 | | * non-expired binding signature, and is not revoked. */ |
2003 | 0 | validity_.reset(); |
2004 | 0 | validity_.validated = true; |
2005 | 0 | if (!primary || (!primary->valid() && !primary->expired())) { |
2006 | 0 | return; |
2007 | 0 | } |
2008 | | /* validate signatures if needed */ |
2009 | 0 | validate_self_signatures(*primary, ctx); |
2010 | |
|
2011 | 0 | bool has_binding = false; |
2012 | 0 | bool has_expired = false; |
2013 | 0 | for (auto &sigid : sigs_) { |
2014 | 0 | auto &sig = get_sig(sigid); |
2015 | 0 | if (!sig.validity.valid()) { |
2016 | 0 | continue; |
2017 | 0 | } |
2018 | | |
2019 | 0 | if (is_binding(sig) && !has_binding) { |
2020 | | /* check whether subkey is expired */ |
2021 | 0 | if (expired_with(sig, ctx.time())) { |
2022 | 0 | has_expired = true; |
2023 | 0 | continue; |
2024 | 0 | } |
2025 | 0 | has_binding = true; |
2026 | 0 | } else if (is_revocation(sig)) { |
2027 | 0 | return; |
2028 | 0 | } |
2029 | 0 | } |
2030 | 0 | validity_.valid = has_binding && primary->valid(); |
2031 | 0 | if (!validity_.valid) { |
2032 | 0 | validity_.expired = has_expired; |
2033 | 0 | } |
2034 | 0 | } |
2035 | | |
2036 | | void |
2037 | | Key::validate(KeyStore &keyring) |
2038 | 117 | { |
2039 | 117 | validity_.reset(); |
2040 | 117 | if (!is_subkey()) { |
2041 | 117 | validate_primary(keyring); |
2042 | 117 | return; |
2043 | 117 | } |
2044 | 0 | Key *primary = nullptr; |
2045 | 0 | if (has_primary_fp()) { |
2046 | 0 | primary = keyring.get_key(primary_fp()); |
2047 | 0 | } |
2048 | 0 | validate_subkey(primary, keyring.secctx); |
2049 | 0 | } |
2050 | | |
2051 | | void |
2052 | | Key::revalidate(KeyStore &keyring) |
2053 | 117 | { |
2054 | 117 | if (is_subkey()) { |
2055 | 0 | Key *primary = keyring.primary_key(*this); |
2056 | 0 | if (primary) { |
2057 | 0 | primary->revalidate(keyring); |
2058 | 0 | } else { |
2059 | 0 | validate_subkey(NULL, keyring.secctx); |
2060 | 0 | } |
2061 | 0 | return; |
2062 | 0 | } |
2063 | | |
2064 | 117 | validate_desig_revokes(keyring); |
2065 | 117 | validate(keyring); |
2066 | 117 | if (!refresh_data(keyring.secctx)) { |
2067 | 117 | RNP_LOG("Failed to refresh key data"); |
2068 | 117 | } |
2069 | | /* validate/re-validate all subkeys as well */ |
2070 | 117 | for (auto &fp : subkey_fps_) { |
2071 | 0 | Key *subkey = keyring.get_key(fp); |
2072 | 0 | if (subkey) { |
2073 | 0 | subkey->validate_subkey(this, keyring.secctx); |
2074 | 0 | if (!subkey->refresh_data(this, keyring.secctx)) { |
2075 | 0 | RNP_LOG("Failed to refresh subkey data"); |
2076 | 0 | } |
2077 | 0 | } |
2078 | 0 | } |
2079 | 117 | } |
2080 | | |
2081 | | void |
2082 | | Key::mark_valid() |
2083 | 0 | { |
2084 | 0 | validity_.mark_valid(); |
2085 | 0 | for (auto &sigid : sigs_) { |
2086 | 0 | get_sig(sigid).validity.reset(true); |
2087 | 0 | } |
2088 | 0 | } |
2089 | | |
2090 | | void |
2091 | | Key::sign_init(RNG & rng, |
2092 | | pgp::pkt::Signature &sig, |
2093 | | pgp_hash_alg_t hash, |
2094 | | uint64_t creation, |
2095 | | pgp_version_t version) const |
2096 | 0 | { |
2097 | 0 | sig.version = version; |
2098 | 0 | sig.halg = pkt_.material->adjust_hash(hash); |
2099 | 0 | sig.palg = alg(); |
2100 | 0 | sig.set_keyfp(fp()); |
2101 | 0 | sig.set_creation(creation); |
2102 | 0 | if (version == PGP_V4) { |
2103 | | // for v6 issuing keys, this MUST NOT be included |
2104 | 0 | sig.set_keyid(keyid()); |
2105 | 0 | } |
2106 | 0 | #if defined(ENABLE_CRYPTO_REFRESH) |
2107 | 0 | if (version == PGP_V6) { |
2108 | 0 | sig.salt.resize(Hash::size(sig.halg) / 2); |
2109 | 0 | rng.get(sig.salt.data(), sig.salt.size()); |
2110 | 0 | } |
2111 | 0 | #endif |
2112 | 0 | } |
2113 | | |
2114 | | void |
2115 | | Key::sign_cert(const pgp_key_pkt_t & key, |
2116 | | const pgp_userid_pkt_t &uid, |
2117 | | pgp::pkt::Signature & sig, |
2118 | | SecurityContext & ctx) |
2119 | 0 | { |
2120 | 0 | sig.fill_hashed_data(); |
2121 | 0 | auto hash = signature_hash_certification(sig, key, uid); |
2122 | 0 | signature_calculate(sig, *pkt_.material, *hash, ctx); |
2123 | 0 | } |
2124 | | |
2125 | | void |
2126 | | Key::sign_direct(const pgp_key_pkt_t &key, pgp::pkt::Signature &sig, SecurityContext &ctx) |
2127 | 0 | { |
2128 | 0 | sig.fill_hashed_data(); |
2129 | 0 | auto hash = signature_hash_direct(sig, key); |
2130 | 0 | signature_calculate(sig, *pkt_.material, *hash, ctx); |
2131 | 0 | } |
2132 | | |
2133 | | void |
2134 | | Key::sign_binding(const pgp_key_pkt_t &key, pgp::pkt::Signature &sig, SecurityContext &ctx) |
2135 | 0 | { |
2136 | 0 | sig.fill_hashed_data(); |
2137 | 0 | auto hash = is_primary() ? signature_hash_binding(sig, pkt(), key) : |
2138 | 0 | signature_hash_binding(sig, key, pkt()); |
2139 | 0 | signature_calculate(sig, *pkt_.material, *hash, ctx); |
2140 | 0 | } |
2141 | | |
2142 | | void |
2143 | | Key::gen_revocation(const Revocation & rev, |
2144 | | pgp_hash_alg_t hash, |
2145 | | const pgp_key_pkt_t &key, |
2146 | | pgp::pkt::Signature &sig, |
2147 | | SecurityContext & ctx) |
2148 | 0 | { |
2149 | 0 | sign_init(ctx.rng, sig, hash, ctx.time(), key.version); |
2150 | 0 | sig.set_type(is_primary_key_pkt(key.tag) ? PGP_SIG_REV_KEY : PGP_SIG_REV_SUBKEY); |
2151 | 0 | sig.set_revocation_reason(rev.code, rev.reason); |
2152 | |
|
2153 | 0 | if (is_primary_key_pkt(key.tag)) { |
2154 | 0 | sign_direct(key, sig, ctx); |
2155 | 0 | } else { |
2156 | 0 | sign_binding(key, sig, ctx); |
2157 | 0 | } |
2158 | 0 | } |
2159 | | |
2160 | | void |
2161 | | Key::sign_subkey_binding(Key & sub, |
2162 | | pgp::pkt::Signature &sig, |
2163 | | SecurityContext & ctx, |
2164 | | bool subsign) |
2165 | 0 | { |
2166 | 0 | if (!is_primary()) { |
2167 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
2168 | 0 | } |
2169 | 0 | sign_binding(sub.pkt(), sig, ctx); |
2170 | | /* add primary key binding subpacket if requested */ |
2171 | 0 | if (subsign) { |
2172 | 0 | pgp::pkt::Signature embsig; |
2173 | 0 | sub.sign_init(ctx.rng, embsig, sig.halg, ctx.time(), sub.version()); |
2174 | 0 | embsig.set_type(PGP_SIG_PRIMARY); |
2175 | 0 | sub.sign_binding(pkt(), embsig, ctx); |
2176 | 0 | sig.set_embedded_sig(embsig); |
2177 | 0 | } |
2178 | 0 | } |
2179 | | |
2180 | | #if defined(ENABLE_CRYPTO_REFRESH) |
2181 | | void |
2182 | | Key::add_direct_sig(CertParams &cert, pgp_hash_alg_t hash, SecurityContext &ctx, Key *pubkey) |
2183 | 0 | { |
2184 | | // We only support modifying v4 and newer keys |
2185 | 0 | if (pkt().version < PGP_V4) { |
2186 | 0 | RNP_LOG("adding a direct-key sig to V2/V3 key is not supported"); |
2187 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
2188 | 0 | } |
2189 | | |
2190 | 0 | pgp::pkt::Signature sig; |
2191 | 0 | sign_init(ctx.rng, sig, hash, ctx.time(), pkt().version); |
2192 | 0 | sig.set_type(PGP_SIG_DIRECT); |
2193 | 0 | cert.populate(sig); |
2194 | 0 | sign_direct(pkt_, sig, ctx); |
2195 | |
|
2196 | 0 | add_sig(sig, UserID::None); |
2197 | 0 | refresh_data(ctx); |
2198 | 0 | if (!pubkey) { |
2199 | 0 | return; |
2200 | 0 | } |
2201 | 0 | pubkey->add_sig(sig, UserID::None); |
2202 | 0 | pubkey->refresh_data(ctx); |
2203 | 0 | } |
2204 | | #endif |
2205 | | |
2206 | | void |
2207 | | Key::add_uid_cert(CertParams &cert, pgp_hash_alg_t hash, SecurityContext &ctx, Key *pubkey) |
2208 | 0 | { |
2209 | 0 | if (cert.userid.empty()) { |
2210 | | /* todo: why not to allow empty uid? */ |
2211 | 0 | RNP_LOG("wrong parameters"); |
2212 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
2213 | 0 | } |
2214 | | // userids are only valid for primary keys, not subkeys |
2215 | 0 | if (!is_primary()) { |
2216 | 0 | RNP_LOG("cannot add a userid to a subkey"); |
2217 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
2218 | 0 | } |
2219 | | // see if the key already has this userid |
2220 | 0 | if (has_uid(cert.userid)) { |
2221 | 0 | RNP_LOG("key already has this userid"); |
2222 | 0 | throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); |
2223 | 0 | } |
2224 | | // this isn't really valid for this format |
2225 | 0 | if (format == KeyFormat::G10) { |
2226 | 0 | RNP_LOG("Unsupported key store type"); |
2227 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
2228 | 0 | } |
2229 | | // We only support modifying v4 and newer keys |
2230 | 0 | if (pkt().version < PGP_V4) { |
2231 | 0 | RNP_LOG("adding a userid to V2/V3 key is not supported"); |
2232 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
2233 | 0 | } |
2234 | | /* TODO: if key has at least one uid then has_primary_uid() will be always true! */ |
2235 | 0 | if (has_primary_uid() && cert.primary) { |
2236 | 0 | RNP_LOG("changing the primary userid is not supported"); |
2237 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
2238 | 0 | } |
2239 | | |
2240 | | /* Fill the transferable userid */ |
2241 | 0 | pgp_userid_pkt_t uid; |
2242 | 0 | pgp::pkt::Signature sig; |
2243 | 0 | sign_init(ctx.rng, sig, hash, ctx.time(), pkt().version); |
2244 | 0 | cert.populate(uid, sig); |
2245 | 0 | try { |
2246 | 0 | sign_cert(pkt_, uid, sig, ctx); |
2247 | 0 | } catch (const std::exception &e) { |
2248 | 0 | RNP_LOG("Failed to certify: %s", e.what()); |
2249 | 0 | throw; |
2250 | 0 | } |
2251 | | /* add uid and signature to the key and pubkey, if non-NULL */ |
2252 | 0 | uids_.emplace_back(uid); |
2253 | 0 | add_sig(sig, uid_count() - 1); |
2254 | 0 | refresh_data(ctx); |
2255 | 0 | if (!pubkey) { |
2256 | 0 | return; |
2257 | 0 | } |
2258 | 0 | pubkey->uids_.emplace_back(uid); |
2259 | 0 | pubkey->add_sig(sig, pubkey->uid_count() - 1); |
2260 | 0 | pubkey->refresh_data(ctx); |
2261 | 0 | } |
2262 | | |
2263 | | void |
2264 | | Key::add_sub_binding(Key & subsec, |
2265 | | Key & subpub, |
2266 | | const BindingParams &binding, |
2267 | | pgp_hash_alg_t hash, |
2268 | | SecurityContext & ctx) |
2269 | 0 | { |
2270 | 0 | if (!is_primary()) { |
2271 | 0 | RNP_LOG("must be called on primary key"); |
2272 | 0 | throw rnp_exception(RNP_ERROR_BAD_STATE); |
2273 | 0 | } |
2274 | | |
2275 | | /* populate signature */ |
2276 | 0 | pgp::pkt::Signature sig; |
2277 | 0 | sign_init(ctx.rng, sig, hash, ctx.time(), version()); |
2278 | 0 | sig.set_type(PGP_SIG_SUBKEY); |
2279 | 0 | if (binding.key_expiration) { |
2280 | 0 | sig.set_key_expiration(binding.key_expiration); |
2281 | 0 | } |
2282 | 0 | if (binding.flags) { |
2283 | 0 | sig.set_key_flags(binding.flags); |
2284 | 0 | } |
2285 | | /* calculate binding */ |
2286 | 0 | pgp_key_flags_t realkf = (pgp_key_flags_t) binding.flags; |
2287 | 0 | if (!realkf) { |
2288 | 0 | realkf = pgp_pk_alg_capabilities(subsec.alg()); |
2289 | 0 | } |
2290 | 0 | sign_subkey_binding(subsec, sig, ctx, realkf & PGP_KF_SIGN); |
2291 | | /* add to the secret and public key */ |
2292 | 0 | subsec.add_sig(sig); |
2293 | 0 | subpub.add_sig(sig); |
2294 | 0 | } |
2295 | | |
2296 | | void |
2297 | | Key::refresh_revocations() |
2298 | 0 | { |
2299 | 0 | clear_revokes(); |
2300 | 0 | for (auto &sigid : sigs_) { |
2301 | 0 | auto &sig = get_sig(sigid); |
2302 | 0 | if (!sig.validity.valid()) { |
2303 | 0 | continue; |
2304 | 0 | } |
2305 | 0 | if (is_revocation(sig)) { |
2306 | 0 | if (revoked_) { |
2307 | 0 | continue; |
2308 | 0 | } |
2309 | 0 | revoked_ = true; |
2310 | 0 | revocation_ = Revocation(sig); |
2311 | 0 | continue; |
2312 | 0 | } |
2313 | 0 | if (is_uid_revocation(sig)) { |
2314 | 0 | if (sig.uid >= uid_count()) { |
2315 | 0 | RNP_LOG("Invalid uid index"); |
2316 | 0 | continue; |
2317 | 0 | } |
2318 | 0 | auto &uid = get_uid(sig.uid); |
2319 | 0 | if (uid.revoked) { |
2320 | 0 | continue; |
2321 | 0 | } |
2322 | 0 | uid.revoked = true; |
2323 | 0 | uid.revocation = Revocation(sig); |
2324 | 0 | } |
2325 | 0 | } |
2326 | 0 | } |
2327 | | |
2328 | | bool |
2329 | | Key::refresh_data(const SecurityContext &ctx) |
2330 | 117 | { |
2331 | 117 | if (!is_primary()) { |
2332 | 117 | RNP_LOG("key must be primary"); |
2333 | 117 | return false; |
2334 | 117 | } |
2335 | | /* validate self-signatures if not done yet */ |
2336 | 0 | validate_self_signatures(ctx); |
2337 | | /* key expiration */ |
2338 | 0 | expiration_ = 0; |
2339 | | /* if we have direct-key signature, then it has higher priority */ |
2340 | 0 | auto dirsig = latest_selfsig(UserID::None); |
2341 | 0 | if (dirsig) { |
2342 | 0 | expiration_ = dirsig->sig.key_expiration(); |
2343 | 0 | } |
2344 | | /* if we have primary uid and it is more restrictive, then use it as well */ |
2345 | 0 | auto prisig = latest_selfsig(UserID::Primary); |
2346 | 0 | if (prisig && prisig->sig.key_expiration() && |
2347 | 0 | (!expiration_ || (prisig->sig.key_expiration() < expiration_))) { |
2348 | 0 | expiration_ = prisig->sig.key_expiration(); |
2349 | 0 | } |
2350 | | /* if we don't have direct-key sig and primary uid, use the latest self-cert */ |
2351 | 0 | auto latest = latest_selfsig(UserID::Any); |
2352 | 0 | if (!dirsig && !prisig && latest) { |
2353 | 0 | expiration_ = latest->sig.key_expiration(); |
2354 | 0 | } |
2355 | | /* key flags: check in direct-key sig first, then primary uid, and then latest */ |
2356 | 0 | if (dirsig && dirsig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { |
2357 | 0 | flags_ = dirsig->sig.key_flags(); |
2358 | 0 | } else if (prisig && prisig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { |
2359 | 0 | flags_ = prisig->sig.key_flags(); |
2360 | 0 | } else if (latest && latest->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { |
2361 | 0 | flags_ = latest->sig.key_flags(); |
2362 | 0 | } else { |
2363 | 0 | flags_ = pgp_pk_alg_capabilities(alg()); |
2364 | 0 | } |
2365 | | /* designated revokers */ |
2366 | 0 | revokers_.clear(); |
2367 | 0 | for (auto &sigid : sigs_) { |
2368 | 0 | auto &sig = get_sig(sigid); |
2369 | | /* pick designated revokers only from direct-key signatures */ |
2370 | 0 | if (!sig.validity.valid() || !is_direct_self(sig)) { |
2371 | 0 | continue; |
2372 | 0 | } |
2373 | 0 | if (!sig.sig.has_revoker()) { |
2374 | 0 | continue; |
2375 | 0 | } |
2376 | 0 | add_revoker(sig.sig.revoker()); |
2377 | 0 | } |
2378 | | /* revocation(s) */ |
2379 | 0 | refresh_revocations(); |
2380 | | /* valid till */ |
2381 | 0 | valid_till_ = valid_till_common(expired()); |
2382 | | /* userid validities */ |
2383 | 0 | for (auto &uid : uids_) { |
2384 | 0 | uid.valid = false; |
2385 | 0 | } |
2386 | 0 | for (auto &sigid : sigs_) { |
2387 | 0 | auto &sig = get_sig(sigid); |
2388 | | /* consider userid as valid if it has at least one non-expired self-sig */ |
2389 | 0 | if (!sig.validity.valid() || !sig.is_cert() || !is_signer(sig) || |
2390 | 0 | sig.expired(ctx.time())) { |
2391 | 0 | continue; |
2392 | 0 | } |
2393 | 0 | if (sig.uid >= uid_count()) { |
2394 | 0 | continue; |
2395 | 0 | } |
2396 | 0 | get_uid(sig.uid).valid = true; |
2397 | 0 | } |
2398 | | /* check whether uid is revoked */ |
2399 | 0 | for (auto &uid : uids_) { |
2400 | 0 | if (uid.revoked) { |
2401 | 0 | uid.valid = false; |
2402 | 0 | } |
2403 | 0 | } |
2404 | | /* primary userid: use latest one which is not overridden by later non-primary selfsig */ |
2405 | 0 | uid0_set_ = false; |
2406 | 0 | if (prisig && get_uid(prisig->uid).valid) { |
2407 | 0 | uid0_ = prisig->uid; |
2408 | 0 | uid0_set_ = true; |
2409 | 0 | } |
2410 | 0 | return true; |
2411 | 117 | } |
2412 | | |
2413 | | bool |
2414 | | Key::refresh_data(Key *primary, const SecurityContext &ctx) |
2415 | 0 | { |
2416 | | /* validate self-signatures if not done yet */ |
2417 | 0 | if (primary) { |
2418 | 0 | validate_self_signatures(*primary, ctx); |
2419 | 0 | } |
2420 | 0 | auto sig = latest_binding(primary); |
2421 | | /* subkey expiration */ |
2422 | 0 | expiration_ = sig ? sig->sig.key_expiration() : 0; |
2423 | | /* subkey flags */ |
2424 | 0 | if (sig && sig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { |
2425 | 0 | flags_ = sig->sig.key_flags(); |
2426 | 0 | } else { |
2427 | 0 | flags_ = pgp_pk_alg_capabilities(alg()); |
2428 | 0 | } |
2429 | | /* revocation */ |
2430 | 0 | clear_revokes(); |
2431 | 0 | for (auto &sigid : sigs_) { |
2432 | 0 | auto &rev = get_sig(sigid); |
2433 | 0 | if (!rev.validity.valid() || !is_revocation(rev)) { |
2434 | 0 | continue; |
2435 | 0 | } |
2436 | 0 | revoked_ = true; |
2437 | 0 | try { |
2438 | 0 | revocation_ = Revocation(rev); |
2439 | 0 | } catch (const std::exception &e) { |
2440 | 0 | RNP_LOG("%s", e.what()); |
2441 | 0 | return false; |
2442 | 0 | } |
2443 | 0 | break; |
2444 | 0 | } |
2445 | | /* valid till */ |
2446 | 0 | if (primary) { |
2447 | 0 | valid_till_ = |
2448 | 0 | std::min(primary->valid_till(), valid_till_common(expired() || primary->expired())); |
2449 | 0 | } else { |
2450 | 0 | valid_till_ = valid_till_common(expired()); |
2451 | 0 | } |
2452 | 0 | return true; |
2453 | 0 | } |
2454 | | |
2455 | | void |
2456 | | Key::merge_validity(const pgp_validity_t &src) |
2457 | 0 | { |
2458 | 0 | validity_.valid = validity_.valid && src.valid; |
2459 | | /* We may safely leave validated status only if both merged keys are valid && validated. |
2460 | | * Otherwise we'll need to revalidate. For instance, one validated but invalid key may add |
2461 | | * revocation signature, or valid key may add certification to the invalid one. */ |
2462 | 0 | validity_.validated = validity_.valid && validity_.validated && src.validated; |
2463 | | /* if expired is true at least in one case then valid and validated are false */ |
2464 | 0 | validity_.expired = false; |
2465 | 0 | } |
2466 | | |
2467 | | bool |
2468 | | Key::merge(const Key &src) |
2469 | 0 | { |
2470 | 0 | assert(!is_subkey()); |
2471 | 0 | assert(!src.is_subkey()); |
2472 | | |
2473 | | /* if src is secret key then merged key will become secret as well. */ |
2474 | 0 | if (src.is_secret() && !is_secret()) { |
2475 | 0 | pkt_ = src.pkt(); |
2476 | 0 | rawpkt_ = src.rawpkt(); |
2477 | | /* no subkey processing here - they are separated from the main key */ |
2478 | 0 | } |
2479 | | |
2480 | | /* merge direct-key signatures */ |
2481 | 0 | for (auto &sigid : src.keysigs_) { |
2482 | 0 | if (has_sig(sigid)) { |
2483 | 0 | continue; |
2484 | 0 | } |
2485 | 0 | add_sig(src.get_sig(sigid).sig); |
2486 | 0 | } |
2487 | | |
2488 | | /* merge user ids and their signatures */ |
2489 | 0 | for (auto &srcuid : src.uids_) { |
2490 | | /* check whether we have this uid and add if needed */ |
2491 | 0 | auto uididx = uid_idx(srcuid.pkt); |
2492 | 0 | if (uididx == UserID::None) { |
2493 | 0 | uididx = uid_count(); |
2494 | 0 | uids_.emplace_back(srcuid.pkt); |
2495 | 0 | } |
2496 | | /* add uid signatures */ |
2497 | 0 | for (size_t idx = 0; idx < srcuid.sig_count(); idx++) { |
2498 | 0 | auto &sigid = srcuid.get_sig(idx); |
2499 | 0 | if (has_sig(sigid)) { |
2500 | 0 | continue; |
2501 | 0 | } |
2502 | 0 | add_sig(src.get_sig(sigid).sig, uididx); |
2503 | 0 | } |
2504 | 0 | } |
2505 | | |
2506 | | /* Update subkey fingerprints */ |
2507 | 0 | for (auto &fp : src.subkey_fps()) { |
2508 | 0 | add_subkey_fp(fp); |
2509 | 0 | } |
2510 | | |
2511 | | /* check whether key was unlocked and assign secret key data */ |
2512 | 0 | if (src.is_secret() && !src.is_locked() && (!is_secret() || is_locked())) { |
2513 | 0 | pkt().material = src.pkt().material->clone(); |
2514 | 0 | } |
2515 | | /* copy validity status */ |
2516 | 0 | merge_validity(src.validity_); |
2517 | 0 | return true; |
2518 | 0 | } |
2519 | | |
2520 | | bool |
2521 | | Key::merge(const Key &src, Key *primary) |
2522 | 0 | { |
2523 | 0 | assert(is_subkey()); |
2524 | 0 | assert(src.is_subkey()); |
2525 | | |
2526 | | /* if src is secret key then merged key will become secret as well. */ |
2527 | 0 | if (src.is_secret() && !is_secret()) { |
2528 | 0 | pkt_ = src.pkt(); |
2529 | 0 | rawpkt_ = src.rawpkt(); |
2530 | 0 | } |
2531 | | |
2532 | | /* add subkey binding signatures */ |
2533 | 0 | for (auto &sigid : src.keysigs_) { |
2534 | 0 | if (has_sig(sigid)) { |
2535 | 0 | continue; |
2536 | 0 | } |
2537 | 0 | add_sig(src.get_sig(sigid).sig); |
2538 | 0 | } |
2539 | | |
2540 | | /* check whether key was unlocked and assign secret key data */ |
2541 | 0 | if (src.is_secret() && !src.is_locked() && (!is_secret() || is_locked())) { |
2542 | 0 | pkt().material = src.pkt().material->clone(); |
2543 | 0 | } |
2544 | | /* copy validity status */ |
2545 | 0 | merge_validity(src.validity_); |
2546 | | /* link subkey fps */ |
2547 | 0 | if (primary) { |
2548 | 0 | primary->link_subkey_fp(*this); |
2549 | 0 | } |
2550 | 0 | return true; |
2551 | 0 | } |
2552 | | } // namespace rnp |
2553 | | |
2554 | | pgp_key_flags_t |
2555 | | pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) |
2556 | 0 | { |
2557 | 0 | switch (alg) { |
2558 | 0 | case PGP_PKA_RSA: |
2559 | 0 | return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH | PGP_KF_ENCRYPT); |
2560 | | |
2561 | 0 | case PGP_PKA_RSA_SIGN_ONLY: |
2562 | | // deprecated, but still usable |
2563 | 0 | return PGP_KF_SIGN; |
2564 | | |
2565 | 0 | case PGP_PKA_RSA_ENCRYPT_ONLY: |
2566 | | // deprecated, but still usable |
2567 | 0 | return PGP_KF_ENCRYPT; |
2568 | | |
2569 | 0 | case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: /* deprecated */ |
2570 | | // These are no longer permitted per the RFC |
2571 | 0 | return PGP_KF_NONE; |
2572 | | |
2573 | 0 | case PGP_PKA_DSA: |
2574 | 0 | case PGP_PKA_ECDSA: |
2575 | 0 | case PGP_PKA_EDDSA: |
2576 | 0 | return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); |
2577 | | |
2578 | 0 | #if defined(ENABLE_CRYPTO_REFRESH) |
2579 | 0 | case PGP_PKA_ED25519: |
2580 | 0 | return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); |
2581 | 0 | case PGP_PKA_X25519: |
2582 | 0 | return PGP_KF_ENCRYPT; |
2583 | 0 | #endif |
2584 | | |
2585 | 0 | case PGP_PKA_SM2: |
2586 | 0 | return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH | PGP_KF_ENCRYPT); |
2587 | | |
2588 | 0 | case PGP_PKA_ECDH: |
2589 | 0 | case PGP_PKA_ELGAMAL: |
2590 | 0 | return PGP_KF_ENCRYPT; |
2591 | | |
2592 | 0 | #if defined(ENABLE_PQC) |
2593 | 0 | case PGP_PKA_KYBER768_X25519: |
2594 | 0 | FALLTHROUGH_STATEMENT; |
2595 | | // TODO: Add case for PGP_PKA_KYBER1024_X448 with FALLTHROUGH_STATEMENT; |
2596 | 0 | case PGP_PKA_KYBER768_P256: |
2597 | 0 | FALLTHROUGH_STATEMENT; |
2598 | 0 | case PGP_PKA_KYBER1024_P384: |
2599 | 0 | FALLTHROUGH_STATEMENT; |
2600 | 0 | case PGP_PKA_KYBER768_BP256: |
2601 | 0 | FALLTHROUGH_STATEMENT; |
2602 | 0 | case PGP_PKA_KYBER1024_BP384: |
2603 | 0 | return PGP_KF_ENCRYPT; |
2604 | | |
2605 | 0 | case PGP_PKA_DILITHIUM3_ED25519: |
2606 | 0 | FALLTHROUGH_STATEMENT; |
2607 | | // TODO: Add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; |
2608 | 0 | case PGP_PKA_DILITHIUM3_P256: |
2609 | 0 | FALLTHROUGH_STATEMENT; |
2610 | 0 | case PGP_PKA_DILITHIUM5_P384: |
2611 | 0 | FALLTHROUGH_STATEMENT; |
2612 | 0 | case PGP_PKA_DILITHIUM3_BP256: |
2613 | 0 | FALLTHROUGH_STATEMENT; |
2614 | 0 | case PGP_PKA_DILITHIUM5_BP384: |
2615 | 0 | FALLTHROUGH_STATEMENT; |
2616 | 0 | case PGP_PKA_SPHINCSPLUS_SHA2: |
2617 | 0 | FALLTHROUGH_STATEMENT; |
2618 | 0 | case PGP_PKA_SPHINCSPLUS_SHAKE: |
2619 | 0 | return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); |
2620 | 0 | #endif |
2621 | | |
2622 | 0 | default: |
2623 | 0 | RNP_LOG("unknown pk alg: %d\n", alg); |
2624 | 0 | return PGP_KF_NONE; |
2625 | 0 | } |
2626 | 0 | } |