diff --git a/scd/app-common.h b/scd/app-common.h index 0265604c5..f95db7433 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -208,7 +208,7 @@ unsigned int app_help_count_bits (const unsigned char *a, size_t len); gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, gcry_sexp_t *r_pkey, - int *r_algo); + int *r_algo, char **r_algostr); gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, gcry_sexp_t *r_pkey, int *r_algo); gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen, diff --git a/scd/app-help.c b/scd/app-help.c index f95928675..8d225ef58 100644 --- a/scd/app-help.c +++ b/scd/app-help.c @@ -57,10 +57,13 @@ app_help_count_bits (const unsigned char *a, size_t len) * function succeeded, the S-expression representing the key is stored * there. The caller needs to call gcry_sexp_release on that. If * R_ALGO is not NULL the public key algorithm id of Libgcrypt is - * stored there. */ + * stored there. If R_ALGOSTR is not NULL and the function succeeds a + * newly allocated algo string (e.g. "rsa2048") is stored there. + * HEXKEYGRIP may be NULL if the caller is not interested in it. */ gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, - gcry_sexp_t *r_pkey, int *r_algo) + gcry_sexp_t *r_pkey, int *r_algo, + char **r_algostr) { gpg_error_t err; gcry_sexp_t s_pkey; @@ -68,11 +71,13 @@ app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, if (r_pkey) *r_pkey = NULL; + if (r_algostr) + *r_algostr = NULL; err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen); if (err) return err; /* Can't parse that S-expression. */ - if (!gcry_pk_get_keygrip (s_pkey, array)) + if (hexkeygrip && !gcry_pk_get_keygrip (s_pkey, array)) { gcry_sexp_release (s_pkey); return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/ @@ -81,12 +86,24 @@ app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, if (r_algo) *r_algo = get_pk_algo_from_key (s_pkey); + if (r_algostr) + { + *r_algostr = pubkey_algo_string (s_pkey, NULL); + if (!*r_algostr) + { + err = gpg_error_from_syserror (); + gcry_sexp_release (s_pkey); + return err; + } + } + if (r_pkey) *r_pkey = s_pkey; else gcry_sexp_release (s_pkey); - bin2hex (array, KEYGRIP_LEN, hexkeygrip); + if (hexkeygrip) + bin2hex (array, KEYGRIP_LEN, hexkeygrip); return 0; } @@ -116,7 +133,7 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, if (!n) return gpg_error (GPG_ERR_INV_SEXP); err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip, - r_pkey, r_algo); + r_pkey, r_algo, NULL); ksba_free (p); return err; } diff --git a/scd/command.c b/scd/command.c index dd965a31b..2e2627f71 100644 --- a/scd/command.c +++ b/scd/command.c @@ -499,29 +499,35 @@ cmd_readcert (assuan_context_t ctx, char *line) static const char hlp_readkey[] = - "READKEY [--advanced] \n" + "READKEY [--advanced] [--info[-only]] \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."; + "S-expression. With --advanced the S-expression is returned in\n" + "advanced format. With --info a KEYPAIRINFO status line is also\n" + "emitted; with --info-only the regular output is suppressed."; static gpg_error_t cmd_readkey (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); int rc; int advanced = 0; + int opt_info = 0; + int opt_nokey = 0; unsigned char *cert = NULL; size_t ncert; unsigned char *pk; size_t pklen; + int direct_readkey = 0; if ((rc = open_card (ctrl))) return rc; if (has_option (line, "--advanced")) advanced = 1; + if (has_option (line, "--info")) + opt_info = 1; + if (has_option (line, "--info-only")) + opt_info = opt_nokey = 1; line = skip_options (line); line = xstrdup (line); /* Need a copy of the line. */ @@ -531,7 +537,7 @@ cmd_readkey (assuan_context_t ctx, char *line) certificate. */ rc = app_readkey (ctrl->app_ctx, ctrl, advanced, line, &pk, &pklen); if (!rc) - ; /* Yeah, got that key - send it back. */ + direct_readkey = 1; /* Yeah, got that key - send it back. */ else if (gpg_err_code (rc) == GPG_ERR_UNSUPPORTED_OPERATION || gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { @@ -550,9 +556,38 @@ cmd_readkey (assuan_context_t ctx, char *line) else log_error ("app_readkey failed: %s\n", gpg_strerror (rc)); - if (!rc && pk && pklen) + if (!rc && pk && pklen && opt_info && !direct_readkey) + { + char keygripstr[KEYGRIP_LEN*2+1]; + char *algostr; + + rc = app_help_get_keygrip_string_pk (pk, pklen, + keygripstr, NULL, NULL, + &algostr); + if (rc) + { + log_error ("app_help_get_keygrip_string failed: %s\n", + gpg_strerror (rc)); + goto leave; + } + + /* FIXME: Using LINE is not correct because it might be an + * OID and has not been canonicalized (i.e. uppercased). */ + send_status_info (ctrl, "KEYPAIRINFO", + keygripstr, strlen (keygripstr), + line, strlen (line), + "-", (size_t)1, + "-", (size_t)1, + algostr, strlen (algostr), + NULL, (size_t)0); + xfree (algostr); + } + + + if (!rc && pk && pklen && !opt_nokey) rc = assuan_send_data (ctx, pk, pklen); + leave: xfree (cert); xfree (pk); xfree (line);