2 * keydb_keyring.c - Routines to fetch keys from a PGP keyring file.
4 * Copyright 2019 Jonathan McDowell <noodles@earth.li>
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <https://www.gnu.org/licenses/>.
21 #include <sys/types.h>
32 #include "build-config.h"
33 #include "charfuncs.h"
37 #include "keystructs.h"
41 #include "onak-conf.h"
44 struct onak_keyring_dbctx {
50 struct openpgp_fingerprint fp;
57 * starttrans - Start a transaction.
59 * This is just a no-op for keyring file access.
61 static bool keyring_starttrans(__unused struct onak_dbctx *dbctx)
67 * endtrans - End a transaction.
69 * This is just a no-op for keyring file access.
71 static void keyring_endtrans(__unused struct onak_dbctx *dbctx)
77 * keyring_fetch_key - fetch a key given its index
79 static int keyring_fetch_key_idx(struct onak_keyring_dbctx *privctx,
81 struct openpgp_publickey **publickey)
83 struct openpgp_packet_list *packets = NULL;
84 struct buffer_ctx buf;
86 if (index > privctx->count)
89 buf.buffer = (char *) privctx->keys[index].start;
90 buf.size = privctx->keys[index].len;
93 read_openpgp_stream(buffer_fetchchar, &buf, &packets, 0);
94 parse_keys(packets, publickey);
95 free_packet_list(packets);
102 * We only index the primary fingerprint of the key, so will only return one
103 * key at most from this function.
105 static int keyring_fetch_key(struct onak_dbctx *dbctx,
106 struct openpgp_fingerprint *fingerprint,
107 struct openpgp_publickey **publickey,
108 __unused bool intrans)
110 struct onak_keyring_dbctx *privctx =
111 (struct onak_keyring_dbctx *) dbctx->priv;
114 for (i = 0; i < privctx->count; i++) {
115 if (fingerprint_cmp(fingerprint, &privctx->keys[i].fp) == 0)
119 if (i < privctx->count) {
120 return keyring_fetch_key_idx(privctx, i, publickey);
127 * fetch_key_id - Given a keyid fetch the key from storage.
128 * @keyid: The keyid to fetch.
129 * @publickey: A pointer to a structure to return the key in.
130 * @intrans: If we're already in a transaction.
132 static int keyring_fetch_key_id(struct onak_dbctx *dbctx,
134 struct openpgp_publickey **publickey,
135 __unused bool intrans)
137 struct onak_keyring_dbctx *privctx =
138 (struct onak_keyring_dbctx *) dbctx->priv;
142 for (i = 0; i < privctx->count; i++) {
143 if (fingerprint2keyid(&privctx->keys[i].fp) == keyid) {
144 if (keyring_fetch_key_idx(privctx, i, publickey))
153 * store_key - Takes a key and stores it.
154 * @publickey: A pointer to the public key to store.
155 * @intrans: If we're already in a transaction.
156 * @update: If true the key exists and should be updated.
158 * We don't support storing keys into a keyring file.
160 static int keyring_store_key(__unused struct onak_dbctx *dbctx,
161 __unused struct openpgp_publickey *publickey,
162 __unused bool intrans,
163 __unused bool update)
169 * delete_key - Given a keyid delete the key from storage.
170 * @fp: The fingerprint of the key to delete.
171 * @intrans: If we're already in a transaction.
173 * We don't support removing keys from a keyring file.
175 static int keyring_delete_key(__unused struct onak_dbctx *dbctx,
176 __unused struct openpgp_fingerprint *fp, __unused bool intrans)
182 * fetch_key_text - Trys to find the keys that contain the supplied text.
183 * @search: The text to search for.
184 * @publickey: A pointer to a structure to return the key in.
186 * This function searches for the supplied text and returns the keys that
189 * TODO: Write for flat file access. Some sort of grep?
191 static int keyring_fetch_key_text(__unused struct onak_dbctx *dbctx,
192 __unused const char *search,
193 __unused struct openpgp_publickey **publickey)
199 * iterate_keys - call a function once for each key in the db.
200 * @iterfunc: The function to call.
201 * @ctx: A context pointer
203 * Calls iterfunc once for each key in the database. ctx is passed
204 * unaltered to iterfunc. This function is intended to aid database dumps
205 * and statistic calculations.
207 * Returns the number of keys we iterated over.
209 static int keyring_iterate_keys(struct onak_dbctx *dbctx,
210 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
213 struct onak_keyring_dbctx *privctx =
214 (struct onak_keyring_dbctx *) dbctx->priv;
215 struct openpgp_publickey *key = NULL;
219 for (i = 0; i < privctx->count; i++) {
220 if (keyring_fetch_key_idx(privctx, i, &key)) {
230 static int keyring_update_keys(__unused struct onak_dbctx *dbctx,
231 __unused struct openpgp_publickey **keys,
232 __unused struct keyarray *blacklist,
233 __unused bool updateonly,
234 __unused bool sendsync)
240 * Include the basic keydb routines.
242 #define NEED_KEYID2UID 1
243 #define NEED_GETKEYSIGS 1
246 static int keyring_parse_keys(struct onak_keyring_dbctx *privctx)
248 size_t len, pos, start, totlen;
249 struct openpgp_publickey *key;
252 if (privctx == NULL) {
256 if (privctx->file == NULL) {
261 * Walk the keyring file, noting the start of each public key and the
262 * total length of packets associated with it.
264 len = pos = start = totlen = 0;
265 while (((privctx->length - pos) > 5) && (privctx->file[pos] & 0x80)) {
266 if (privctx->file[pos] & 0x40) {
267 tag = privctx->file[pos] & 0x3F;
268 len = privctx->file[pos + 1];
269 if (len > 191 && len < 224) {
272 len += privctx->file[pos + 2];
274 len += 1; /* Header */
275 } else if (len > 223 && len < 255) {
277 } else if (len == 255) {
278 len = privctx->file[pos + 2];
280 len += privctx->file[pos + 3];
282 len += privctx->file[pos + 4];
284 len += privctx->file[pos + 5];
285 len += 4; /* Header */
287 len += 2; /* Header */
289 tag = (privctx->file[pos] & 0x3C) >> 2;
290 switch (privctx->file[pos] & 3) {
292 len = privctx->file[pos + 1];
293 len += 2; /* Header */
296 len = privctx->file[pos + 1];
298 len += privctx->file[pos + 2];
299 len += 3; /* Header */
302 len = privctx->file[pos + 1];
304 len += privctx->file[pos + 2];
306 len += privctx->file[pos + 3];
308 len += privctx->file[pos + 4];
309 len += 5; /* Header */
316 if (tag == OPENPGP_PACKET_PUBLICKEY) {
318 /* Expand the array of keys if necessary */
319 if (privctx->count == privctx->space) {
321 privctx->keys = realloc(privctx->keys,
323 sizeof(*privctx->keys));
326 /* TODO: Sort by fingerprint? */
327 privctx->keys[privctx->count].start =
328 &privctx->file[start];
329 privctx->keys[privctx->count].len = totlen;
333 * We need to fetch the key to calculate the
336 keyring_fetch_key_idx(privctx,
339 get_fingerprint(key->publickey,
340 &privctx->keys[privctx->count - 1].fp);
351 return privctx->count;
355 * cleanupdb - De-initialize the key database.
357 * This is just a no-op for flat file access.
359 static void keyring_cleanupdb(struct onak_dbctx *dbctx)
361 struct onak_keyring_dbctx *privctx =
362 (struct onak_keyring_dbctx *) dbctx->priv;
364 if (dbctx->priv != NULL) {
365 if (privctx->file != NULL) {
366 munmap(privctx->file, privctx->length);
379 * initdb - Initialize the key database.
381 * This is just a no-op for flat file access.
383 struct onak_dbctx *keydb_keyring_init(struct onak_db_config *dbcfg,
384 __unused bool readonly)
386 struct onak_keyring_dbctx *privctx;
387 struct onak_dbctx *dbctx;
391 dbctx = malloc(sizeof(struct onak_dbctx));
395 dbctx->config = dbcfg;
396 dbctx->priv = privctx = calloc(1, sizeof(*privctx));
397 if (privctx == NULL) {
402 privctx->keys = calloc(privctx->space, sizeof(*privctx->keys));
404 fd = open(dbcfg->location, O_RDONLY);
406 logthing(LOGTHING_CRITICAL,
407 "Couldn't open keyring file %s: %s (%d)",
411 keyring_cleanupdb(dbctx);
414 if (fstat(fd, &sb) < 0) {
415 logthing(LOGTHING_CRITICAL,
416 "Couldn't stat keyring file %s: %s (%d)",
421 keyring_cleanupdb(dbctx);
424 privctx->file = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
425 if (privctx->file == MAP_FAILED) {
426 logthing(LOGTHING_CRITICAL,
427 "Couldn't mmap keyring file %s: %s (%d)",
431 privctx->file = NULL;
433 keyring_cleanupdb(dbctx);
436 privctx->length = sb.st_size;
439 if (keyring_parse_keys(privctx) == 0) {
440 logthing(LOGTHING_CRITICAL,
441 "Failed to load any keys from keyring file %s",
443 keyring_cleanupdb(dbctx);
447 dbctx->cleanupdb = keyring_cleanupdb;
448 dbctx->starttrans = keyring_starttrans;
449 dbctx->endtrans = keyring_endtrans;
450 dbctx->fetch_key = keyring_fetch_key;
451 /* We don't index by subkey fingerprint, so fallback to fetch_key */
452 dbctx->fetch_key_fp = keyring_fetch_key;
453 dbctx->fetch_key_id = keyring_fetch_key_id;
454 dbctx->fetch_key_text = keyring_fetch_key_text;
455 dbctx->store_key = keyring_store_key;
456 dbctx->update_keys = keyring_update_keys;
457 dbctx->delete_key = keyring_delete_key;
458 dbctx->getkeysigs = generic_getkeysigs;
459 dbctx->cached_getkeysigs = generic_cached_getkeysigs;
460 dbctx->keyid2uid = generic_keyid2uid;
461 dbctx->iterate_keys = keyring_iterate_keys;