Skip to content

Commit f463586

Browse files
committed
gpgsm: Extend --learn-card by an optional s/n argument.
* agent/command.c (cmd_learn): Allow for s/n argument. * agent/learncard.c (agent_handle_learn): Ditto. * agent/call-scd.c (agent_card_learn): Ditto. Pass it on to scd. * scd/command.c (cmd_switchcard): Factor most code out to ... (switchcard_core): new. (cmd_learn): Add option --demand to specify a s/n. * sm/gpgsm.c (main): Allow a s/n argument for --learn-card. -- This help Kleopatra to get a stable certificate listing. GnuPG-bug-id: 7379
1 parent 5420c4e commit f463586

File tree

9 files changed

+99
-39
lines changed

9 files changed

+99
-39
lines changed

agent/agent.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ int agent_tpm2d_pkdecrypt (ctrl_t ctrl, const unsigned char *cipher,
731731
char **r_buf, size_t *r_len);
732732

733733
/*-- call-scd.c --*/
734-
int agent_card_learn (ctrl_t ctrl,
734+
int agent_card_learn (ctrl_t ctrl, const char *demand_sn,
735735
void (*kpinfo_cb)(void*, const char *),
736736
void *kpinfo_cb_arg,
737737
void (*certinfo_cb)(void*, const char *),
@@ -780,7 +780,8 @@ gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
780780
int cap, struct card_key_info_s **result);
781781

782782
/*-- learncard.c --*/
783-
int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
783+
int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context,
784+
int force, const char *demand_sn);
784785

785786

786787
/*-- cvt-openpgp.c --*/

agent/call-scd.c

+13-2
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,14 @@ learn_status_cb (void *opaque, const char *line)
260260
return err;
261261
}
262262

263+
263264
/* Perform the LEARN command and return a list of all private keys
264-
stored on the card. */
265+
* stored on the card. If DEMAND_SN is given the info is returned for
266+
* the card with that S/N instead of the current card. This may then
267+
* switch the current card. */
265268
int
266269
agent_card_learn (ctrl_t ctrl,
270+
const char *demand_sn,
267271
void (*kpinfo_cb)(void*, const char *),
268272
void *kpinfo_cb_arg,
269273
void (*certinfo_cb)(void*, const char *),
@@ -273,6 +277,7 @@ agent_card_learn (ctrl_t ctrl,
273277
{
274278
int rc;
275279
struct learn_parm_s parm;
280+
char line[ASSUAN_LINELENGTH];
276281

277282
rc = start_scd (ctrl);
278283
if (rc)
@@ -285,7 +290,13 @@ agent_card_learn (ctrl_t ctrl,
285290
parm.certinfo_cb_arg = certinfo_cb_arg;
286291
parm.sinfo_cb = sinfo_cb;
287292
parm.sinfo_cb_arg = sinfo_cb_arg;
288-
rc = assuan_transact (daemon_ctx (ctrl), "LEARN --force",
293+
294+
if (demand_sn && *demand_sn)
295+
snprintf (line, sizeof line, "LEARN --demand=%s --force", demand_sn);
296+
else
297+
snprintf (line, sizeof line, "LEARN --force");
298+
299+
rc = assuan_transact (daemon_ctx (ctrl), line,
289300
NULL, NULL, NULL, NULL,
290301
learn_status_cb, &parm);
291302
if (rc)

agent/command.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -2376,27 +2376,31 @@ cmd_get_confirmation (assuan_context_t ctx, char *line)
23762376

23772377

23782378
static const char hlp_learn[] =
2379-
"LEARN [--send] [--sendinfo] [--force]\n"
2379+
"LEARN [--send] [--sendinfo] [--force] [SERIALNO]\n"
23802380
"\n"
23812381
"Learn something about the currently inserted smartcard. With\n"
23822382
"--sendinfo information about the card is returned; with --send\n"
23832383
"the available certificates are returned as D lines; with --force\n"
2384-
"private key storage will be updated by the result.";
2384+
"private key storage will be updated by the result. With SERIALNO\n"
2385+
"given the current card is first switched to the specified one.";
23852386
static gpg_error_t
23862387
cmd_learn (assuan_context_t ctx, char *line)
23872388
{
23882389
ctrl_t ctrl = assuan_get_pointer (ctx);
23892390
gpg_error_t err;
23902391
int send, sendinfo, force;
2392+
const char *demand_sn;
23912393

23922394
send = has_option (line, "--send");
23932395
sendinfo = send? 1 : has_option (line, "--sendinfo");
23942396
force = has_option (line, "--force");
2397+
line = skip_options (line);
2398+
demand_sn = *line? line : NULL;
23952399

23962400
if (ctrl->restricted)
23972401
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
23982402

2399-
err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
2403+
err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force, demand_sn);
24002404
return leave_cmd (ctx, err);
24012405
}
24022406

agent/learncard.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,14 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
295295
return 0;
296296
}
297297

298+
298299
/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL and
299-
SEND is true all new certificates are send back via Assuan. */
300+
* SEND is true all new certificates are send back via Assuan. If
301+
* DEMAND_SN is not NULL it has a string with the serial number of the
302+
* card requested. */
300303
int
301-
agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
304+
agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force,
305+
const char *demand_sn)
302306
{
303307
int rc;
304308
struct kpinfo_cb_parm_s parm;
@@ -328,7 +332,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
328332
cparm.ctrl = ctrl;
329333

330334
/* Now gather all the available info. */
331-
rc = agent_card_learn (ctrl, kpinfo_cb, &parm, certinfo_cb, &cparm,
335+
rc = agent_card_learn (ctrl, demand_sn, kpinfo_cb, &parm, certinfo_cb, &cparm,
332336
sinfo_cb, &sparm);
333337
if (!rc && (parm.error || cparm.error || sparm.error))
334338
rc = parm.error? parm.error : cparm.error? cparm.error : sparm.error;

doc/gpgsm.texi

+5-4
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,12 @@ Import the certificates from the PEM or binary encoded files as well as
291291
from signed-only messages. This command may also be used to import a
292292
secret key from a PKCS#12 file.
293293

294-
@item --learn-card
294+
@item --learn-card [@var{serialno}]
295295
@opindex learn-card
296-
Read information about the private keys from the smartcard and import
297-
the certificates from there. This command utilizes the @command{gpg-agent}
298-
and in turn the @command{scdaemon}.
296+
Read information about the private keys from the current smartcard and import
297+
the certificates from there. This command utilizes @command{gpg-agent}
298+
and in turn @command{scdaemon}. If @var{serialno} is provided the
299+
system first makes that card the current one.
299300

300301
@item --change-passphrase @var{user_id}
301302
@opindex change-passphrase

scd/command.c

+52-19
Original file line numberDiff line numberDiff line change
@@ -384,28 +384,14 @@ cmd_serialno (assuan_context_t ctx, char *line)
384384

385385

386386

387-
static const char hlp_switchcard[] =
388-
"SWITCHCARD [<serialno>]\n"
389-
"\n"
390-
"Make the card with SERIALNO the current card.\n"
391-
"The command \"getinfo card_list\" can be used to list\n"
392-
"the serial numbers of inserted and known cards. Note\n"
393-
"that the command \"SERIALNO\" can be used to refresh\n"
394-
"the list of known cards. A simple SERIALNO status\n"
395-
"is printed on success.";
387+
/* Helper for cmd_swicthcard and cmd_learn. */
396388
static gpg_error_t
397-
cmd_switchcard (assuan_context_t ctx, char *line)
389+
switchcard_core (ctrl_t ctrl, const char *line)
398390
{
399-
ctrl_t ctrl = assuan_get_pointer (ctx);
400391
gpg_error_t err = 0;
401392
unsigned char *sn_bin = NULL;
402393
size_t sn_bin_len = 0;
403394

404-
if ((err = open_card (ctrl)))
405-
return err;
406-
407-
line = skip_options (line);
408-
409395
if (*line)
410396
{
411397
sn_bin = hex_to_buffer (line, &sn_bin_len);
@@ -425,6 +411,30 @@ cmd_switchcard (assuan_context_t ctx, char *line)
425411
}
426412

427413

414+
static const char hlp_switchcard[] =
415+
"SWITCHCARD [<serialno>]\n"
416+
"\n"
417+
"Make the card with SERIALNO the current card.\n"
418+
"The command \"getinfo card_list\" can be used to list\n"
419+
"the serial numbers of inserted and known cards. Note\n"
420+
"that the command \"SERIALNO\" can be used to refresh\n"
421+
"the list of known cards. A simple SERIALNO status\n"
422+
"is printed on success.";
423+
static gpg_error_t
424+
cmd_switchcard (assuan_context_t ctx, char *line)
425+
{
426+
ctrl_t ctrl = assuan_get_pointer (ctx);
427+
gpg_error_t err;
428+
429+
if ((err = open_card (ctrl)))
430+
return err;
431+
432+
line = skip_options (line);
433+
434+
return switchcard_core (ctrl, line);
435+
}
436+
437+
428438
static const char hlp_switchapp[] =
429439
"SWITCHAPP [<appname>]\n"
430440
"\n"
@@ -458,7 +468,8 @@ cmd_switchapp (assuan_context_t ctx, char *line)
458468

459469

460470
static const char hlp_learn[] =
461-
"LEARN [--force] [--keypairinfo] [--reread] [--multi]\n"
471+
"LEARN [--force] [--keypairinfo] [--reread] [--multi] KEYGRIP\n"
472+
"LEARN [--demand=<serialno>] [--force] [--keypairinfo] [--reread] [--multi]\n"
462473
"\n"
463474
"Learn all useful information of the currently inserted card. When\n"
464475
"used without the force options, the command might do an INQUIRE\n"
@@ -529,6 +540,8 @@ static const char hlp_learn[] =
529540
"\n"
530541
"The URL to be used for locating the entire public key.\n"
531542
" \n"
543+
"If KEYGRIP is given the card holding a key with that keygrip is used.\n"
544+
"If --demand is used the card with the specified S/N is used.\n"
532545
"Note, that this function may even be used on a locked card.";
533546
static gpg_error_t
534547
cmd_learn (assuan_context_t ctx, char *line)
@@ -539,17 +552,37 @@ cmd_learn (assuan_context_t ctx, char *line)
539552
int opt_multi = has_option (line, "--multi");
540553
int opt_reread = has_option (line, "--reread");
541554
int opt_force = has_option (line, "--force");
555+
const char *opt_demand;
542556
unsigned int flags;
543557
card_t card;
544558
const char *keygrip = NULL;
545559

546-
if ((rc = open_card (ctrl)))
547-
return rc;
560+
opt_demand = has_option_name (line, "--demand");
561+
if (opt_demand)
562+
{
563+
if (*opt_demand != '=')
564+
return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
565+
line = (char *)++opt_demand;
566+
while (*line && !spacep (line))
567+
line++;
568+
if (*line)
569+
*line++ = 0;
570+
}
548571

549572
line = skip_options (line);
550573
if (strlen (line) == 40)
551574
keygrip = line;
552575

576+
if ((rc = open_card (ctrl)))
577+
return rc;
578+
579+
if (opt_demand)
580+
{
581+
rc = switchcard_core (ctrl, opt_demand);
582+
if (rc)
583+
return rc;
584+
}
585+
553586
card = card_get (ctrl, keygrip);
554587
if (!card)
555588
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);

sm/call-agent.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -1275,14 +1275,17 @@ learn_cb (void *opaque, const void *buffer, size_t length)
12751275
return 0;
12761276
}
12771277

1278-
/* Call the agent to learn about a smartcard */
1278+
1279+
/* Call the agent to learn about a smartcard. If SERIALNO is not NULL
1280+
* switch to the card with that s/n first. */
12791281
int
1280-
gpgsm_agent_learn (ctrl_t ctrl)
1282+
gpgsm_agent_learn (ctrl_t ctrl, const char *serialno)
12811283
{
12821284
int rc;
12831285
struct learn_parm_s learn_parm;
12841286
membuf_t data;
12851287
size_t len;
1288+
char line[ASSUAN_LINELENGTH];
12861289

12871290
rc = start_agent (ctrl);
12881291
if (rc)
@@ -1297,7 +1300,10 @@ gpgsm_agent_learn (ctrl_t ctrl)
12971300
learn_parm.ctrl = ctrl;
12981301
learn_parm.ctx = agent_ctx;
12991302
learn_parm.data = &data;
1300-
rc = assuan_transact (agent_ctx, "LEARN --send",
1303+
snprintf (line, sizeof line, "LEARN --send%s%s",
1304+
serialno? " -- ":"",
1305+
serialno? serialno:"");
1306+
rc = assuan_transact (agent_ctx, line,
13011307
learn_cb, &learn_parm,
13021308
NULL, NULL,
13031309
learn_status_cb, &learn_parm);

sm/gpgsm.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -2269,11 +2269,11 @@ main ( int argc, char **argv)
22692269

22702270

22712271
case aLearnCard:
2272-
if (argc)
2272+
if (argc > 1)
22732273
wrong_args ("--learn-card");
22742274
else
22752275
{
2276-
int rc = gpgsm_agent_learn (&ctrl);
2276+
int rc = gpgsm_agent_learn (&ctrl, argc? *argv : NULL);
22772277
if (rc)
22782278
log_error ("error learning card: %s\n", gpg_strerror (rc));
22792279
}

sm/gpgsm.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ int gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr,
539539
struct rootca_flags_s *rootca_flags);
540540
int gpgsm_agent_havekey (ctrl_t ctrl, const char *hexkeygrip);
541541
int gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert);
542-
int gpgsm_agent_learn (ctrl_t ctrl);
542+
int gpgsm_agent_learn (ctrl_t ctrl, const char *serialno);
543543
int gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc);
544544
gpg_error_t gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc);
545545
gpg_error_t gpgsm_agent_send_nop (ctrl_t ctrl);

0 commit comments

Comments
 (0)