aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-06-03 14:24:44 +0000
committerWerner Koch <[email protected]>2020-06-03 14:25:59 +0000
commit4f6e0e12cbd3444b9e6ea5e4b92ea5b3072a3e17 (patch)
tree276274d0eea567faf6ffd44da8d6040577478a57
parentgpg: Improve generation of keys stored on card (brainpool,cv25519). (diff)
downloadgnupg-4f6e0e12cbd3444b9e6ea5e4b92ea5b3072a3e17.tar.gz
gnupg-4f6e0e12cbd3444b9e6ea5e4b92ea5b3072a3e17.zip
card: Improve openpgp key writing in "writecert".
* tools/card-keys.c (struct export_key_status_parm_s): New. (export_key_status_cb): New. (get_minimal_openpgp_key): New. * tools/gpg-card.c (cmd_writecert): Allow writing a keyblock directly from an existing gpg key. Signed-off-by: Werner Koch <[email protected]>
-rw-r--r--tools/card-keys.c93
-rw-r--r--tools/gpg-card.c24
-rw-r--r--tools/gpg-card.h1
3 files changed, 114 insertions, 4 deletions
diff --git a/tools/card-keys.c b/tools/card-keys.c
index 4706cb320..3027de9c7 100644
--- a/tools/card-keys.c
+++ b/tools/card-keys.c
@@ -557,3 +557,96 @@ test_get_matching_keys (const char *hexgrip)
release_keyblock (keyblock);
return 0;
}
+
+
+
+
+struct export_key_status_parm_s
+{
+ const char *fpr;
+ int found;
+ int count;
+};
+
+
+static void
+export_key_status_cb (void *opaque, const char *keyword, char *args)
+{
+ struct export_key_status_parm_s *parm = opaque;
+
+ if (!strcmp (keyword, "EXPORTED"))
+ {
+ parm->count++;
+ if (!ascii_strcasecmp (args, parm->fpr))
+ parm->found = 1;
+ }
+}
+
+
+/* Get a key by fingerprint from gpg's keyring. The binary key is
+ * returned as a new memory stream at R_KEY. */
+gpg_error_t
+get_minimal_openpgp_key (estream_t *r_key, const char *fingerprint)
+{
+ gpg_error_t err;
+ ccparray_t ccp;
+ const char **argv = NULL;
+ estream_t key = NULL;
+ struct export_key_status_parm_s parm = { NULL };
+
+ *r_key = NULL;
+
+ key = es_fopenmem (0, "w+b");
+ if (!key)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ ccparray_init (&ccp, 0);
+
+ ccparray_put (&ccp, "--no-options");
+ if (!opt.verbose)
+ ccparray_put (&ccp, "--quiet");
+ else if (opt.verbose > 1)
+ ccparray_put (&ccp, "--verbose");
+ ccparray_put (&ccp, "--batch");
+ ccparray_put (&ccp, "--status-fd=2");
+ ccparray_put (&ccp, "--always-trust");
+ ccparray_put (&ccp, "--no-armor");
+ ccparray_put (&ccp, "--export-options=export-minimal");
+ ccparray_put (&ccp, "--export");
+ ccparray_put (&ccp, "--");
+ ccparray_put (&ccp, fingerprint);
+
+ ccparray_put (&ccp, NULL);
+ argv = ccparray_get (&ccp, NULL);
+ if (!argv)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ parm.fpr = fingerprint;
+ err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
+ NULL, key,
+ export_key_status_cb, &parm);
+ if (!err && parm.count > 1)
+ err = gpg_error (GPG_ERR_TOO_MANY);
+ else if (!err && !parm.found)
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+ if (err)
+ {
+ log_error ("export failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ es_rewind (key);
+ *r_key = key;
+ key = NULL;
+
+ leave:
+ es_fclose (key);
+ xfree (argv);
+ return err;
+}
diff --git a/tools/gpg-card.c b/tools/gpg-card.c
index f89565ca6..9049b2926 100644
--- a/tools/gpg-card.c
+++ b/tools/gpg-card.c
@@ -1853,15 +1853,18 @@ cmd_writecert (card_info_t info, char *argstr)
char *certref;
char *data = NULL;
size_t datalen;
+ estream_t key = NULL;
if (!info)
return print_help
- ("WRITECERT [--clear] [--openpgp] CERTREF < FILE\n\n"
- "Write a certificate for key 3. Unless --clear is given\n"
- "the file argument is mandatory. The option --clear removes\n"
+ ("WRITECERT CERTREF '<' FILE\n"
+ "WRITECERT --openpgp CERTREF ['<' FILE|FPR]\n"
+ "WRITECERT --clear CERTREF\n\n"
+ "Write a certificate for key 3. The option --clear removes\n"
"the certificate from the card. The option --openpgp expects\n"
- "a keyblock and stores it encapsulated in a CMS container.",
+ "a keyblock and stores it encapsulated in a CMS container; the\n"
+ "keyblock is taken from FILE or directly from the key with FPR",
APP_TYPE_OPENPGP, APP_TYPE_PIV, 0);
opt_clear = has_leading_option (argstr, "--clear");
@@ -1926,6 +1929,18 @@ cmd_writecert (card_info_t info, char *argstr)
goto leave;
}
}
+ else if (opt_openpgp && *argstr)
+ {
+ err = get_minimal_openpgp_key (&key, argstr);
+ if (err)
+ goto leave;
+ if (es_fclose_snatch (key, (void*)&data, &datalen))
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ key = NULL;
+ }
else
{
err = gpg_error (GPG_ERR_INV_ARG);
@@ -1965,6 +1980,7 @@ cmd_writecert (card_info_t info, char *argstr)
err = scd_writecert (certref, data, datalen);
leave:
+ es_fclose (key);
xfree (data);
xfree (certref_buffer);
return err;
diff --git a/tools/gpg-card.h b/tools/gpg-card.h
index 157907a3f..82064999c 100644
--- a/tools/gpg-card.h
+++ b/tools/gpg-card.h
@@ -195,6 +195,7 @@ void flush_keyblock_cache (void);
gpg_error_t get_matching_keys (const unsigned char *keygrip, int protocol,
keyblock_t *r_keyblock);
gpg_error_t test_get_matching_keys (const char *hexgrip);
+gpg_error_t get_minimal_openpgp_key (estream_t *r_key, const char *fingerprint);
/*-- card-misc.c --*/