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 "charfuncs.h"
36 #include "keystructs.h"
40 #include "onak-conf.h"
43 struct onak_keyring_dbctx {
49 struct openpgp_fingerprint fp;
56 * starttrans - Start a transaction.
58 * This is just a no-op for keyring file access.
60 static bool keyring_starttrans(struct onak_dbctx *dbctx)
66 * endtrans - End a transaction.
68 * This is just a no-op for keyring file access.
70 static void keyring_endtrans(struct onak_dbctx *dbctx)
76 * keyring_fetch_key - fetch a key given its index
78 static int keyring_fetch_key(struct onak_keyring_dbctx *privctx,
80 struct openpgp_publickey **publickey)
82 struct openpgp_packet_list *packets = NULL;
83 struct buffer_ctx buf;
85 if (index > privctx->count)
88 buf.buffer = privctx->keys[index].start;
89 buf.size = privctx->keys[index].len;
92 read_openpgp_stream(buffer_fetchchar, &buf, &packets, 0);
93 parse_keys(packets, publickey);
94 free_packet_list(packets);
100 static int keyring_fetch_key_fp(struct onak_dbctx *dbctx,
101 struct openpgp_fingerprint *fingerprint,
102 struct openpgp_publickey **publickey,
105 struct onak_keyring_dbctx *privctx =
106 (struct onak_keyring_dbctx *) dbctx->priv;
109 for (i = 0; i < privctx->count; i++) {
110 if (fingerprint_cmp(fingerprint, &privctx->keys[i].fp) == 0)
114 if (i < privctx->count) {
115 return keyring_fetch_key(privctx, i, publickey);
122 * fetch_key_id - Given a keyid fetch the key from storage.
123 * @keyid: The keyid to fetch.
124 * @publickey: A pointer to a structure to return the key in.
125 * @intrans: If we're already in a transaction.
127 static int keyring_fetch_key_id(struct onak_dbctx *dbctx,
129 struct openpgp_publickey **publickey,
132 struct onak_keyring_dbctx *privctx =
133 (struct onak_keyring_dbctx *) dbctx->priv;
137 for (i = 0; i < privctx->count; i++) {
138 if (fingerprint2keyid(&privctx->keys[i].fp) == keyid) {
139 if (keyring_fetch_key(privctx, i, publickey))
148 * store_key - Takes a key and stores it.
149 * @publickey: A pointer to the public key to store.
150 * @intrans: If we're already in a transaction.
151 * @update: If true the key exists and should be updated.
153 * We don't support storing keys into a keyring file.
155 static int keyring_store_key(struct onak_dbctx *dbctx,
156 struct openpgp_publickey *publickey, bool intrans,
163 * delete_key - Given a keyid delete the key from storage.
164 * @fp: The fingerprint of the key to delete.
165 * @intrans: If we're already in a transaction.
167 * We don't support removing keys from a keyring file.
169 static int keyring_delete_key(struct onak_dbctx *dbctx,
170 struct openpgp_fingerprint *fp, bool intrans)
176 * fetch_key_text - Trys to find the keys that contain the supplied text.
177 * @search: The text to search for.
178 * @publickey: A pointer to a structure to return the key in.
180 * This function searches for the supplied text and returns the keys that
183 * TODO: Write for flat file access. Some sort of grep?
185 static int keyring_fetch_key_text(struct onak_dbctx *dbctx,
187 struct openpgp_publickey **publickey)
193 * iterate_keys - call a function once for each key in the db.
194 * @iterfunc: The function to call.
195 * @ctx: A context pointer
197 * Calls iterfunc once for each key in the database. ctx is passed
198 * unaltered to iterfunc. This function is intended to aid database dumps
199 * and statistic calculations.
201 * Returns the number of keys we iterated over.
203 static int keyring_iterate_keys(struct onak_dbctx *dbctx,
204 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
207 struct onak_keyring_dbctx *privctx =
208 (struct onak_keyring_dbctx *) dbctx->priv;
209 struct openpgp_publickey *key = NULL;
213 for (i = 0; i < privctx->count; i++) {
214 if (keyring_fetch_key(privctx, i, &key)) {
224 static int keyring_update_keys(struct onak_dbctx *dbctx,
225 struct openpgp_publickey **keys, bool sendsync)
231 * Include the basic keydb routines.
233 #define NEED_KEYID2UID 1
234 #define NEED_GETKEYSIGS 1
235 #define NEED_GETFULLKEYID 1
236 #define NEED_GET_FP 1
239 static int keyring_parse_keys(struct onak_keyring_dbctx *privctx)
241 size_t len, pos, start, totlen;
242 struct openpgp_publickey *key;
245 if (privctx == NULL) {
249 if (privctx->file == NULL) {
254 * Walk the keyring file, noting the start of each public key and the
255 * total length of packets associated with it.
257 len = pos = start = totlen = 0;
258 while (((privctx->length - pos) > 5) && (privctx->file[pos] & 0x80)) {
259 if (privctx->file[pos] & 0x40) {
260 tag = privctx->file[pos] & 0x3F;
261 len = privctx->file[pos + 1];
262 if (len > 191 && len < 224) {
265 len += privctx->file[pos + 2];
267 len += 1; /* Header */
268 } else if (len > 223 & len < 255) {
270 } else if (len == 255) {
271 len = privctx->file[pos + 2];
273 len += privctx->file[pos + 3];
275 len += privctx->file[pos + 4];
277 len += privctx->file[pos + 5];
278 len += 4; /* Header */
280 len += 2; /* Header */
282 tag = (privctx->file[pos] & 0x3C) >> 2;
283 switch (privctx->file[pos] & 3) {
285 len = privctx->file[pos + 1];
286 len += 2; /* Header */
289 len = privctx->file[pos + 1];
291 len += privctx->file[pos + 2];
292 len += 3; /* Header */
295 len = privctx->file[pos + 1];
297 len += privctx->file[pos + 2];
299 len += privctx->file[pos + 3];
301 len += privctx->file[pos + 4];
302 len += 5; /* Header */
309 if (tag == OPENPGP_PACKET_PUBLICKEY) {
311 /* Expand the array of keys if necessary */
312 if (privctx->count == privctx->space) {
314 privctx->keys = realloc(privctx->keys,
316 sizeof(*privctx->keys));
319 /* TODO: Sort by fingerprint? */
320 privctx->keys[privctx->count].start =
321 &privctx->file[start];
322 privctx->keys[privctx->count].len = totlen;
326 * We need to fetch the key to calculate the
329 keyring_fetch_key(privctx, privctx->count - 1,
331 get_fingerprint(key->publickey,
332 &privctx->keys[privctx->count - 1].fp);
343 return privctx->count;
347 * cleanupdb - De-initialize the key database.
349 * This is just a no-op for flat file access.
351 static void keyring_cleanupdb(struct onak_dbctx *dbctx)
353 struct onak_keyring_dbctx *privctx =
354 (struct onak_keyring_dbctx *) dbctx->priv;
356 if (dbctx->priv != NULL) {
357 if (privctx->file != NULL) {
358 munmap(privctx->file, privctx->length);
371 * initdb - Initialize the key database.
373 * This is just a no-op for flat file access.
375 struct onak_dbctx *keydb_keyring_init(struct onak_db_config *dbcfg,
378 struct onak_keyring_dbctx *privctx;
379 struct onak_dbctx *dbctx;
383 dbctx = malloc(sizeof(struct onak_dbctx));
387 dbctx->config = dbcfg;
388 dbctx->priv = privctx = calloc(1, sizeof(*privctx));
389 if (privctx == NULL) {
394 privctx->keys = calloc(privctx->space, sizeof(*privctx->keys));
396 fd = open(dbcfg->location, O_RDONLY);
398 logthing(LOGTHING_CRITICAL,
399 "Couldn't open keyring file %s: %s (%d)",
403 keyring_cleanupdb(dbctx);
406 if (fstat(fd, &sb) < 0) {
407 logthing(LOGTHING_CRITICAL,
408 "Couldn't stat keyring file %s: %s (%d)",
413 keyring_cleanupdb(dbctx);
416 privctx->file = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
417 if (privctx->file == MAP_FAILED) {
418 logthing(LOGTHING_CRITICAL,
419 "Couldn't mmap keyring file %s: %s (%d)",
423 privctx->file = NULL;
425 keyring_cleanupdb(dbctx);
428 privctx->length = sb.st_size;
431 if (keyring_parse_keys(privctx) == 0) {
432 logthing(LOGTHING_CRITICAL,
433 "Failed to load any keys from keyring file %s",
435 keyring_cleanupdb(dbctx);
439 dbctx->cleanupdb = keyring_cleanupdb;
440 dbctx->starttrans = keyring_starttrans;
441 dbctx->endtrans = keyring_endtrans;
442 dbctx->fetch_key_id = keyring_fetch_key_id;
443 dbctx->fetch_key_fp = keyring_fetch_key_fp;
444 dbctx->fetch_key_text = keyring_fetch_key_text;
445 dbctx->store_key = keyring_store_key;
446 dbctx->update_keys = keyring_update_keys;
447 dbctx->delete_key = keyring_delete_key;
448 dbctx->getkeysigs = generic_getkeysigs;
449 dbctx->cached_getkeysigs = generic_cached_getkeysigs;
450 dbctx->keyid2uid = generic_keyid2uid;
451 dbctx->getfullkeyid = generic_getfullkeyid;
452 dbctx->iterate_keys = keyring_iterate_keys;