aboutsummaryrefslogtreecommitdiffstats
path: root/src/m_paper_key/restore.cpp
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2024-07-28 08:18:33 +0000
committersaturneric <[email protected]>2024-07-28 08:18:33 +0000
commitc27c541257585878e4db705559c5cb953dc860b7 (patch)
tree7dc69115de96151a40acfc8891bf9a065eee0a9b /src/m_paper_key/restore.cpp
parentfix: solve a memory leak issue (diff)
downloadmodules-c27c541257585878e4db705559c5cb953dc860b7.tar.gz
modules-c27c541257585878e4db705559c5cb953dc860b7.zip
feat: add pinentry module and paper key module
Diffstat (limited to 'src/m_paper_key/restore.cpp')
-rw-r--r--src/m_paper_key/restore.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/m_paper_key/restore.cpp b/src/m_paper_key/restore.cpp
new file mode 100644
index 0000000..e1c8146
--- /dev/null
+++ b/src/m_paper_key/restore.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007, 2012 David Shaw <[email protected]>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "restore.h"
+
+#include <cctype>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "GFSDKBasic.h"
+#include "output.h"
+#include "packets.h"
+#include "parse.h"
+
+struct key {
+ unsigned char fpr[20];
+ struct packet *packet;
+ struct key *next;
+};
+
+static auto extract_keys(struct packet *packet) -> struct key * {
+ struct key *key = NULL;
+ size_t idx = 1;
+
+ /* Check the version */
+ if (packet->len && packet->buf[0] != 0) {
+ fprintf(stderr, "Cannot handle secrets file version %d\n", packet->buf[0]);
+ return NULL;
+ }
+
+ while (idx < packet->len) {
+ /* 1+20+2 == version + fingerprint + length */
+ if (idx + 1 + 20 + 2 <= packet->len) {
+ if (packet->buf[idx] == 4) {
+ unsigned int len;
+ struct key *newkey;
+
+ newkey =
+ static_cast<struct key *>(GFAllocateMemory(sizeof(struct key)));
+ newkey->next = NULL;
+
+ idx++;
+ memcpy(newkey->fpr, &packet->buf[idx], 20);
+
+ idx += 20;
+
+ len = packet->buf[idx++] << 8;
+ len |= packet->buf[idx++];
+
+ if (idx + len <= packet->len) {
+ newkey->packet = append_packet(NULL, &packet->buf[idx], len);
+ idx += len;
+ } else {
+ fprintf(stderr, "Warning: Short data in secret image\n");
+ free(newkey);
+ break;
+ }
+
+ newkey->next = key;
+ key = newkey;
+ } else {
+ fprintf(stderr, "Warning: Corrupt data in secret image\n");
+ break;
+ }
+ } else {
+ fprintf(stderr, "Warning: Short header in secret image\n");
+ break;
+ }
+ }
+
+ return key;
+}
+
+static void free_keys(struct key *key) {
+ while (key) {
+ struct key *keytmp = key;
+ free_packet(key->packet);
+ key = key->next;
+ free(keytmp);
+ }
+}
+
+auto restore(FILE *pubring, FILE *secrets, enum data_type input_type,
+ const char *outname) -> int {
+ struct packet *secret;
+
+ if (input_type == AUTO) {
+ int test = fgetc(secrets);
+
+ if (test == EOF) {
+ fprintf(stderr, "Unable to check type of secrets file\n");
+ return 1;
+ } else if (isascii(test) && isprint(test))
+ input_type = BASE16;
+ else
+ input_type = RAW;
+
+ ungetc(test, secrets);
+ }
+
+ secret = read_secrets_file(secrets, input_type);
+ if (secret) {
+ struct packet *pubkey;
+ struct key *keys;
+ int did_pubkey = 0;
+
+ /* Build a list of all keys. We need to do this since the
+ public key we are transforming might have the subkeys in a
+ different order than (or not match subkeys at all with) our
+ secret data. */
+
+ keys = extract_keys(secret);
+ if (keys) {
+ output_start(outname, RAW, NULL);
+
+ while ((pubkey = parse(pubring, 0, 0))) {
+ unsigned char ptag;
+
+ if (pubkey->type == 6 || pubkey->type == 14) {
+ /* Public key or subkey */
+ unsigned char fpr[20];
+ struct key *keyidx;
+
+ if (pubkey->type == 6 && did_pubkey) break;
+
+ calculate_fingerprint(pubkey, pubkey->len, fpr);
+
+ /* Do we have a secret key that matches? */
+ for (keyidx = keys; keyidx; keyidx = keyidx->next) {
+ if (memcmp(fpr, keyidx->fpr, 20) == 0) {
+ if (pubkey->type == 6) {
+ ptag = 5;
+ did_pubkey = 1;
+ } else
+ ptag = 7;
+
+ /* Match, so create a secret key. */
+ output_openpgp_header(ptag, pubkey->len + keyidx->packet->len);
+ output_packet(pubkey);
+ output_packet(keyidx->packet);
+ }
+ }
+ } else if (did_pubkey) {
+ /* Copy the usual user ID, sigs, etc, so the key is
+ well-formed. */
+ output_openpgp_header(pubkey->type, pubkey->len);
+ output_packet(pubkey);
+ }
+
+ free_packet(pubkey);
+ }
+
+ free_keys(keys);
+ } else {
+ fprintf(stderr, "Unable to parse secret data\n");
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Unable to read secrets file\n");
+ return 1;
+ }
+
+ return 0;
+}