From f9da935c3eb302e75a80def51128fb6f669661d7 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 4 Nov 2016 13:45:57 +0900 Subject: [PATCH] scd: Add --advanced option for READKEY. * scd/command.c (cmd_readkey) : Support ADVANCED arg. * scd/app.c (app_readcert): Add ADVANCED arg. * scd/app-openpgp.c (do_readkey): Implement ADVANCED arg. * scd/app-nks.c (do_readkey): Error return with GPG_ERR_NOT_SUPPORTED. -- "SCD READKEY --advanced OPENPGP.3" returns key in advanced format. With this suport, poldi-ctrl will be no longer needed. Signed-off-by: NIIBE Yutaka --- scd/app-common.h | 4 +- scd/app-nks.c | 8 ++- scd/app-openpgp.c | 130 +++++++++++++++++++++++++++------------------- scd/app.c | 5 +- scd/command.c | 13 +++-- 5 files changed, 99 insertions(+), 61 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index b4bb55bf2..cda657f14 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -72,7 +72,7 @@ struct app_ctx_s { gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags); gpg_error_t (*readcert) (app_t app, const char *certid, unsigned char **cert, size_t *certlen); - gpg_error_t (*readkey) (app_t app, const char *certid, + gpg_error_t (*readkey) (app_t app, int advanced, const char *certid, unsigned char **pk, size_t *pklen); gpg_error_t (*getattr) (app_t app, ctrl_t ctrl, const char *name); gpg_error_t (*setattr) (app_t app, const char *name, @@ -154,7 +154,7 @@ gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags); gpg_error_t app_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen); -gpg_error_t app_readkey (app_t app, const char *keyid, +gpg_error_t app_readkey (app_t app, int advanced, const char *keyid, unsigned char **pk, size_t *pklen); gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name); gpg_error_t app_setattr (app_t app, const char *name, diff --git a/scd/app-nks.c b/scd/app-nks.c index 458516bfb..598dee187 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -618,13 +618,17 @@ do_readcert (app_t app, const char *certid, certificate parsing code in commands.c:cmd_readkey. For internal use PK and PKLEN may be NULL to just check for an existing key. */ static gpg_error_t -do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) +do_readkey (app_t app, int advanced, const char *keyid, + unsigned char **pk, size_t *pklen) { gpg_error_t err; unsigned char *buffer[2]; size_t buflen[2]; unsigned short path[1] = { 0x4500 }; + if (advanced) + return GPG_ERR_NOT_SUPPORTED; + /* We use a generic name to retrieve PK.AUT.IFD-SPK. */ if (!strcmp (keyid, "$IFDAUTHKEY") && app->app_local->nks_version >= 3) ; @@ -698,7 +702,7 @@ do_writekey (app_t app, ctrl_t ctrl, else return gpg_error (GPG_ERR_INV_ID); - if (!force && !do_readkey (app, keyid, NULL, NULL)) + if (!force && !do_readkey (app, 0, keyid, NULL, NULL)) return gpg_error (GPG_ERR_EEXIST); /* Parse the S-expression. */ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index d75721fc3..4bf99add9 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1115,8 +1115,8 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr) #if GNUPG_MAJOR_VERSION > 1 static gpg_error_t retrieve_key_material (FILE *fp, const char *hexkeyid, - const unsigned char **m, size_t *mlen, - const unsigned char **e, size_t *elen) + const unsigned char **m, size_t *mlen, + const unsigned char **e, size_t *elen) { gcry_error_t err = 0; char *line = NULL; /* read_line() buffer. */ @@ -1146,10 +1146,10 @@ retrieve_key_material (FILE *fp, const char *hexkeyid, if (!i) break; /* EOF. */ if (i < 0) - { - err = gpg_error_from_syserror (); - goto leave; /* Error. */ - } + { + err = gpg_error_from_syserror (); + goto leave; /* Error. */ + } if (!max_length) { err = gpg_error (GPG_ERR_TRUNCATED); @@ -1173,7 +1173,7 @@ retrieve_key_material (FILE *fp, const char *hexkeyid, && nfields > 4 && !strcmp (fields[4], hexkeyid)) found_key = 1; continue; - } + } if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") ) break; /* Next key - stop. */ @@ -1561,8 +1561,8 @@ get_public_key (app_t app, int keyno) Clearly that is not an option and thus we try to locate the key using an external helper. - The helper we use here is gpg itself, which should know about - the key in any case. */ + The helper we use here is gpg itself, which should know about + the key in any case. */ char fpr[41]; char *hexkeyid; @@ -1574,38 +1574,38 @@ get_public_key (app_t app, int keyno) err = retrieve_fpr_from_card (app, keyno, fpr); if (err) - { - log_error ("error while retrieving fpr from card: %s\n", - gpg_strerror (err)); - goto leave; - } + { + log_error ("error while retrieving fpr from card: %s\n", + gpg_strerror (err)); + goto leave; + } hexkeyid = fpr + 24; ret = gpgrt_asprintf (&command, "gpg --list-keys --with-colons --with-key-data '%s'", fpr); if (ret < 0) - { - err = gpg_error_from_syserror (); - goto leave; - } + { + err = gpg_error_from_syserror (); + goto leave; + } fp = popen (command, "r"); xfree (command); if (!fp) - { - err = gpg_error_from_syserror (); - log_error ("running gpg failed: %s\n", gpg_strerror (err)); - goto leave; - } + { + err = gpg_error_from_syserror (); + log_error ("running gpg failed: %s\n", gpg_strerror (err)); + goto leave; + } err = retrieve_key_material (fp, hexkeyid, &m, &mlen, &e, &elen); pclose (fp); if (err) - { - log_error ("error while retrieving key material through pipe: %s\n", + { + log_error ("error while retrieving key material through pipe: %s\n", gpg_strerror (err)); - goto leave; - } + goto leave; + } err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))", (int)mlen, m, (int)elen, e); @@ -1726,7 +1726,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) buffer. On error PK and PKLEN are not changed and an error code is returned. */ static gpg_error_t -do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) +do_readkey (app_t app, int advanced, const char *keyid, + unsigned char **pk, size_t *pklen) { #if GNUPG_MAJOR_VERSION > 1 gpg_error_t err; @@ -1749,15 +1750,40 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) buf = app->app_local->pk[keyno].key; if (!buf) return gpg_error (GPG_ERR_NO_PUBKEY); - *pklen = app->app_local->pk[keyno].keylen;; - *pk = xtrymalloc (*pklen); - if (!*pk) + + if (advanced) { - err = gpg_error_from_syserror (); - *pklen = 0; - return err; + gcry_sexp_t s_key; + + err = gcry_sexp_new (&s_key, buf, app->app_local->pk[keyno].keylen, 0); + if (err) + return err; + + *pklen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_ADVANCED, NULL, 0); + *pk = xtrymalloc (*pklen); + if (!*pk) + { + err = gpg_error_from_syserror (); + *pklen = 0; + return err; + } + + gcry_sexp_sprint (s_key, GCRYSEXP_FMT_ADVANCED, *pk, *pklen); + gcry_sexp_release (s_key); } - memcpy (*pk, buf, *pklen); + else + { + *pklen = app->app_local->pk[keyno].keylen; + *pk = xtrymalloc (*pklen); + if (!*pk) + { + err = gpg_error_from_syserror (); + *pklen = 0; + return err; + } + memcpy (*pk, buf, *pklen); + } + return 0; #else return gpg_error (GPG_ERR_NOT_IMPLEMENTED); @@ -2366,7 +2392,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, } else if (chvno == 1 || chvno == 3) { - if (!use_pinpad) + if (!use_pinpad) { char *promptbuf = NULL; const char *prompt; @@ -3990,23 +4016,23 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, else { for (s=keyidstr, n=0; hexdigitp (s); s++, n++) - ; + ; if (n != 32) - return gpg_error (GPG_ERR_INV_ID); + return gpg_error (GPG_ERR_INV_ID); else if (!*s) - ; /* no fingerprint given: we allow this for now. */ + ; /* no fingerprint given: we allow this for now. */ else if (*s == '/') - fpr = s + 1; + fpr = s + 1; else - return gpg_error (GPG_ERR_INV_ID); + return gpg_error (GPG_ERR_INV_ID); for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); + tmp_sn[n] = xtoi_2 (s); if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); + return gpg_error (GPG_ERR_INV_CARD); if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); + return gpg_error (GPG_ERR_WRONG_CARD); } /* If a fingerprint has been specified check it against the one on @@ -4244,23 +4270,23 @@ do_decipher (app_t app, const char *keyidstr, else { for (s=keyidstr, n=0; hexdigitp (s); s++, n++) - ; + ; if (n != 32) - return gpg_error (GPG_ERR_INV_ID); + return gpg_error (GPG_ERR_INV_ID); else if (!*s) - ; /* no fingerprint given: we allow this for now. */ + ; /* no fingerprint given: we allow this for now. */ else if (*s == '/') - fpr = s + 1; + fpr = s + 1; else - return gpg_error (GPG_ERR_INV_ID); + return gpg_error (GPG_ERR_INV_ID); for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); + tmp_sn[n] = xtoi_2 (s); if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); + return gpg_error (GPG_ERR_INV_CARD); if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); + return gpg_error (GPG_ERR_WRONG_CARD); } /* If a fingerprint has been specified check it against the one on diff --git a/scd/app.c b/scd/app.c index 55b8edd12..1f21dc149 100644 --- a/scd/app.c +++ b/scd/app.c @@ -612,7 +612,8 @@ app_readcert (app_t app, const char *certid, This function might not be supported by all applications. */ gpg_error_t -app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) +app_readkey (app_t app, int advanced, const char *keyid, + unsigned char **pk, size_t *pklen) { gpg_error_t err; @@ -630,7 +631,7 @@ app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) err = lock_reader (app->slot, NULL /*FIXME*/); if (err) return err; - err= app->fnc.readkey (app, keyid, pk, pklen); + err= app->fnc.readkey (app, advanced, keyid, pk, pklen); unlock_reader (app->slot); return err; } diff --git a/scd/command.c b/scd/command.c index 9d978ab48..edea01c1e 100644 --- a/scd/command.c +++ b/scd/command.c @@ -729,17 +729,19 @@ cmd_readcert (assuan_context_t ctx, char *line) static const char hlp_readkey[] = - "READKEY \n" + "READKEY [--advanced] \n" "\n" "Return the public key for the given cert or key ID as a standard\n" "S-expression.\n" + "In --advanced mode it returns the S-expression in advanced format.\n" "\n" - "Note, that this function may even be used on a locked card."; + "Note that this function may even be used on a locked card."; static gpg_error_t cmd_readkey (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); int rc; + int advanced = 0; unsigned char *cert = NULL; size_t ncert, n; ksba_cert_t kc = NULL; @@ -750,11 +752,16 @@ cmd_readkey (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl, NULL))) return rc; + if (has_option (line, "--advanced")) + advanced = 1; + + line = skip_options (line); + line = xstrdup (line); /* Need a copy of the line. */ /* If the application supports the READKEY function we use that. Otherwise we use the old way by extracting it from the certificate. */ - rc = app_readkey (ctrl->app_ctx, line, &pk, &pklen); + rc = app_readkey (ctrl->app_ctx, advanced, line, &pk, &pklen); if (!rc) { /* Yeah, got that key - send it back. */ rc = assuan_send_data (ctx, pk, pklen);