From e82fd57b92d94287f728e37a3e17aaab11b722b8 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Thu, 14 Sep 2023 11:29:08 +0530 Subject: [PATCH] Add a helper for reading OpenPGP packets from a file Provide a convenience function for opening a file, working out if it's ASCII-armoured or binary, and loading the packets contained within it. --- CMakeLists.txt | 6 ++-- key-store.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ key-store.h | 41 +++++++++++++++++++++++++ keydb/keydb_file.c | 23 ++++++-------- keydb/keydb_fs.c | 24 ++++++++------- onak.h | 1 + 6 files changed, 143 insertions(+), 28 deletions(-) create mode 100644 key-store.c create mode 100644 key-store.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 581e849..f755cf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,9 +36,9 @@ endif() # Core objects add_library(libonak STATIC armor.c charfuncs.c cleankey.c cleanup.c decodekey.c - getcgi.c hash.c hash-helper.c keyarray.c keyid.c keyindex.c ll.c log.c - marshal.c mem.c merge.c onak-conf.c parsekey.c photoid.c rsa.c - sigcheck.c sendsync.c sha1x.c wordlist.c) + getcgi.c hash.c hash-helper.c key-store.c keyarray.c keyid.c keyindex.c + ll.c log.c marshal.c mem.c merge.c onak-conf.c parsekey.c photoid.c + rsa.c sigcheck.c sendsync.c sha1x.c wordlist.c) set(LIBONAK_LIBRARIES "") # Ideally use Nettle, fall back to our own md5/sha1 routines otherwise diff --git a/key-store.c b/key-store.c new file mode 100644 index 0000000..e7b0d3e --- /dev/null +++ b/key-store.c @@ -0,0 +1,76 @@ +/* + * key-store.c - High level routines to load + save OpenPGP packets/keys + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include + +#include "build-config.h" + +#include "armor.h" +#include "charfuncs.h" +#include "key-store.h" +#include "keystructs.h" +#include "onak.h" +#include "parsekey.h" + +/** + * onak_read_openpgp_file - Reads a set of OpenPGP packets from a file + * @file: The file to open and read + * @packets: The returned packet list + * + * This function opens the supplied file and tries to parse it as a set + * of OpenPGP packets. It will attempt to autodetect if the file is ASCII + * armored, or binary packets, and adapt accordingly. The packets read are + * returned in the packets parameter. It is the callers responsbility to + * free the packet memory when it is no longe required, e.g. using + * free_packet_list. + * + * Returns a status code indicating any error. + */ +onak_status_t onak_read_openpgp_file(const char *file, + struct openpgp_packet_list **packets) +{ + onak_status_t res; + int fd, ret; + char c; + + fd = open(file, O_RDONLY); + if (fd < 0) { + return (errno == ENOENT) ? ONAK_E_NOT_FOUND : ONAK_E_IO_ERROR; + } + + /* Peek at the first byte in the file */ + ret = read(fd, &c, 1); + if (ret != 1) { + return ONAK_E_IO_ERROR; + } + lseek(fd, 0, SEEK_SET); + + /* + * A binary OpenPGP packet will have the top bit set on its first byte, + * so we use that to determine if we should try to process the stream + * as binary or ASCII armored data. + */ + if (c & 0x80) { + res = read_openpgp_stream(file_fetchchar, &fd, + packets, 0); + } else { + res = dearmor_openpgp_stream(file_fetchchar, &fd, packets); + } + + return res; +} diff --git a/key-store.h b/key-store.h new file mode 100644 index 0000000..7af972a --- /dev/null +++ b/key-store.h @@ -0,0 +1,41 @@ +/* + * key-store.h - High level routines to load + save OpenPGP packets/keys + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __KEY_STORE_H__ +#define __KEY_STORE_H__ + +#include "build-config.h" +#include "keystructs.h" +#include "onak.h" + +/** + * onak_read_openpgp_file - Reads a set of OpenPGP packets from a file + * @file: The file to open and read + * @packets: The returned packet list + * + * This function opens the supplied file and tries to parse it as a set + * of OpenPGP packets. It will attempt to autodetect if the file is ASCII + * armored, or binary packets, and adapt accordingly. The packets read are + * returned in the packets parameter. It is the callers responsbility to + * free the packet memory when it is no longe required, e.g. using + * free_packet_list. + * + * Returns a status code indicating any error. + */ +onak_status_t onak_read_openpgp_file(const char *file, + struct openpgp_packet_list **packets); + +#endif /* __KEY_STORE_H__ */ diff --git a/keydb/keydb_file.c b/keydb/keydb_file.c index d396364..91b42c5 100644 --- a/keydb/keydb_file.c +++ b/keydb/keydb_file.c @@ -29,6 +29,7 @@ #include #include "charfuncs.h" +#include "key-store.h" #include "keydb.h" #include "keyid.h" #include "keystructs.h" @@ -78,21 +79,19 @@ static int file_fetch_key_id(struct onak_dbctx *dbctx, char *db_dir = (char *) dbctx->priv; struct openpgp_packet_list *packets = NULL; char keyfile[1024]; - int fd = -1; + onak_status_t res; snprintf(keyfile, 1023, "%s/0x%" PRIX64, db_dir, keyid & 0xFFFFFFFF); - fd = open(keyfile, O_RDONLY); // | O_SHLOCK); + res = onak_read_openpgp_file(keyfile, &packets); - if (fd > -1) { - read_openpgp_stream(file_fetchchar, &fd, &packets, 0); + if (res == ONAK_E_OK) { parse_keys(packets, publickey); free_packet_list(packets); packets = NULL; - close(fd); } - return (fd > -1); + return (res == ONAK_E_OK); } /** @@ -199,8 +198,8 @@ static int file_iterate_keys(struct onak_dbctx *dbctx, struct openpgp_publickey *key = NULL; DIR *dir; char keyfile[1024]; - int fd = -1; struct dirent *curfile = NULL; + onak_status_t res; dir = opendir(db_dir); @@ -211,13 +210,10 @@ static int file_iterate_keys(struct onak_dbctx *dbctx, snprintf(keyfile, 1023, "%s/%s", db_dir, curfile->d_name); - fd = open(keyfile, O_RDONLY); + res = onak_read_openpgp_file(keyfile, + &packets); - if (fd > -1) { - read_openpgp_stream(file_fetchchar, - &fd, - &packets, - 0); + if (res == ONAK_E_OK) { parse_keys(packets, &key); iterfunc(ctx, key); @@ -226,7 +222,6 @@ static int file_iterate_keys(struct onak_dbctx *dbctx, key = NULL; free_packet_list(packets); packets = NULL; - close(fd); } numkeys++; } diff --git a/keydb/keydb_fs.c b/keydb/keydb_fs.c index f7c865e..565cfe8 100644 --- a/keydb/keydb_fs.c +++ b/keydb/keydb_fs.c @@ -32,6 +32,7 @@ #include "charfuncs.h" #include "decodekey.h" +#include "key-store.h" #include "keydb.h" #include "keyid.h" #include "keystructs.h" @@ -258,8 +259,9 @@ static int fs_fetch_key_id(struct onak_dbctx *dbctx, bool intrans) { static char buffer[PATH_MAX]; - int ret = 0, fd; + int ret = 0; struct openpgp_packet_list *packets = NULL; + onak_status_t res; if (!intrans) fs_starttrans(dbctx); @@ -268,20 +270,20 @@ static int fs_fetch_key_id(struct onak_dbctx *dbctx, keyid = fs_getfullkeyid(dbctx, keyid); keypath(buffer, sizeof(buffer), keyid, dbctx->config->location); - fd = open(buffer, O_RDONLY); - if (fd == -1 && errno == ENOENT) { + res = onak_read_openpgp_file(buffer, + &packets); + if (res == ONAK_E_NOT_FOUND) { subkeypath(buffer, sizeof(buffer), keyid, dbctx->config->location); - fd = open(buffer, O_RDONLY); + res = onak_read_openpgp_file(buffer, + &packets); } - if (fd != -1) { + if (res == ONAK_E_OK) { /* File is present, load it in... */ - read_openpgp_stream(file_fetchchar, &fd, &packets, 0); parse_keys(packets, publickey); free_packet_list(packets); packets = NULL; - close(fd); ret = 1; } @@ -593,16 +595,16 @@ static int fs_fetch_key_skshash(struct onak_dbctx *dbctx, struct openpgp_publickey **publickey) { static char buffer[PATH_MAX]; - int ret = 0, fd; + int ret = 0; struct openpgp_packet_list *packets = NULL; + onak_status_t res; skshashpath(buffer, sizeof(buffer), hash, dbctx->config->location); - if ((fd = open(buffer, O_RDONLY)) != -1) { - read_openpgp_stream(file_fetchchar, &fd, &packets, 0); + res = onak_read_openpgp_file(buffer, &packets); + if (res == ONAK_E_OK) { parse_keys(packets, publickey); free_packet_list(packets); packets = NULL; - close(fd); ret = 1; } diff --git a/onak.h b/onak.h index 7856dbf..8ad6c75 100644 --- a/onak.h +++ b/onak.h @@ -29,6 +29,7 @@ typedef enum { ONAK_E_UNSUPPORTED_FEATURE, ONAK_E_BAD_SIGNATURE, ONAK_E_WEAK_SIGNATURE, + ONAK_E_IO_ERROR, } onak_status_t; #endif /* __ONAK_H__ */ -- 2.39.5