From 82cbab906a3e72a98fdc16096f2f0451465969a2 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 20 Oct 2016 12:05:15 +0900 Subject: [PATCH] agent: Add --card option for READKEY. * agent/findkey.c (agent_write_shadow_key): New. * agent/command-ssh.c (card_key_available): Use agent_write_shadow_key. * agent/learncard.c (agent_handle_learn): Likewise. * agent/command.c (cmd_readkey): Add --card option. -- Signed-off-by: NIIBE Yutaka --- agent/agent.h | 3 ++ agent/command-ssh.c | 32 +-------------------- agent/command.c | 69 +++++++++++++++++++++++++++++++++++++-------- agent/findkey.c | 36 +++++++++++++++++++++++ agent/learncard.c | 30 ++------------------ 5 files changed, 100 insertions(+), 70 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index fe5ffba12..a3ec45724 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -490,6 +490,9 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo, const unsigned char *s2ksalt, unsigned int s2kcount, unsigned char *key, size_t keylen); +gpg_error_t agent_write_shadow_key (const unsigned char *grip, + const char *serialno, const char *keyid, + const unsigned char *pkbuf, int force); /*-- trustlist.c --*/ diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 083b8d890..7bcda504c 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2474,39 +2474,9 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) if ( agent_key_available (grip) ) { /* (Shadow)-key is not available in our key storage. */ - unsigned char *shadow_info; - unsigned char *tmp; - - shadow_info = make_shadow_info (serialno, authkeyid); - if (!shadow_info) - { - err = gpg_error_from_syserror (); - xfree (pkbuf); - gcry_sexp_release (s_pk); - xfree (serialno); - xfree (authkeyid); - return err; - } - err = agent_shadow_key (pkbuf, shadow_info, &tmp); - xfree (shadow_info); + err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0); if (err) { - log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err)); - xfree (pkbuf); - gcry_sexp_release (s_pk); - xfree (serialno); - xfree (authkeyid); - return err; - } - xfree (pkbuf); - pkbuf = tmp; - pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); - assert (pkbuflen); - - err = agent_write_private_key (grip, pkbuf, pkbuflen, 0); - if (err) - { - log_error (_("error writing key: %s\n"), gpg_strerror (err)); xfree (pkbuf); gcry_sexp_release (s_pk); xfree (serialno); diff --git a/agent/command.c b/agent/command.c index 1ecdf20cd..a291d5b68 100644 --- a/agent/command.c +++ b/agent/command.c @@ -988,8 +988,10 @@ cmd_genkey (assuan_context_t ctx, char *line) static const char hlp_readkey[] = "READKEY \n" + " --card \n" "\n" - "Return the public key for the given keygrip."; + "Return the public key for the given keygrip or keyid.\n" + "With --card, private key file with card information will be created."; static gpg_error_t cmd_readkey (assuan_context_t ctx, char *line) { @@ -997,10 +999,57 @@ cmd_readkey (assuan_context_t ctx, char *line) int rc; unsigned char grip[20]; gcry_sexp_t s_pkey = NULL; + unsigned char *pkbuf = NULL; + size_t pkbuflen; if (ctrl->restricted) return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); + if (has_option_name (line, "--card")) + { + const char *keyid; + char *serialno = NULL; + + keyid = skip_options (line); + + rc = agent_card_getattr (ctrl, "SERIALNO", &serialno); + if (rc) + { + log_error (_("error getting serial number of card: %s\n"), + gpg_strerror (rc)); + goto leave; + } + + pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); + rc = agent_card_readkey (ctrl, keyid, &pkbuf); + if (rc) + goto leave; + rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)pkbuf, pkbuflen); + if (rc) + goto leave; + + if (!gcry_pk_get_keygrip (s_pkey, grip)) + { + rc = gcry_pk_testkey (s_pkey); + if (rc == 0) + rc = gpg_error (GPG_ERR_INTERNAL); + + goto leave; + } + + rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0); + if (rc) + goto leave; + + rc = assuan_send_data (ctx, pkbuf, pkbuflen); + + leave: + xfree (serialno); + xfree (pkbuf); + gcry_sexp_release (s_pkey); + return leave_cmd (ctx, rc); + } + rc = parse_keygrip (ctx, line, grip); if (rc) return rc; /* Return immediately as this is already an Assuan error code.*/ @@ -1008,20 +1057,16 @@ cmd_readkey (assuan_context_t ctx, char *line) rc = agent_public_key_from_file (ctrl, grip, &s_pkey); if (!rc) { - size_t len; - unsigned char *buf; - - len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); - assert (len); - buf = xtrymalloc (len); - if (!buf) + pkbuflen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + assert (pkbuflen); + pkbuf = xtrymalloc (pkbuflen); + if (!pkbuf) rc = gpg_error_from_syserror (); else { - len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, buf, len); - assert (len); - rc = assuan_send_data (ctx, buf, len); - xfree (buf); + gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, pkbuf, pkbuflen); + rc = assuan_send_data (ctx, pkbuf, pkbuflen); + xfree (pkbuf); } gcry_sexp_release (s_pkey); } diff --git a/agent/findkey.c b/agent/findkey.c index c5ab0e905..23e94f0dd 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -1492,3 +1492,39 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text, gcry_sexp_release (s_skey); return err; } + + +/* Write an S-expression formatted shadow key to our key storage. + Shadow key is created by an S-expression public key in PKBUF and + card's SERIALNO and the IDSTRING. With FORCE passed as true an + existing key with the given GRIP will get overwritten. */ +gpg_error_t +agent_write_shadow_key (const unsigned char *grip, + const char *serialno, const char *keyid, + const unsigned char *pkbuf, int force) +{ + gpg_error_t err; + unsigned char *shadow_info; + unsigned char *shdkey; + size_t len; + + shadow_info = make_shadow_info (serialno, keyid); + if (!shadow_info) + return gpg_error_from_syserror (); + + err = agent_shadow_key (pkbuf, shadow_info, &shdkey); + xfree (shadow_info); + if (err) + { + log_error ("shadowing the key failed: %s\n", gpg_strerror (err)); + return err; + } + + len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL); + err = agent_write_private_key (grip, shdkey, len, force); + xfree (shdkey); + if (err) + log_error ("error writing key: %s\n", gpg_strerror (err)); + + return err; +} diff --git a/agent/learncard.c b/agent/learncard.c index e9304fb8b..103a82163 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -381,8 +381,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) for (item = parm.info; item; item = item->next) { - unsigned char *pubkey, *shdkey; - size_t n; + unsigned char *pubkey; if (opt.verbose) log_info (" id: %s (grip=%s)\n", item->id, item->hexgrip); @@ -410,33 +409,10 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) goto leave; } - { - unsigned char *shadow_info = make_shadow_info (serialno, item->id); - if (!shadow_info) - { - rc = gpg_error (GPG_ERR_ENOMEM); - xfree (pubkey); - goto leave; - } - rc = agent_shadow_key (pubkey, shadow_info, &shdkey); - xfree (shadow_info); - } + rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force); xfree (pubkey); if (rc) - { - log_error ("shadowing the key failed: %s\n", gpg_strerror (rc)); - goto leave; - } - n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL); - assert (n); - - rc = agent_write_private_key (grip, shdkey, n, force); - xfree (shdkey); - if (rc) - { - log_error ("error writing key: %s\n", gpg_strerror (rc)); - goto leave; - } + goto leave; if (opt.verbose) log_info (" id: %s - shadow key created\n", item->id);