1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-04-17 15:44:34 +02:00

scd: Implement direct access by KEYGRIP for GETATTR and READKEY.

* scd/app-openpgp.c (do_readkey): Handle KEYGRIP access.
* scd/command.c (do_readkey): New.
(cmd_readkey): Use do_readkey supporting KEYGRIP access.
(cmd_getattr): Supporting KEYGRIP access.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2020-01-10 15:58:49 +09:00
parent 63bda3aad8
commit 0cfded4bb1
2 changed files with 127 additions and 58 deletions

View File

@ -1920,7 +1920,21 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags,
int keyno; int keyno;
unsigned char *buf; unsigned char *buf;
if (!strcmp (keyid, "OPENPGP.1")) if (strlen (keyid) == 40)
{
const unsigned char *keygrip_str;
for (keyno = 0; keyno < 3; keyno++)
{
keygrip_str = app->app_local->pk[keyno].keygrip_str;
if (!strncmp (keygrip_str, keyid, 40))
break;
}
if (keyno >= 3)
return gpg_error (GPG_ERR_INV_ID);
}
else if (!strcmp (keyid, "OPENPGP.1"))
keyno = 0; keyno = 0;
else if (!strcmp (keyid, "OPENPGP.2")) else if (!strcmp (keyid, "OPENPGP.2"))
keyno = 1; keyno = 1;

View File

@ -537,8 +537,74 @@ cmd_readcert (assuan_context_t ctx, char *line)
} }
static gpg_error_t
do_readkey (card_t card, ctrl_t ctrl, const char *line,
int opt_info, int opt_nokey,
unsigned char **pk_p, size_t *pklen_p)
{
int rc;
/* 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 (card, ctrl, line,
opt_info? APP_READKEY_FLAG_INFO : 0,
opt_nokey? NULL : pk_p, pklen_p);
if (!rc)
/* Okay, got that key. */
return 0;
if (gpg_err_code (rc) == GPG_ERR_UNSUPPORTED_OPERATION
|| gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
{
unsigned char *cert = NULL;
size_t ncert;
/* Fall back to certificate reading. */
rc = app_readcert (card, ctrl, line, &cert, &ncert);
if (rc)
{
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
return rc;
}
rc = app_help_pubkey_from_cert (cert, ncert, pk_p, pklen_p);
xfree (cert);
if (rc)
{
log_error ("failed to parse the certificate: %s\n",
gpg_strerror (rc));
return rc;
}
if (opt_info)
{
char keygripstr[KEYGRIP_LEN*2+1];
rc = app_help_get_keygrip_string_pk (*pk_p, *pklen_p, keygripstr);
if (rc)
{
log_error ("app_help_get_keygrip_string failed: %s\n",
gpg_strerror (rc));
return rc;
}
/* 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),
NULL, (size_t)0);
}
}
else
log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
return rc;
}
static const char hlp_readkey[] = static const char hlp_readkey[] =
"READKEY [--advanced] [--info[-only]] <keyid>|<oid>\n" "READKEY [--advanced] [--info[-only]] <keyid>|<oid>|<keygrip>\n"
"\n" "\n"
"Return the public key for the given cert or key ID as a standard\n" "Return the public key for the given cert or key ID as a standard\n"
"S-expression. With --advanced the S-expression is returned in\n" "S-expression. With --advanced the S-expression is returned in\n"
@ -552,9 +618,10 @@ cmd_readkey (assuan_context_t ctx, char *line)
int advanced = 0; int advanced = 0;
int opt_info = 0; int opt_info = 0;
int opt_nokey = 0; int opt_nokey = 0;
unsigned char *cert = NULL;
unsigned char *pk = NULL; unsigned char *pk = NULL;
size_t ncert, pklen; size_t pklen;
card_t card;
int direct = 0;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
@ -569,57 +636,26 @@ cmd_readkey (assuan_context_t ctx, char *line)
line = skip_options (line); line = skip_options (line);
line = xstrdup (line); /* Need a copy of the line. */ line = xstrdup (line); /* Need a copy of the line. */
/* If the application supports the READKEY function we use that. if (strlen (line) == 40)
Otherwise we use the old way by extracting it from the
certificate. */
rc = app_readkey (ctrl->card_ctx, ctrl, line,
opt_info? APP_READKEY_FLAG_INFO : 0,
opt_nokey? NULL : &pk, &pklen);
if (!rc)
; /* Okay, got that key. */
else if (gpg_err_code (rc) == GPG_ERR_UNSUPPORTED_OPERATION
|| gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
{ {
/* Fall back to certificate reading. */ card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, line, 0);
rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert); direct = 1;
if (rc)
{
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
goto leave;
}
rc = app_help_pubkey_from_cert (cert, ncert, &pk, &pklen);
if (rc)
{
log_error ("failed to parse the certificate: %s\n",
gpg_strerror (rc));
goto leave;
}
if (opt_info)
{
char keygripstr[KEYGRIP_LEN*2+1];
rc = app_help_get_keygrip_string_pk (pk, pklen, keygripstr);
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),
NULL, (size_t)0);
}
} }
else else
card = ctrl->card_ctx;
if (card)
{ {
log_error ("app_readkey failed: %s\n", gpg_strerror (rc)); if (direct)
goto leave; card_ref (card);
rc = do_readkey (card, ctrl, line, opt_info, opt_nokey, &pk, &pklen);
if (direct)
card_unref (card);
} }
else
rc = gpg_error (GPG_ERR_NO_SECKEY);
if (opt_nokey) if (opt_nokey)
; ;
@ -653,7 +689,6 @@ cmd_readkey (assuan_context_t ctx, char *line)
leave: leave:
xfree (pk); xfree (pk);
xfree (cert);
return rc; return rc;
} }
@ -1004,7 +1039,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
static const char hlp_getattr[] = static const char hlp_getattr[] =
"GETATTR <name>\n" "GETATTR <name> [<keygrip>]\n"
"\n" "\n"
"This command is used to retrieve data from a smartcard. The\n" "This command is used to retrieve data from a smartcard. The\n"
"allowed names depend on the currently selected smartcard\n" "allowed names depend on the currently selected smartcard\n"
@ -1014,13 +1049,16 @@ static const char hlp_getattr[] =
"However, the current implementation assumes that Name is not escaped;\n" "However, the current implementation assumes that Name is not escaped;\n"
"this works as long as no one uses arbitrary escaping. \n" "this works as long as no one uses arbitrary escaping. \n"
"\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.\n"
"When KEYGRIP is specified, it accesses directly with the KEYGRIP.";
static gpg_error_t static gpg_error_t
cmd_getattr (assuan_context_t ctx, char *line) cmd_getattr (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
int rc; int rc;
const char *keyword; const char *keyword;
card_t card;
int direct = 0;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
@ -1031,11 +1069,28 @@ cmd_getattr (assuan_context_t ctx, char *line)
if (*line) if (*line)
*line++ = 0; *line++ = 0;
/* (We ignore any garbage for now.) */ if (strlen (line) == 40)
{
card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, line, 0);
direct = 1;
}
else
card = ctrl->card_ctx;
if (card)
{
if (direct)
card_ref (card);
/* FIXME: Applications should not return sensitive data if the card /* FIXME: Applications should not return sensitive data if the card
is locked. */ is locked. */
rc = app_getattr (ctrl->card_ctx, ctrl, keyword); rc = app_getattr (card, ctrl, keyword);
if (direct)
card_unref (card);
}
else
rc = gpg_error (GPG_ERR_NO_SECKEY);
return rc; return rc;
} }