Coverage Report

Created: 2026-03-26 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rnp/src/librekey/rnp_key_store.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2017-2023 [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 "config.h"
28
#include <sys/stat.h>
29
#include <sys/types.h>
30
#ifdef HAVE_SYS_PARAM_H
31
#include <sys/param.h>
32
#else
33
#include "uniwin.h"
34
#endif
35
36
#include <assert.h>
37
#include <stdio.h>
38
#include <string.h>
39
#include <stdint.h>
40
#include <stdlib.h>
41
#include <dirent.h>
42
#include <errno.h>
43
#include <algorithm>
44
#include <stdexcept>
45
46
#include <rekey/rnp_key_store.h>
47
#include <librepgp/stream-packet.h>
48
49
#include "key_store_g10.h"
50
#include "kbx_blob.hpp"
51
52
#include "key.hpp"
53
#include "fingerprint.hpp"
54
#include "crypto/hash.hpp"
55
#include "crypto/mem.h"
56
#include "file-utils.h"
57
#ifdef _WIN32
58
#include "str-utils.h"
59
#endif
60
61
namespace rnp {
62
bool
63
KeyStore::load(const KeyProvider *key_provider)
64
0
{
65
0
    pgp_source_t src = {};
66
67
0
    if (format == KeyFormat::G10) {
68
0
        auto dir = rnp_opendir(path.c_str());
69
0
        if (!dir) {
70
0
            RNP_LOG("Can't open G10 directory %s: %s", path.c_str(), strerror(errno));
71
0
            return false;
72
0
        }
73
74
0
        std::string dirname;
75
0
        while (!((dirname = rnp_readdir_name(dir)).empty())) {
76
0
            std::string apath = path::append(path, dirname);
77
78
0
            if (init_file_src(&src, apath.c_str())) {
79
0
                RNP_LOG("failed to read file %s", apath.c_str());
80
0
                continue;
81
0
            }
82
            // G10 may fail to read one file, so ignore it!
83
0
            if (!load_g10(src, key_provider)) {
84
0
                RNP_LOG("Can't parse file: %s", apath.c_str()); // TODO: %S ?
85
0
            }
86
0
            src.close();
87
0
        }
88
0
        rnp_closedir(dir);
89
0
        return true;
90
0
    }
91
92
    /* init file source and load from it */
93
0
    if (init_file_src(&src, path.c_str())) {
94
0
        RNP_LOG("failed to read file %s", path.c_str());
95
0
        return false;
96
0
    }
97
98
0
    bool rc = load(src, key_provider);
99
0
    src.close();
100
0
    return rc;
101
0
}
102
103
bool
104
KeyStore::load(pgp_source_t &src, const KeyProvider *key_provider)
105
21.9k
{
106
21.9k
    switch (format) {
107
12.4k
    case KeyFormat::GPG:
108
12.4k
        return !load_pgp(src);
109
9.49k
    case KeyFormat::KBX:
110
9.49k
        return load_kbx(src, key_provider);
111
0
    case KeyFormat::G10:
112
0
        return load_g10(src, key_provider);
113
0
    default:
114
0
        RNP_LOG("Unsupported load from memory for key-store format: %d",
115
21.9k
                static_cast<int>(format));
116
21.9k
    }
117
118
0
    return false;
119
21.9k
}
120
121
bool
122
KeyStore::write()
123
0
{
124
0
    bool       rc;
125
0
    pgp_dest_t keydst = {};
126
127
    /* write g10 key store to the directory */
128
0
    if (format == KeyFormat::G10) {
129
0
        char chpath[MAXPATHLEN];
130
131
0
        struct stat path_stat;
132
0
        if (rnp_stat(path.c_str(), &path_stat) != -1) {
133
0
            if (!S_ISDIR(path_stat.st_mode)) {
134
0
                RNP_LOG("G10 keystore should be a directory: %s", path.c_str());
135
0
                return false;
136
0
            }
137
0
        } else {
138
0
            if (errno != ENOENT) {
139
0
                RNP_LOG("stat(%s): %s", path.c_str(), strerror(errno));
140
0
                return false;
141
0
            }
142
0
            if (RNP_MKDIR(path.c_str(), S_IRWXU) != 0) {
143
0
                RNP_LOG("mkdir(%s, S_IRWXU): %s", path.c_str(), strerror(errno));
144
0
                return false;
145
0
            }
146
0
        }
147
148
0
        for (auto &key : keys) {
149
0
            auto grip = bin_to_hex(key.grip().data(), key.grip().size());
150
0
            snprintf(chpath, sizeof(chpath), "%s/%s.key", path.c_str(), grip.c_str());
151
152
0
            if (init_tmpfile_dest(&keydst, chpath, true)) {
153
0
                RNP_LOG("failed to create file");
154
0
                return false;
155
0
            }
156
157
0
            if (!rnp_key_store_gnupg_sexp_to_dst(key, keydst)) {
158
0
                RNP_LOG("failed to write key to file");
159
0
                dst_close(&keydst, true);
160
0
                return false;
161
0
            }
162
163
0
            rc = dst_finish(&keydst) == RNP_SUCCESS;
164
0
            dst_close(&keydst, !rc);
165
166
0
            if (!rc) {
167
0
                return false;
168
0
            }
169
0
        }
170
171
0
        return true;
172
0
    }
173
174
    /* write kbx/gpg store to the single file */
175
0
    if (init_tmpfile_dest(&keydst, path.c_str(), true)) {
176
0
        RNP_LOG("failed to create keystore file");
177
0
        return false;
178
0
    }
179
180
0
    if (!write(keydst)) {
181
0
        RNP_LOG("failed to write keys to file");
182
0
        dst_close(&keydst, true);
183
0
        return false;
184
0
    }
185
186
0
    rc = dst_finish(&keydst) == RNP_SUCCESS;
187
0
    dst_close(&keydst, !rc);
188
0
    return rc;
189
0
}
190
191
bool
192
KeyStore::write(pgp_dest_t &dst)
193
0
{
194
0
    switch (format) {
195
0
    case KeyFormat::GPG:
196
0
        return write_pgp(dst);
197
0
    case KeyFormat::KBX:
198
0
        return write_kbx(dst);
199
0
    default:
200
0
        RNP_LOG("Unsupported write to memory for key-store format: %d",
201
0
                static_cast<int>(format));
202
0
    }
203
204
0
    return false;
205
0
}
206
207
void
208
KeyStore::clear()
209
362k
{
210
362k
    keybyfp.clear();
211
362k
    keys.clear();
212
362k
    blobs.clear();
213
362k
}
214
215
size_t
216
KeyStore::key_count() const
217
0
{
218
0
    return keys.size();
219
0
}
220
221
bool
222
KeyStore::refresh_subkey_grips(Key &key)
223
215k
{
224
215k
    if (key.is_subkey()) {
225
0
        RNP_LOG("wrong argument");
226
0
        return false;
227
0
    }
228
229
1.30M
    for (auto &skey : keys) {
230
1.30M
        bool found = false;
231
232
        /* if we have primary_grip then we also added to subkey_grips */
233
1.30M
        if (!skey.is_subkey() || skey.has_primary_fp()) {
234
1.29M
            continue;
235
1.29M
        }
236
237
19.3k
        for (size_t i = 0; i < skey.sig_count(); i++) {
238
15.1k
            auto &subsig = skey.get_sig(i);
239
240
15.1k
            if (subsig.sig.type() != PGP_SIG_SUBKEY) {
241
11.6k
                continue;
242
11.6k
            }
243
3.49k
            if (subsig.sig.has_keyfp() && (key.fp() == subsig.sig.keyfp())) {
244
340
                found = true;
245
340
                break;
246
340
            }
247
3.15k
            if (subsig.sig.has_keyid() && (key.keyid() == subsig.sig.keyid())) {
248
369
                found = true;
249
369
                break;
250
369
            }
251
3.15k
        }
252
253
4.90k
        if (found) {
254
709
            try {
255
709
                key.link_subkey_fp(skey);
256
709
            } catch (const std::exception &e) {
257
                /* LCOV_EXCL_START */
258
0
                RNP_LOG("%s", e.what());
259
0
                return false;
260
                /* LCOV_EXCL_END */
261
0
            }
262
709
        }
263
4.90k
    }
264
265
215k
    return true;
266
215k
}
267
268
Key *
269
KeyStore::add_subkey(Key &srckey, Key *oldkey)
270
247k
{
271
247k
    Key *primary = NULL;
272
247k
    if (oldkey) {
273
128k
        primary = primary_key(*oldkey);
274
128k
    }
275
247k
    if (!primary) {
276
135k
        primary = primary_key(srckey);
277
135k
    }
278
279
247k
    if (oldkey) {
280
        /* check for the weird case when same subkey has different primary keys */
281
128k
        if (srckey.has_primary_fp() && oldkey->has_primary_fp() &&
282
115k
            (srckey.primary_fp() != oldkey->primary_fp())) {
283
40.1k
            RNP_LOG_KEY("Warning: different primary keys for subkey %s", &srckey);
284
40.1k
            auto *srcprim = get_key(srckey.primary_fp());
285
40.1k
            if (srcprim && (srcprim != primary)) {
286
29.5k
                srcprim->remove_subkey_fp(srckey.fp());
287
29.5k
            }
288
40.1k
        }
289
        /* in case we already have key let's merge it in */
290
128k
        if (!oldkey->merge(srckey, primary)) {
291
0
            RNP_LOG_KEY("failed to merge subkey %s", &srckey);
292
0
            RNP_LOG_KEY("primary key is %s", primary);
293
0
            return NULL;
294
0
        }
295
128k
    } else {
296
119k
        try {
297
119k
            keys.emplace_back();
298
119k
            oldkey = &keys.back();
299
119k
            keybyfp[srckey.fp()] = std::prev(keys.end());
300
119k
            *oldkey = Key(srckey);
301
119k
            if (primary) {
302
98.6k
                primary->link_subkey_fp(*oldkey);
303
98.6k
            }
304
119k
        } catch (const std::exception &e) {
305
            /* LCOV_EXCL_START */
306
0
            RNP_LOG_KEY("key %s copying failed", &srckey);
307
0
            RNP_LOG_KEY("primary key is %s", primary);
308
0
            RNP_LOG("%s", e.what());
309
0
            if (oldkey) {
310
0
                keys.pop_back();
311
0
                keybyfp.erase(srckey.fp());
312
0
            }
313
0
            return nullptr;
314
            /* LCOV_EXCL_END */
315
0
        }
316
119k
    }
317
318
    /* validate all added keys if not disabled */
319
247k
    if (!disable_validation && !oldkey->validated()) {
320
22.5k
        oldkey->validate_subkey(primary, secctx);
321
22.5k
    }
322
247k
    if (!oldkey->refresh_data(primary, secctx)) {
323
0
        RNP_LOG_KEY("Failed to refresh subkey %s data", &srckey);
324
0
        RNP_LOG_KEY("primary key is %s", primary);
325
0
    }
326
247k
    return oldkey;
327
247k
}
328
329
/* add a key to keyring */
330
Key *
331
KeyStore::add_key(Key &srckey)
332
714k
{
333
714k
    assert(srckey.type() && srckey.version());
334
714k
    auto *added_key = get_key(srckey.fp());
335
    /* we cannot merge G10 keys - so just return it */
336
714k
    if (added_key && (srckey.format == KeyFormat::G10)) {
337
0
        return added_key;
338
0
    }
339
    /* different processing for subkeys */
340
714k
    if (srckey.is_subkey()) {
341
247k
        return add_subkey(srckey, added_key);
342
247k
    }
343
344
466k
    if (added_key) {
345
251k
        if (!added_key->merge(srckey)) {
346
0
            RNP_LOG_KEY("failed to merge key %s", &srckey);
347
0
            return NULL;
348
0
        }
349
251k
    } else {
350
215k
        try {
351
215k
            keys.emplace_back();
352
215k
            added_key = &keys.back();
353
215k
            keybyfp[srckey.fp()] = std::prev(keys.end());
354
215k
            *added_key = Key(srckey);
355
            /* primary key may be added after subkeys, so let's handle this case correctly */
356
215k
            if (!refresh_subkey_grips(*added_key)) {
357
0
                RNP_LOG_KEY("failed to refresh subkey grips for %s", added_key);
358
0
            }
359
215k
        } catch (const std::exception &e) {
360
            /* LCOV_EXCL_START */
361
0
            RNP_LOG_KEY("key %s copying failed", &srckey);
362
0
            RNP_LOG("%s", e.what());
363
0
            if (added_key) {
364
0
                keys.pop_back();
365
0
                keybyfp.erase(srckey.fp());
366
0
            }
367
0
            return NULL;
368
            /* LCOV_EXCL_END */
369
0
        }
370
215k
    }
371
372
    /* validate all added keys if not disabled or already validated */
373
466k
    if (!disable_validation && !added_key->validated()) {
374
147
        added_key->revalidate(*this);
375
466k
    } else if (!added_key->refresh_data(secctx)) {
376
5.36k
        RNP_LOG_KEY("Failed to refresh key %s data", &srckey);
377
5.36k
    }
378
    /* Revalidate non-self revocations for all keys in keyring, as added_key key could be a
379
     * revoker. Should not be time-consuming as `validate_desig_revokes()` has early exit. */
380
4.45M
    for (auto &key : keys) {
381
4.45M
        if (&key == added_key) {
382
466k
            continue;
383
466k
        }
384
3.98M
        if (key.validate_desig_revokes(*this)) {
385
56
            key.revalidate(*this);
386
56
        }
387
3.98M
    }
388
466k
    return added_key;
389
466k
}
390
391
Signature *
392
KeyStore::add_key_sig(const pgp::Fingerprint &   keyfp,
393
                      const pgp::pkt::Signature &sig,
394
                      const pgp_userid_pkt_t *   uid,
395
                      bool                       front)
396
0
{
397
0
    auto *key = get_key(keyfp);
398
0
    if (!key) {
399
0
        return nullptr;
400
0
    }
401
402
0
    bool  desig_rev = false;
403
0
    auto *signer = get_signer(sig);
404
0
    switch (sig.type()) {
405
0
    case PGP_SIG_REV_KEY:
406
0
        desig_rev = signer && (signer->fp() != key->fp());
407
0
        break;
408
0
    case PGP_SIG_REV_SUBKEY:
409
0
        desig_rev = signer && (signer->fp() != key->primary_fp());
410
0
        break;
411
0
    default:
412
0
        break;
413
0
    }
414
    /* Add to the keyring(s) */
415
0
    uint32_t uididx = UserID::None;
416
0
    if (uid) {
417
0
        uididx = key->uid_idx(*uid);
418
0
        if (uididx == UserID::None) {
419
0
            RNP_LOG("Attempt to add signature on non-existing userid.");
420
0
            return nullptr;
421
0
        }
422
0
    }
423
0
    auto &newsig = key->add_sig(sig, uididx, front);
424
0
    if (desig_rev) {
425
0
        key->validate_desig_revokes(*this);
426
0
    }
427
0
    if (key->is_primary()) {
428
0
        key->refresh_data(secctx);
429
0
    } else {
430
0
        key->refresh_data(primary_key(*key), secctx);
431
0
    }
432
0
    return &newsig;
433
0
}
434
435
Key *
436
KeyStore::import_key(Key &srckey, bool pubkey, pgp_key_import_status_t *status)
437
228k
{
438
    /* add public key */
439
228k
    auto * exkey = get_key(srckey.fp());
440
228k
    size_t expackets = exkey ? exkey->rawpkt_count() : 0;
441
228k
    try {
442
228k
        Key keycp(srckey, pubkey);
443
228k
        disable_validation = true;
444
228k
        exkey = add_key(keycp);
445
228k
        disable_validation = false;
446
228k
        if (!exkey) {
447
0
            RNP_LOG("failed to add key to the keyring");
448
0
            return nullptr;
449
0
        }
450
228k
        bool changed = exkey->rawpkt_count() > expackets;
451
228k
        if (changed || !exkey->validated()) {
452
            /* this will revalidate primary key with all of its subkeys */
453
223k
            exkey->revalidate(*this);
454
223k
        }
455
228k
        if (status) {
456
180k
            *status = changed ? (expackets ? PGP_KEY_IMPORT_STATUS_UPDATED :
457
88.9k
                                             PGP_KEY_IMPORT_STATUS_NEW) :
458
180k
                                PGP_KEY_IMPORT_STATUS_UNCHANGED;
459
180k
        }
460
228k
        return exkey;
461
228k
    } catch (const std::exception &e) {
462
        /* LCOV_EXCL_START */
463
138
        RNP_LOG("%s", e.what());
464
138
        disable_validation = false;
465
138
        return nullptr;
466
        /* LCOV_EXCL_END */
467
138
    }
468
228k
}
469
470
pgp_sig_import_status_t
471
KeyStore::import_subkey_signature(Key &key, const pgp::pkt::Signature &sig)
472
0
{
473
0
    if ((sig.type() != PGP_SIG_SUBKEY) && (sig.type() != PGP_SIG_REV_SUBKEY)) {
474
0
        return PGP_SIG_IMPORT_STATUS_UNKNOWN;
475
0
    }
476
0
    auto *primary = get_signer(sig);
477
0
    if (!primary || !key.has_primary_fp()) {
478
0
        RNP_LOG("No primary grip or primary key");
479
0
        return PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY;
480
0
    }
481
0
    if (primary->fp() != key.primary_fp()) {
482
0
        RNP_LOG("Wrong subkey signature's signer.");
483
0
        return PGP_SIG_IMPORT_STATUS_UNKNOWN;
484
0
    }
485
486
0
    try {
487
0
        Key tmpkey(key.pkt());
488
0
        tmpkey.add_sig(sig);
489
0
        if (!tmpkey.refresh_data(primary, secctx)) {
490
0
            RNP_LOG("Failed to add signature to the key.");
491
0
            return PGP_SIG_IMPORT_STATUS_UNKNOWN;
492
0
        }
493
494
0
        size_t expackets = key.rawpkt_count();
495
0
        auto   nkey = add_key(tmpkey);
496
0
        if (!nkey) {
497
0
            RNP_LOG("Failed to add key with imported sig to the keyring");
498
0
            return PGP_SIG_IMPORT_STATUS_UNKNOWN;
499
0
        }
500
0
        return (nkey->rawpkt_count() > expackets) ? PGP_SIG_IMPORT_STATUS_NEW :
501
0
                                                    PGP_SIG_IMPORT_STATUS_UNCHANGED;
502
0
    } catch (const std::exception &e) {
503
        /* LCOV_EXCL_START */
504
0
        RNP_LOG("%s", e.what());
505
0
        return PGP_SIG_IMPORT_STATUS_UNKNOWN;
506
        /* LCOV_EXCL_END */
507
0
    }
508
0
}
509
510
pgp_sig_import_status_t
511
KeyStore::import_signature(Key &key, const pgp::pkt::Signature &sig)
512
0
{
513
0
    if (key.is_subkey()) {
514
0
        return import_subkey_signature(key, sig);
515
0
    }
516
0
    if ((sig.type() != PGP_SIG_DIRECT) && (sig.type() != PGP_SIG_REV_KEY)) {
517
0
        RNP_LOG("Wrong signature type: %d", (int) sig.type());
518
0
        return PGP_SIG_IMPORT_STATUS_UNKNOWN;
519
0
    }
520
521
0
    try {
522
0
        Key tmpkey(key.pkt());
523
0
        tmpkey.add_sig(sig);
524
0
        if (!tmpkey.refresh_data(secctx)) {
525
0
            RNP_LOG("Failed to add signature to the key.");
526
0
            return PGP_SIG_IMPORT_STATUS_UNKNOWN;
527
0
        }
528
529
0
        size_t expackets = key.rawpkt_count();
530
0
        auto   nkey = add_key(tmpkey);
531
0
        if (!nkey) {
532
0
            RNP_LOG("Failed to add key with imported sig to the keyring");
533
0
            return PGP_SIG_IMPORT_STATUS_UNKNOWN;
534
0
        }
535
0
        return (nkey->rawpkt_count() > expackets) ? PGP_SIG_IMPORT_STATUS_NEW :
536
0
                                                    PGP_SIG_IMPORT_STATUS_UNCHANGED;
537
0
    } catch (const std::exception &e) {
538
        /* LCOV_EXCL_START */
539
0
        RNP_LOG("%s", e.what());
540
0
        return PGP_SIG_IMPORT_STATUS_UNKNOWN;
541
        /* LCOV_EXCL_END */
542
0
    }
543
0
}
544
545
Key *
546
KeyStore::import_signature(const pgp::pkt::Signature &sig, pgp_sig_import_status_t *status)
547
13.5k
{
548
13.5k
    pgp_sig_import_status_t tmp_status = PGP_SIG_IMPORT_STATUS_UNKNOWN;
549
13.5k
    if (!status) {
550
0
        status = &tmp_status;
551
0
    }
552
13.5k
    *status = PGP_SIG_IMPORT_STATUS_UNKNOWN;
553
554
    /* we support only direct-key and key revocation signatures here */
555
13.5k
    if ((sig.type() != PGP_SIG_DIRECT) && (sig.type() != PGP_SIG_REV_KEY)) {
556
5.60k
        return nullptr;
557
5.60k
    }
558
559
7.91k
    auto *res_key = get_signer(sig);
560
7.91k
    if (!res_key || !res_key->is_primary()) {
561
7.91k
        *status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY;
562
7.91k
        return nullptr;
563
7.91k
    }
564
0
    *status = import_signature(*res_key, sig);
565
0
    return res_key;
566
7.91k
}
567
568
bool
569
KeyStore::remove_key(const Key &key, bool subkeys)
570
1.58k
{
571
1.58k
    auto it = keybyfp.find(key.fp());
572
1.58k
    if (it == keybyfp.end()) {
573
0
        return false;
574
0
    }
575
576
    /* cleanup primary_grip (or subkey)/subkey_grips */
577
1.58k
    if (key.is_primary() && key.subkey_count()) {
578
3.71k
        for (size_t i = 0; i < key.subkey_count(); i++) {
579
2.51k
            auto its = keybyfp.find(key.get_subkey_fp(i));
580
2.51k
            if (its == keybyfp.end()) {
581
0
                continue;
582
0
            }
583
            /* if subkeys are deleted then no need to update grips */
584
2.51k
            if (subkeys) {
585
0
                keys.erase(its->second);
586
0
                keybyfp.erase(its);
587
0
                continue;
588
0
            }
589
2.51k
            its->second->unset_primary_fp();
590
2.51k
        }
591
1.20k
    }
592
1.58k
    if (key.is_subkey() && key.has_primary_fp()) {
593
50
        auto *primary = primary_key(key);
594
50
        if (primary) {
595
49
            primary->remove_subkey_fp(key.fp());
596
49
        }
597
50
    }
598
599
1.58k
    keys.erase(it->second);
600
1.58k
    keybyfp.erase(it);
601
1.58k
    return true;
602
1.58k
}
603
604
const Key *
605
KeyStore::get_key(const pgp::Fingerprint &fpr) const
606
0
{
607
0
    auto it = keybyfp.find(fpr);
608
0
    if (it == keybyfp.end()) {
609
0
        return nullptr;
610
0
    }
611
0
    return &*it->second;
612
0
}
613
614
Key *
615
KeyStore::get_key(const pgp::Fingerprint &fpr)
616
2.65M
{
617
2.65M
    auto it = keybyfp.find(fpr);
618
2.65M
    if (it == keybyfp.end()) {
619
603k
        return nullptr;
620
603k
    }
621
2.05M
    return &*it->second;
622
2.65M
}
623
624
Key *
625
KeyStore::get_subkey(const Key &key, size_t idx)
626
522k
{
627
522k
    if (idx >= key.subkey_count()) {
628
0
        return nullptr;
629
0
    }
630
522k
    return get_key(key.get_subkey_fp(idx));
631
522k
}
632
633
Key *
634
KeyStore::primary_key(const Key &subkey)
635
361k
{
636
361k
    if (!subkey.is_subkey()) {
637
1.15k
        return nullptr;
638
1.15k
    }
639
640
360k
    if (subkey.has_primary_fp()) {
641
308k
        Key *primary = get_key(subkey.primary_fp());
642
308k
        return primary && primary->is_primary() ? primary : nullptr;
643
308k
    }
644
645
297k
    for (size_t i = 0; i < subkey.sig_count(); i++) {
646
250k
        auto &subsig = subkey.get_sig(i);
647
250k
        if (subsig.sig.type() != PGP_SIG_SUBKEY) {
648
218k
            continue;
649
218k
        }
650
651
31.9k
        Key *primary = get_signer(subsig.sig);
652
31.9k
        if (primary && primary->is_primary()) {
653
4.41k
            return primary;
654
4.41k
        }
655
31.9k
    }
656
47.2k
    return nullptr;
657
51.6k
}
658
659
Key *
660
KeyStore::search(const KeySearch &search, Key *after)
661
399k
{
662
    // since keys are distinguished by fingerprint then just do map lookup
663
399k
    if (search.type() == KeySearch::Type::Fingerprint) {
664
90.3k
        auto fpsearch = dynamic_cast<const KeyFingerprintSearch *>(&search);
665
90.3k
        assert(fpsearch != nullptr);
666
90.3k
        auto key = get_key(fpsearch->get_fp());
667
90.3k
        if (after && (after != key)) {
668
0
            RNP_LOG("searching with invalid after param");
669
0
            return nullptr;
670
0
        }
671
        // return NULL if after is specified
672
90.3k
        return after ? nullptr : key;
673
90.3k
    }
674
675
    // if after is provided, make sure it is a member of the appropriate list
676
309k
    auto it = std::find_if(
677
309k
      keys.begin(), keys.end(), [after](const Key &key) { return !after || (after == &key); });
678
309k
    if (after && (it == keys.end())) {
679
0
        RNP_LOG("searching with non-keyrings after param");
680
0
        return nullptr;
681
0
    }
682
309k
    if (after) {
683
0
        it = std::next(it);
684
0
    }
685
309k
    it =
686
309k
      std::find_if(it, keys.end(), [&search](const Key &key) { return search.matches(key); });
687
309k
    return (it == keys.end()) ? nullptr : &(*it);
688
309k
}
689
690
Key *
691
KeyStore::get_signer(const pgp::pkt::Signature &sig, const KeyProvider *prov)
692
121k
{
693
    /* if we have fingerprint let's check it */
694
121k
    std::unique_ptr<KeySearch> ks;
695
121k
    if (sig.has_keyfp()) {
696
88.6k
        ks = KeySearch::create(sig.keyfp());
697
88.6k
    } else if (sig.has_keyid()) {
698
16.4k
        ks = KeySearch::create(sig.keyid());
699
16.6k
    } else {
700
16.6k
        RNP_LOG("No way to search for the signer.");
701
16.6k
        return nullptr;
702
16.6k
    }
703
704
105k
    auto key = search(*ks);
705
105k
    if (key || !prov) {
706
105k
        return key;
707
105k
    }
708
0
    return prov->request_key(*ks, PGP_OP_VERIFY);
709
105k
}
710
711
KeyStore::KeyStore(const std::string &_path, SecurityContext &ctx, KeyFormat _format)
712
358k
    : secctx(ctx)
713
358k
{
714
358k
    if (_format == KeyFormat::Unknown) {
715
0
        RNP_LOG("Invalid key store format");
716
0
        throw std::invalid_argument("format");
717
0
    }
718
358k
    format = _format;
719
358k
    path = _path;
720
358k
}
721
722
KeyStore::~KeyStore()
723
362k
{
724
362k
    clear();
725
362k
}
726
} // namespace rnp