mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-10 13:04:23 +01:00
gpg: Allow decryption using non-OpenPGP cards.
* g10/call-agent.c (struct getattr_one_parm_s): New. (getattr_one_status_cb): New. (agent_scd_getattr_one): New. * g10/pubkey-enc.c (get_it): Allow the standard leading zero byte from pkcs#1. * g10/getkey.c (enum_secret_keys): Move to... * g10/skclist.c (enum_secret_keys): here and handle non-OpenPGP cards. -- Signed-off-by: Werner Koch <wk@gnupg.org> (cherry picked from commit ec6a6779236a89d4784a6bb7de0def9cc0f9e8a4) This commit also incorporates "g10: Move enum_secret_keys to skclist.c." Which was started with commit 03a8de7def4195b9accde47c1dcb84279361936d on master about a year ago. Signed-off-by: Werner Koch <wk@gnupg.org> GnuPG-bug-id: 4681
This commit is contained in:
parent
23784f8bf0
commit
9a317557c5
@ -925,6 +925,86 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Object used with the agent_scd_getattr_one. */
|
||||||
|
struct getattr_one_parm_s {
|
||||||
|
const char *keyword; /* Keyword to look for. */
|
||||||
|
char *data; /* Malloced and unescaped data. */
|
||||||
|
gpg_error_t err; /* Error code or 0 on success. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Callback for agent_scd_getattr_one. */
|
||||||
|
static gpg_error_t
|
||||||
|
getattr_one_status_cb (void *opaque, const char *line)
|
||||||
|
{
|
||||||
|
struct getattr_one_parm_s *parm = opaque;
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (parm->data)
|
||||||
|
return 0; /* We want only the first occurrence. */
|
||||||
|
|
||||||
|
if ((s=has_leading_keyword (line, parm->keyword)))
|
||||||
|
{
|
||||||
|
parm->data = percent_plus_unescape (s, 0xff);
|
||||||
|
if (!parm->data)
|
||||||
|
parm->err = gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Simplified version of agent_scd_getattr. This function returns
|
||||||
|
* only the first occurance of the attribute NAME and stores it at
|
||||||
|
* R_VALUE. A nul in the result is silennly replaced by 0xff. On
|
||||||
|
* error NULL is stored at R_VALUE. */
|
||||||
|
gpg_error_t
|
||||||
|
agent_scd_getattr_one (const char *name, char **r_value)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char line[ASSUAN_LINELENGTH];
|
||||||
|
struct default_inq_parm_s inqparm;
|
||||||
|
struct getattr_one_parm_s parm;
|
||||||
|
|
||||||
|
*r_value = NULL;
|
||||||
|
|
||||||
|
if (!*name)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
memset (&inqparm, 0, sizeof inqparm);
|
||||||
|
inqparm.ctx = agent_ctx;
|
||||||
|
|
||||||
|
memset (&parm, 0, sizeof parm);
|
||||||
|
parm.keyword = name;
|
||||||
|
|
||||||
|
/* We assume that NAME does not need escaping. */
|
||||||
|
if (12 + strlen (name) > DIM(line)-1)
|
||||||
|
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||||
|
stpcpy (stpcpy (line, "SCD GETATTR "), name);
|
||||||
|
|
||||||
|
err = start_agent (NULL, 1);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = assuan_transact (agent_ctx, line,
|
||||||
|
NULL, NULL,
|
||||||
|
default_inq_cb, &inqparm,
|
||||||
|
getattr_one_status_cb, &parm);
|
||||||
|
if (!err && parm.err)
|
||||||
|
err = parm.err;
|
||||||
|
else if (!err && !parm.data)
|
||||||
|
err = gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
*r_value = parm.data;
|
||||||
|
else
|
||||||
|
xfree (parm.data);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Call the agent to retrieve a data object. This function returns
|
/* Call the agent to retrieve a data object. This function returns
|
||||||
* the data in the same structure as used by the learn command. It is
|
* the data in the same structure as used by the learn command. It is
|
||||||
|
@ -94,6 +94,9 @@ int agent_scd_serialno (char **r_serialno, const char *demand);
|
|||||||
/* Send an APDU to the card. */
|
/* Send an APDU to the card. */
|
||||||
gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
|
gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
|
||||||
|
|
||||||
|
/* Get attribute NAME from the card and store at R_VALUE. */
|
||||||
|
gpg_error_t agent_scd_getattr_one (const char *name, char **r_value);
|
||||||
|
|
||||||
/* Update INFO with the attribute NAME. */
|
/* Update INFO with the attribute NAME. */
|
||||||
int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
|
int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
|
||||||
|
|
||||||
|
174
g10/getkey.c
174
g10/getkey.c
@ -3774,180 +3774,6 @@ lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Enumerate some secret keys (specifically, those specified with
|
|
||||||
* --default-key and --try-secret-key). Use the following procedure:
|
|
||||||
*
|
|
||||||
* 1) Initialize a void pointer to NULL
|
|
||||||
* 2) Pass a reference to this pointer to this function (content)
|
|
||||||
* and provide space for the secret key (sk)
|
|
||||||
* 3) Call this function as long as it does not return an error (or
|
|
||||||
* until you are done). The error code GPG_ERR_EOF indicates the
|
|
||||||
* end of the listing.
|
|
||||||
* 4) Call this function a last time with SK set to NULL,
|
|
||||||
* so that can free it's context.
|
|
||||||
*
|
|
||||||
* In pseudo-code:
|
|
||||||
*
|
|
||||||
* void *ctx = NULL;
|
|
||||||
* PKT_public_key *sk = xmalloc_clear (sizeof (*sk));
|
|
||||||
*
|
|
||||||
* while ((err = enum_secret_keys (&ctx, sk)))
|
|
||||||
* { // Process SK.
|
|
||||||
* if (done)
|
|
||||||
* break;
|
|
||||||
* free_public_key (sk);
|
|
||||||
* sk = xmalloc_clear (sizeof (*sk));
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // Release any resources used by CTX.
|
|
||||||
* enum_secret_keys (&ctx, NULL);
|
|
||||||
* free_public_key (sk);
|
|
||||||
*
|
|
||||||
* if (gpg_err_code (err) != GPG_ERR_EOF)
|
|
||||||
* ; // An error occurred.
|
|
||||||
*/
|
|
||||||
gpg_error_t
|
|
||||||
enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
|
|
||||||
{
|
|
||||||
gpg_error_t err = 0;
|
|
||||||
const char *name;
|
|
||||||
kbnode_t keyblock;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int eof;
|
|
||||||
int state;
|
|
||||||
strlist_t sl;
|
|
||||||
kbnode_t keyblock;
|
|
||||||
kbnode_t node;
|
|
||||||
getkey_ctx_t ctx;
|
|
||||||
} *c = *context;
|
|
||||||
|
|
||||||
if (!c)
|
|
||||||
{
|
|
||||||
/* Make a new context. */
|
|
||||||
c = xtrycalloc (1, sizeof *c);
|
|
||||||
if (!c)
|
|
||||||
return gpg_error_from_syserror ();
|
|
||||||
*context = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sk)
|
|
||||||
{
|
|
||||||
/* Free the context. */
|
|
||||||
release_kbnode (c->keyblock);
|
|
||||||
getkey_end (ctrl, c->ctx);
|
|
||||||
xfree (c);
|
|
||||||
*context = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->eof)
|
|
||||||
return gpg_error (GPG_ERR_EOF);
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
/* Loop until we have a keyblock. */
|
|
||||||
while (!c->keyblock)
|
|
||||||
{
|
|
||||||
/* Loop over the list of secret keys. */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
name = NULL;
|
|
||||||
keyblock = NULL;
|
|
||||||
switch (c->state)
|
|
||||||
{
|
|
||||||
case 0: /* First try to use the --default-key. */
|
|
||||||
name = parse_def_secret_key (ctrl);
|
|
||||||
c->state = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: /* Init list of keys to try. */
|
|
||||||
c->sl = opt.secret_keys_to_try;
|
|
||||||
c->state++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: /* Get next item from list. */
|
|
||||||
if (c->sl)
|
|
||||||
{
|
|
||||||
name = c->sl->d;
|
|
||||||
c->sl = c->sl->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
c->state++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: /* Init search context to enum all secret keys. */
|
|
||||||
err = getkey_bynames (ctrl, &c->ctx, NULL, NULL, 1,
|
|
||||||
&keyblock);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
release_kbnode (keyblock);
|
|
||||||
keyblock = NULL;
|
|
||||||
getkey_end (ctrl, c->ctx);
|
|
||||||
c->ctx = NULL;
|
|
||||||
}
|
|
||||||
c->state++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4: /* Get next item from the context. */
|
|
||||||
if (c->ctx)
|
|
||||||
{
|
|
||||||
err = getkey_next (ctrl, c->ctx, NULL, &keyblock);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
release_kbnode (keyblock);
|
|
||||||
keyblock = NULL;
|
|
||||||
getkey_end (ctrl, c->ctx);
|
|
||||||
c->ctx = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
c->state++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: /* No more names to check - stop. */
|
|
||||||
c->eof = 1;
|
|
||||||
return gpg_error (GPG_ERR_EOF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((!name || !*name) && !keyblock);
|
|
||||||
|
|
||||||
if (keyblock)
|
|
||||||
c->node = c->keyblock = keyblock;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
/* getkey_byname might return a keyblock even in the
|
|
||||||
error case - I have not checked. Thus better release
|
|
||||||
it. */
|
|
||||||
release_kbnode (c->keyblock);
|
|
||||||
c->keyblock = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
c->node = c->keyblock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the next key from the current keyblock. */
|
|
||||||
for (; c->node; c->node = c->node->next)
|
|
||||||
{
|
|
||||||
if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
||||||
|| c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
||||||
{
|
|
||||||
copy_public_key (sk, c->node->pkt->pkt.public_key);
|
|
||||||
c->node = c->node->next;
|
|
||||||
return 0; /* Found. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dispose the keyblock and continue. */
|
|
||||||
release_kbnode (c->keyblock);
|
|
||||||
c->keyblock = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk,
|
get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk,
|
||||||
const byte *fpr_card, size_t fpr_len)
|
const byte *fpr_card, size_t fpr_len)
|
||||||
|
@ -305,6 +305,16 @@ get_it (ctrl_t ctrl,
|
|||||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: Actually the leading zero is required but due to
|
||||||
|
* the way we encode the output in libgcrypt as an MPI we
|
||||||
|
* are not able to encode that leading zero. However, when
|
||||||
|
* using a Smartcard we are doing it the right way and
|
||||||
|
* therefore we have to skip the zero. This should be fixed
|
||||||
|
* in gpg-agent of course. */
|
||||||
|
if (!frame[n])
|
||||||
|
n++;
|
||||||
|
|
||||||
if (frame[n] == 1 && frame[nframe - 1] == 2)
|
if (frame[n] == 1 && frame[nframe - 1] == 2)
|
||||||
{
|
{
|
||||||
log_info (_("old encoding of the DEK is not supported\n"));
|
log_info (_("old encoding of the DEK is not supported\n"));
|
||||||
|
307
g10/skclist.c
307
g10/skclist.c
@ -286,3 +286,310 @@ build_sk_list (ctrl_t ctrl,
|
|||||||
*ret_sk_list = sk_list;
|
*ret_sk_list = sk_list;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Enumerate some secret keys (specifically, those specified with
|
||||||
|
* --default-key and --try-secret-key). Use the following procedure:
|
||||||
|
*
|
||||||
|
* 1) Initialize a void pointer to NULL
|
||||||
|
* 2) Pass a reference to this pointer to this function (content)
|
||||||
|
* and provide space for the secret key (sk)
|
||||||
|
* 3) Call this function as long as it does not return an error (or
|
||||||
|
* until you are done). The error code GPG_ERR_EOF indicates the
|
||||||
|
* end of the listing.
|
||||||
|
* 4) Call this function a last time with SK set to NULL,
|
||||||
|
* so that can free it's context.
|
||||||
|
*
|
||||||
|
* In pseudo-code:
|
||||||
|
*
|
||||||
|
* void *ctx = NULL;
|
||||||
|
* PKT_public_key *sk = xmalloc_clear (sizeof (*sk));
|
||||||
|
*
|
||||||
|
* while ((err = enum_secret_keys (&ctx, sk)))
|
||||||
|
* { // Process SK.
|
||||||
|
* if (done)
|
||||||
|
* break;
|
||||||
|
* sk = xmalloc_clear (sizeof (*sk));
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Release any resources used by CTX.
|
||||||
|
* enum_secret_keys (&ctx, NULL);
|
||||||
|
*
|
||||||
|
* if (gpg_err_code (err) != GPG_ERR_EOF)
|
||||||
|
* ; // An error occurred.
|
||||||
|
*/
|
||||||
|
gpg_error_t
|
||||||
|
enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
|
||||||
|
{
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
const char *name;
|
||||||
|
kbnode_t keyblock;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int eof;
|
||||||
|
int state;
|
||||||
|
strlist_t sl;
|
||||||
|
strlist_t card_list;
|
||||||
|
char *serialno;
|
||||||
|
char fpr2[2 * MAX_FINGERPRINT_LEN + 3 ];
|
||||||
|
struct agent_card_info_s info;
|
||||||
|
kbnode_t keyblock;
|
||||||
|
kbnode_t node;
|
||||||
|
getkey_ctx_t ctx;
|
||||||
|
SK_LIST results;
|
||||||
|
} *c = *context;
|
||||||
|
|
||||||
|
#if MAX_FINGERPRINT_LEN < KEYGRIP_LEN
|
||||||
|
# error buffer too short for this configuration
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
/* Make a new context. */
|
||||||
|
c = xtrycalloc (1, sizeof *c);
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
free_public_key (sk);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
*context = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sk)
|
||||||
|
{
|
||||||
|
/* Free the context. */
|
||||||
|
xfree (c->serialno);
|
||||||
|
free_strlist (c->card_list);
|
||||||
|
release_sk_list (c->results);
|
||||||
|
release_kbnode (c->keyblock);
|
||||||
|
getkey_end (ctrl, c->ctx);
|
||||||
|
xfree (c);
|
||||||
|
*context = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->eof)
|
||||||
|
{
|
||||||
|
free_public_key (sk);
|
||||||
|
return gpg_error (GPG_ERR_EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/* Loop until we have a keyblock. */
|
||||||
|
while (!c->keyblock)
|
||||||
|
{
|
||||||
|
/* Loop over the list of secret keys. */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
char *serialno;
|
||||||
|
|
||||||
|
name = NULL;
|
||||||
|
keyblock = NULL;
|
||||||
|
switch (c->state)
|
||||||
|
{
|
||||||
|
case 0: /* First try to use the --default-key. */
|
||||||
|
name = parse_def_secret_key (ctrl);
|
||||||
|
c->state = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* Init list of keys to try. */
|
||||||
|
c->sl = opt.secret_keys_to_try;
|
||||||
|
c->state++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* Get next item from list. */
|
||||||
|
if (c->sl)
|
||||||
|
{
|
||||||
|
name = c->sl->d;
|
||||||
|
c->sl = c->sl->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
c->state++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: /* Init list of card keys to try. */
|
||||||
|
err = agent_scd_cardlist (&c->card_list);
|
||||||
|
if (!err)
|
||||||
|
agent_scd_serialno (&c->serialno, NULL);
|
||||||
|
c->sl = c->card_list;
|
||||||
|
c->state++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: /* Get next item from card list. */
|
||||||
|
if (c->sl)
|
||||||
|
{
|
||||||
|
err = agent_scd_serialno (&serialno, c->sl->d);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info (_("error getting serial number of card: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
c->sl = c->sl->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (serialno);
|
||||||
|
err = agent_scd_getattr ("KEY-FPR", &c->info);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
if (c->info.fpr2valid)
|
||||||
|
{
|
||||||
|
c->fpr2[0] = '0';
|
||||||
|
c->fpr2[1] = 'x';
|
||||||
|
bin2hex (c->info.fpr2, sizeof c->info.fpr2,
|
||||||
|
c->fpr2 + 2);
|
||||||
|
name = c->fpr2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (gpg_err_code (err) == GPG_ERR_INV_NAME)
|
||||||
|
{
|
||||||
|
/* KEY-FPR not supported by the card - get
|
||||||
|
* the key using the keygrip. */
|
||||||
|
char *keyref;
|
||||||
|
strlist_t kplist, sl;
|
||||||
|
const char *s;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
err = agent_scd_getattr_one ("$ENCRKEYID", &keyref);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
err = agent_scd_keypairinfo (ctrl, &kplist);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
for (sl = kplist; sl; sl = sl->next)
|
||||||
|
if ((s = strchr (sl->d, ' '))
|
||||||
|
&& !strcmp (s+1, keyref))
|
||||||
|
break;
|
||||||
|
if (sl)
|
||||||
|
{
|
||||||
|
c->fpr2[0] = '&';
|
||||||
|
for (i=1, s=sl->d;
|
||||||
|
(*s && *s != ' '
|
||||||
|
&& i < sizeof c->fpr2 - 3);
|
||||||
|
s++, i++)
|
||||||
|
c->fpr2[i] = *s;
|
||||||
|
c->fpr2[i] = 0;
|
||||||
|
name = c->fpr2;
|
||||||
|
}
|
||||||
|
else /* Restore error. */
|
||||||
|
err = gpg_error (GPG_ERR_INV_NAME);
|
||||||
|
free_strlist (kplist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xfree (keyref);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
log_error ("error retrieving key from card: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
|
||||||
|
c->sl = c->sl->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serialno = c->serialno;
|
||||||
|
if (serialno)
|
||||||
|
{
|
||||||
|
/* Select the original card again. */
|
||||||
|
agent_scd_serialno (&c->serialno, serialno);
|
||||||
|
xfree (serialno);
|
||||||
|
}
|
||||||
|
c->state++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: /* Init search context to enum all secret keys. */
|
||||||
|
err = getkey_bynames (ctrl, &c->ctx, NULL, NULL, 1,
|
||||||
|
&keyblock);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
release_kbnode (keyblock);
|
||||||
|
keyblock = NULL;
|
||||||
|
getkey_end (ctrl, c->ctx);
|
||||||
|
c->ctx = NULL;
|
||||||
|
}
|
||||||
|
c->state++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6: /* Get next item from the context. */
|
||||||
|
if (c->ctx)
|
||||||
|
{
|
||||||
|
err = getkey_next (ctrl, c->ctx, NULL, &keyblock);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
release_kbnode (keyblock);
|
||||||
|
keyblock = NULL;
|
||||||
|
getkey_end (ctrl, c->ctx);
|
||||||
|
c->ctx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
c->state++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: /* No more names to check - stop. */
|
||||||
|
c->eof = 1;
|
||||||
|
free_public_key (sk);
|
||||||
|
return gpg_error (GPG_ERR_EOF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ((!name || !*name) && !keyblock);
|
||||||
|
|
||||||
|
if (keyblock)
|
||||||
|
c->node = c->keyblock = keyblock;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
/* getkey_byname might return a keyblock even in the
|
||||||
|
error case - I have not checked. Thus better release
|
||||||
|
it. */
|
||||||
|
release_kbnode (c->keyblock);
|
||||||
|
c->keyblock = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
c->node = c->keyblock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the next key from the current keyblock. */
|
||||||
|
for (; c->node; c->node = c->node->next)
|
||||||
|
{
|
||||||
|
if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|
|| c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
||||||
|
{
|
||||||
|
SK_LIST r;
|
||||||
|
|
||||||
|
/* Skip this candidate if it's already enumerated. */
|
||||||
|
for (r = c->results; r; r = r->next)
|
||||||
|
if (!cmp_public_keys (r->pk, c->node->pkt->pkt.public_key))
|
||||||
|
break;
|
||||||
|
if (r)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
copy_public_key (sk, c->node->pkt->pkt.public_key);
|
||||||
|
c->node = c->node->next;
|
||||||
|
|
||||||
|
r = xtrycalloc (1, sizeof (*r));
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
free_public_key (sk);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->pk = sk;
|
||||||
|
r->next = c->results;
|
||||||
|
c->results = r;
|
||||||
|
|
||||||
|
return 0; /* Found. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dispose the keyblock and continue. */
|
||||||
|
release_kbnode (c->keyblock);
|
||||||
|
c->keyblock = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user