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 --*/