aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app-openpgp.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/app-openpgp.c')
-rw-r--r--scd/app-openpgp.c515
1 files changed, 290 insertions, 225 deletions
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 1e904b578..767f29d26 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -50,27 +50,20 @@
#include <assert.h>
#include <time.h>
-#if GNUPG_MAJOR_VERSION == 1
-/* This is used with GnuPG version < 1.9. The code has been source
- copied from the current GnuPG >= 1.9 and is maintained over
- there. */
-#include "options.h"
-#include "errors.h"
-#include "memory.h"
-#include "cardglue.h"
-#else /* GNUPG_MAJOR_VERSION != 1 */
#include "scdaemon.h"
-#endif /* GNUPG_MAJOR_VERSION != 1 */
-
#include "../common/util.h"
#include "../common/i18n.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
#include "../common/host2net.h"
#include "../common/openpgpdefs.h"
+
+/* The AID of this application. */
+static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
+
+
/* A table describing the DOs of the card. */
static struct {
int tag;
@@ -176,6 +169,7 @@ struct app_local_s {
is usually only required for cross checks
because the length of an S-expression is
implicitly available. */
+ unsigned char keygrip_str[41]; /* The keygrip, null terminated */
} pk[3];
unsigned char status_indicator; /* The card status indicator. */
@@ -348,7 +342,7 @@ get_cached_data (app_t app, int tag,
else
exmode = 0;
- err = iso7816_get_data (app->slot, exmode, tag, &p, &len);
+ err = iso7816_get_data (app_get_slot (app), exmode, tag, &p, &len);
if (err)
return err;
if (len)
@@ -479,7 +473,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
if (app->appversion > 0x0100 && data_objects[i].get_immediate_in_v11)
{
exmode = 0;
- rc = iso7816_get_data (app->slot, exmode, tag, &buffer, &buflen);
+ rc = iso7816_get_data (app_get_slot (app), exmode, tag, &buffer, &buflen);
if (rc)
{
*r_rc = rc;
@@ -821,7 +815,7 @@ store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr,
tag2 = 0xCE + keynumber;
flush_cache_item (app, 0xCD);
- rc = iso7816_put_data (app->slot, 0, tag, fpr, 20);
+ rc = iso7816_put_data (app_get_slot (app), 0, tag, fpr, 20);
if (rc)
log_error (_("failed to store the fingerprint: %s\n"),gpg_strerror (rc));
@@ -834,7 +828,7 @@ store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr,
buf[2] = timestamp >> 8;
buf[3] = timestamp;
- rc = iso7816_put_data (app->slot, 0, tag2, buf, 4);
+ rc = iso7816_put_data (app_get_slot (app), 0, tag2, buf, 4);
if (rc)
log_error (_("failed to store the creation date: %s\n"),
gpg_strerror (rc));
@@ -987,6 +981,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
{ "PRIVATE-DO-3", 0x0103 },
{ "PRIVATE-DO-4", 0x0104 },
{ "$AUTHKEYID", 0x0000, -3 },
+ { "$ENCRKEYID", 0x0000, -6 },
+ { "$SIGNKEYID", 0x0000, -7 },
{ "$DISPSERIALNO",0x0000, -4 },
{ "UIF-1", 0x00D6, 0 },
{ "UIF-2", 0x00D7, 0 },
@@ -1071,6 +1067,18 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
send_key_attr (ctrl, app, table[idx].name, i);
return 0;
}
+ if (table[idx].special == -6)
+ {
+ char const tmp[] = "OPENPGP.2";
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ return 0;
+ }
+ if (table[idx].special == -7)
+ {
+ char const tmp[] = "OPENPGP.1";
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ return 0;
+ }
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc);
if (relptr)
@@ -1214,7 +1222,6 @@ get_remaining_tries (app_t app, int adminpw)
the according hex representation to FPR. Caller must have provide
a buffer at FPR of least 41 bytes. Returns 0 on success or an
error code. */
-#if GNUPG_MAJOR_VERSION > 1
static gpg_error_t
retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
{
@@ -1233,7 +1240,6 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
xfree (relptr);
return err;
}
-#endif /*GNUPG_MAJOR_VERSION > 1*/
/* Retrieve the public key material for the RSA key, whose fingerprint
@@ -1242,7 +1248,6 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
public exponent at E and ELEN. Returns zero on success, an error
code on failure. Caller must release the allocated buffers at M
and E if the function returns success. */
-#if GNUPG_MAJOR_VERSION > 1
static gpg_error_t
retrieve_key_material (FILE *fp, const char *hexkeyid,
const unsigned char **m, size_t *mlen,
@@ -1347,7 +1352,6 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
xfree (line);
return err;
}
-#endif /*GNUPG_MAJOR_VERSION > 1*/
static gpg_error_t
@@ -1561,6 +1565,23 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
}
+static gpg_error_t
+store_keygrip (app_t app, int keyno)
+{
+ gpg_error_t err;
+ unsigned char grip[20];
+
+ err = keygrip_from_canon_sexp (app->app_local->pk[keyno].key,
+ app->app_local->pk[keyno].keylen,
+ grip);
+ if (err)
+ return err;
+
+ bin2hex (grip, 20, app->app_local->pk[keyno].keygrip_str);
+ return 0;
+}
+
+
/* Parse tag-length-value data for public key in BUFFER of BUFLEN
length. Key of KEYNO in APP is updated with an S-expression of
public key. When CTRL is not NULL, fingerprint is computed with
@@ -1612,6 +1633,8 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
app->app_local->pk[keyno].key = keybuf;
/* Decrement for trailing '\0' */
app->app_local->pk[keyno].keylen = len - 1;
+
+ err = store_keygrip (app, keyno);
}
return err;
@@ -1628,7 +1651,6 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
consuming to send it just for the fun of it. However, given that we
use the same code in gpg 1.4, we can't use the gcry S-expression
here but need to open encode it. */
-#if GNUPG_MAJOR_VERSION > 1
static gpg_error_t
get_public_key (app_t app, int keyno)
{
@@ -1673,7 +1695,7 @@ get_public_key (app_t app, int keyno)
le_value = 256; /* Use legacy value. */
}
- err = iso7816_read_public_key (app->slot, exmode,
+ err = iso7816_read_public_key (app_get_slot (app), exmode,
(keyno == 0? "\xB6" :
keyno == 1? "\xB8" : "\xA4"),
2, le_value, &buffer, &buflen);
@@ -1713,7 +1735,8 @@ get_public_key (app_t app, int keyno)
hexkeyid = fpr + 24;
ret = gpgrt_asprintf
- (&command, "gpg --list-keys --with-colons --with-key-data '%s'", fpr);
+ (&command, "%s --list-keys --with-colons --with-key-data '%s'",
+ gnupg_module_name (GNUPG_MODULE_NAME_GPG), fpr);
if (ret < 0)
{
err = gpg_error_from_syserror ();
@@ -1759,17 +1782,17 @@ get_public_key (app_t app, int keyno)
app->app_local->pk[keyno].key = (unsigned char*)keybuf;
/* Decrement for trailing '\0' */
app->app_local->pk[keyno].keylen = len - 1;
+ err = store_keygrip (app, keyno);
}
leave:
/* Set a flag to indicate that we tried to read the key. */
- app->app_local->pk[keyno].read_done = 1;
+ if (!err)
+ app->app_local->pk[keyno].read_done = 1;
xfree (buffer);
return err;
}
-#endif /* GNUPG_MAJOR_VERSION > 1 */
-
/* Send the KEYPAIRINFO back. KEY needs to be in the range [1,3].
@@ -1779,11 +1802,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key)
{
int keyno = key - 1;
gpg_error_t err = 0;
- /* Note that GnuPG 1.x does not need this and it would be too time
- consuming to send it just for the fun of it. */
-#if GNUPG_MAJOR_VERSION > 1
- unsigned char grip[20];
- char gripstr[41];
char idbuf[50];
const char *usage;
@@ -1795,14 +1813,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key)
if (!app->app_local->pk[keyno].key)
goto leave; /* No such key - ignore. */
- err = keygrip_from_canon_sexp (app->app_local->pk[keyno].key,
- app->app_local->pk[keyno].keylen,
- grip);
- if (err)
- goto leave;
-
- bin2hex (grip, 20, gripstr);
-
switch (keyno)
{
case 0: usage = "sc"; break;
@@ -1813,14 +1823,12 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key)
sprintf (idbuf, "OPENPGP.%d", keyno+1);
send_status_info (ctrl, "KEYPAIRINFO",
- gripstr, 40,
+ app->app_local->pk[keyno].keygrip_str, 40,
idbuf, strlen (idbuf),
usage, strlen (usage),
NULL, (size_t)0);
leave:
-#endif /* GNUPG_MAJOR_VERSION > 1 */
-
return err;
}
@@ -1875,7 +1883,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, ctrl_t ctrl, const char *keyid, unsigned int flags,
+ unsigned char **pk, size_t *pklen)
{
gpg_error_t err;
int keyno;
@@ -1898,15 +1907,25 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
if (!buf)
return gpg_error (GPG_ERR_NO_PUBKEY);
- *pklen = app->app_local->pk[keyno].keylen;
- *pk = xtrymalloc (*pklen);
- if (!*pk)
+ if ((flags & APP_READKEY_FLAG_INFO))
{
- err = gpg_error_from_syserror ();
- *pklen = 0;
- return err;
+ err = send_keypair_info (app, ctrl, keyno+1);
+ if (err)
+ return err;
+ }
+
+ if (pk && pklen)
+ {
+ *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);
}
- memcpy (*pk, buf, *pklen);
return 0;
}
@@ -1919,7 +1938,6 @@ static gpg_error_t
do_readcert (app_t app, const char *certid,
unsigned char **cert, size_t *certlen)
{
-#if GNUPG_MAJOR_VERSION > 1
gpg_error_t err;
unsigned char *buffer;
size_t buflen;
@@ -1948,9 +1966,6 @@ do_readcert (app_t app, const char *certid,
}
xfree (relptr);
return err;
-#else
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-#endif
}
@@ -2150,7 +2165,7 @@ verify_a_chv (app_t app,
/* Special case for def_chv2 mechanism. */
if (opt.verbose)
log_info (_("using default PIN as %s\n"), "CHV2");
- rc = iso7816_verify (app->slot, 0x82, "123456", 6);
+ rc = iso7816_verify (app_get_slot (app), 0x82, "123456", 6);
if (rc)
{
/* Verification of CHV2 with the default PIN failed,
@@ -2183,7 +2198,7 @@ verify_a_chv (app_t app,
}
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
+ && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo)
&& !check_pinpad_request (app, &pininfo, 0))
{
/* The reader supports the verify command through the pinpad.
@@ -2199,7 +2214,7 @@ verify_a_chv (app_t app,
gpg_strerror (rc));
return rc;
}
- rc = iso7816_verify_kp (app->slot, 0x80+chvno, &pininfo);
+ rc = iso7816_verify_kp (app_get_slot (app), 0x80+chvno, &pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
@@ -2230,7 +2245,8 @@ verify_a_chv (app_t app,
rc = pin2hash_if_kdf (app, chvno, *pinvalue, pinlen);
if (!rc)
- rc = iso7816_verify (app->slot, 0x80+chvno, *pinvalue, *pinlen);
+ rc = iso7816_verify (app_get_slot (app),
+ 0x80 + chvno, *pinvalue, *pinlen);
}
if (rc)
@@ -2270,7 +2286,7 @@ verify_chv2 (app_t app,
the card is not configured to require a verification before
each CHV1 controlled operation (force_chv1) and if we are not
using the pinpad (PINVALUE == NULL). */
- rc = iso7816_verify (app->slot, 0x81, pinvalue, pinlen);
+ rc = iso7816_verify (app_get_slot (app), 0x81, pinvalue, pinlen);
if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
if (rc)
@@ -2337,13 +2353,11 @@ verify_chv3 (app_t app,
{
int rc = 0;
-#if GNUPG_MAJOR_VERSION != 1
if (!opt.allow_admin)
{
log_info (_("access to admin commands is not configured\n"));
return gpg_error (GPG_ERR_EACCES);
}
-#endif
if (!app->did_chv3)
{
@@ -2360,7 +2374,8 @@ verify_chv3 (app_t app,
return rc;
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
+ && !iso7816_check_pinpad (app_get_slot (app),
+ ISO7816_VERIFY, &pininfo)
&& !check_pinpad_request (app, &pininfo, 1))
{
/* The reader supports the verify command through the pinpad. */
@@ -2373,7 +2388,7 @@ verify_chv3 (app_t app,
gpg_strerror (rc));
return rc;
}
- rc = iso7816_verify_kp (app->slot, 0x83, &pininfo);
+ rc = iso7816_verify_kp (app_get_slot (app), 0x83, &pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
}
@@ -2402,7 +2417,7 @@ verify_chv3 (app_t app,
rc = pin2hash_if_kdf (app, 3, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_verify (app->slot, 0x83, pinvalue, pinlen);
+ rc = iso7816_verify (app_get_slot (app), 0x83, pinvalue, pinlen);
xfree (pinvalue);
}
@@ -2501,7 +2516,8 @@ do_setattr (app_t app, const char *name,
exmode = -254; /* Command chaining with max. 254 bytes. */
else
exmode = 0;
- rc = iso7816_put_data (app->slot, exmode, table[idx].tag, value, valuelen);
+ rc = iso7816_put_data (app_get_slot (app),
+ exmode, table[idx].tag, value, valuelen);
if (rc)
log_error ("failed to set '%s': %s\n", table[idx].name, gpg_strerror (rc));
@@ -2532,7 +2548,6 @@ do_writecert (app_t app, ctrl_t ctrl,
const unsigned char *certdata, size_t certdatalen)
{
(void)ctrl;
-#if GNUPG_MAJOR_VERSION > 1
if (strcmp (certidstr, "OPENPGP.3"))
return gpg_error (GPG_ERR_INV_ID);
if (!certdata || !certdatalen)
@@ -2542,9 +2557,6 @@ do_writecert (app_t app, ctrl_t ctrl,
if (certdatalen > app->app_local->extcap.max_certlen_3)
return gpg_error (GPG_ERR_TOO_LARGE);
return do_setattr (app, "CERT-3", pincb, pincb_arg, certdata, certdatalen);
-#else
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-#endif
}
@@ -2562,7 +2574,7 @@ clear_chv_status (app_t app, int chvno)
apdu[2] = 0xff;
apdu[3] = 0x80+chvno;
- err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL);
+ err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, NULL, NULL, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_INV_VALUE)
@@ -2573,7 +2585,8 @@ clear_chv_status (app_t app, int chvno)
if (chvno == 1)
{
apdu[3]++;
- err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL);
+ err = iso7816_apdu_direct (app_get_slot (app),
+ apdu, 4, 0, NULL, NULL, NULL);
app->did_chv1 = app->did_chv2 = 0;
}
else if (chvno == 2)
@@ -2684,7 +2697,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
/* Version 2 cards. */
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot,
+ && !iso7816_check_pinpad (app_get_slot (app),
ISO7816_CHANGE_REFERENCE_DATA, &pininfo)
&& !check_pinpad_request (app, &pininfo, chvno == 3))
use_pinpad = 1;
@@ -2827,7 +2840,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
rc = pin2hash_if_kdf (app, 0, buffer+pinlen0, &pinlen);
}
if (!rc)
- rc = iso7816_reset_retry_counter_with_rc (app->slot, 0x81,
+ rc = iso7816_reset_retry_counter_with_rc (app_get_slot (app), 0x81,
buffer, pinlen0+pinlen);
wipememory (buffer, pinlen0 + pinlen);
xfree (buffer);
@@ -2844,31 +2857,37 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
{
rc = pin2hash_if_kdf (app, 0, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_put_data (app->slot, 0, 0xD3, pinvalue, pinlen);
+ rc = iso7816_put_data (app_get_slot (app),
+ 0, 0xD3, pinvalue, pinlen);
}
}
else if (reset_mode)
{
rc = pin2hash_if_kdf (app, 1, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_reset_retry_counter (app->slot, 0x81, pinvalue, pinlen);
+ rc = iso7816_reset_retry_counter (app_get_slot (app),
+ 0x81, pinvalue, pinlen);
if (!rc && !app->app_local->extcap.is_v2)
- rc = iso7816_reset_retry_counter (app->slot, 0x82, pinvalue, pinlen);
+ rc = iso7816_reset_retry_counter (app_get_slot (app),
+ 0x82, pinvalue, pinlen);
}
else if (!app->app_local->extcap.is_v2)
{
/* Version 1 cards. */
if (chvno == 1 || chvno == 2)
{
- rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x81, NULL, 0,
pinvalue, strlen (pinvalue));
if (!rc)
- rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x82, NULL, 0,
pinvalue, strlen (pinvalue));
}
else /* CHVNO == 3 */
{
- rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x80 + chvno, NULL, 0,
pinvalue, strlen (pinvalue));
}
}
@@ -2889,7 +2908,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
gpg_strerror (rc));
goto leave;
}
- rc = iso7816_change_reference_data_kp (app->slot, 0x80 + chvno, 0,
+ rc = iso7816_change_reference_data_kp (app_get_slot (app),
+ 0x80 + chvno, 0,
&pininfo);
pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
}
@@ -2899,7 +2919,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
if (!rc)
rc = pin2hash_if_kdf (app, chvno, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_change_reference_data (app->slot, 0x80 + chvno,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x80 + chvno,
oldpinvalue, pinlen0,
pinvalue, pinlen);
}
@@ -2942,7 +2963,7 @@ does_key_exist (app_t app, int keyidx, int generating, int force)
assert (keyidx >=0 && keyidx <= 2);
- if (iso7816_get_data (app->slot, 0, 0x006E, &buffer, &buflen))
+ if (iso7816_get_data (app_get_slot (app), 0, 0x006E, &buffer, &buflen))
{
log_error (_("error reading application data\n"));
return gpg_error (GPG_ERR_GENERAL);
@@ -3256,7 +3277,7 @@ change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen,
return err;
/* Change the attribute. */
- err = iso7816_put_data (app->slot, 0, 0xC1+keyno, buf, buflen);
+ err = iso7816_put_data (app_get_slot (app), 0, 0xC1+keyno, buf, buflen);
if (err)
log_error ("error changing key attribute (key=%d)\n", keyno+1);
else
@@ -3648,7 +3669,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
exmode = -254;
else
exmode = 0;
- err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
+ err = iso7816_put_data_odd (app_get_slot (app), exmode, 0x3fff,
template, template_len);
}
else
@@ -3698,7 +3719,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
goto leave;
/* Store the key. */
- err = iso7816_put_data (app->slot, 0,
+ err = iso7816_put_data (app_get_slot (app), 0,
(app->appversion > 0x0007? 0xE0:0xE9)+keyno,
template, template_len);
}
@@ -3970,7 +3991,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
exmode = -254;
else
exmode = 0;
- err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
+ err = iso7816_put_data_odd (app_get_slot (app), exmode, 0x3fff,
template, template_len);
xfree (template);
}
@@ -4138,7 +4159,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, const char *keytype,
log_info (_("please wait while key is being generated ...\n"));
start_at = time (NULL);
- err = iso7816_generate_keypair (app->slot, exmode, 0x80, 0,
+ err = iso7816_generate_keypair (app_get_slot (app), exmode, 0x80, 0,
(keyno == 0? "\xB6" :
keyno == 1? "\xB8" : "\xA4"),
2, le_value, &buffer, &buflen);
@@ -4269,6 +4290,74 @@ check_against_given_fingerprint (app_t app, const char *fpr, int key)
}
+/* Check KEYIDSTR, if it's valid.
+ When KEYNO is 0, it means it's for PIN check.
+ Otherwise, KEYNO corresponds to the slot (signing, decipher and auth).
+ KEYIDSTR is either:
+ (1) Serial number
+ (2) Serial number "/" fingerprint
+ (3) keygrip
+
+ When KEYNO is 0 and KEYIDSTR is for a keygrip, the keygrip should
+ be to be compared is the first one (keygrip for signing).
+ */
+static int
+check_keyidstr (app_t app, const char *keyidstr, int keyno)
+{
+ int rc;
+ const char *s;
+ int n;
+ const char *fpr = NULL;
+ unsigned char tmp_sn[20]; /* Actually 16 bytes but also for the fpr. */
+
+ if (strlen (keyidstr) < 32)
+ return gpg_error (GPG_ERR_INV_ID);
+ else
+ {
+ for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
+ ;
+
+ /* Check if it's a keygrip */
+ if (n == 40)
+ {
+ const unsigned char *keygrip_str;
+
+ keygrip_str = app->app_local->pk[keyno?keyno-1:0].keygrip_str;
+ if (!strncmp (keygrip_str, keyidstr, 40))
+ return 0;
+ else
+ return gpg_error (GPG_ERR_INV_ID);
+ }
+
+ if (n != 32 || strncmp (keyidstr, "D27600012401", 12))
+ return gpg_error (GPG_ERR_INV_ID);
+ else if (!*s)
+ ; /* no fingerprint given: we allow this for now. */
+ else if (*s == '/')
+ fpr = s + 1;
+ else
+ return gpg_error (GPG_ERR_INV_ID);
+
+ for (s=keyidstr, n=0; n < 16; s += 2, n++)
+ tmp_sn[n] = xtoi_2 (s);
+
+ if (app->card->serialnolen != 16)
+ return gpg_error (GPG_ERR_INV_CARD);
+ if (memcmp (app->card->serialno, tmp_sn, 16))
+ return gpg_error (GPG_ERR_WRONG_CARD);
+ }
+
+ /* If a fingerprint has been specified check it against the one on
+ the card. This is allows for a meaningful error message in case
+ the key on the card has been replaced but the shadow information
+ known to gpg was not updated. If there is no fingerprint, gpg
+ will detect a bogus signature anyway due to the
+ verify-after-signing feature. */
+ rc = (fpr&&keyno)? check_against_given_fingerprint (app, fpr, keyno) : 0;
+
+ return rc;
+}
+
/* Compute a digital signature on INDATA which is expected to be the
raw message digest. For this application the KEYIDSTR consists of
@@ -4314,10 +4403,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
int rc;
unsigned char data[19+64];
size_t datalen;
- unsigned char tmp_sn[20]; /* Actually 16 bytes but also for the fpr. */
- const char *s;
- int n;
- const char *fpr = NULL;
unsigned long sigcount;
int use_auth = 0;
int exmode, le_value;
@@ -4362,40 +4447,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
;
else if (!strcmp (keyidstr, "OPENPGP.3"))
use_auth = 1;
- else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
else
{
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
+ rc = check_keyidstr (app, keyidstr, 1);
+ if (rc)
+ return rc;
}
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, gpg
- will detect a bogus signature anyway due to the
- verify-after-signing feature. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0;
- if (rc)
- return rc;
-
/* Concatenate prefix and digest. */
#define X(a,b,d) \
if (hashalgo == GCRY_MD_ ## a && (d) ) \
@@ -4443,7 +4501,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
char *pinvalue;
int pinlen;
- rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount, &pinvalue, &pinlen);
+ rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount,
+ &pinvalue, &pinlen);
if (rc)
return rc;
@@ -4456,7 +4515,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
pinpad has been used. */
if (!app->did_chv2 && pinvalue && !app->app_local->extcap.is_v2)
{
- rc = iso7816_verify (app->slot, 0x82, pinvalue, pinlen);
+ rc = iso7816_verify (app_get_slot (app), 0x82, pinvalue, pinlen);
if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
if (rc)
@@ -4484,7 +4543,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
exmode = 0;
le_value = 0;
}
- rc = iso7816_compute_ds (app->slot, exmode, data, datalen, le_value,
+ rc = iso7816_compute_ds (app_get_slot (app), exmode, data, datalen, le_value,
outdata, outdatalen);
if (gpg_err_code (rc) == GPG_ERR_TIMEOUT)
clear_chv_status (app, 1);
@@ -4512,10 +4571,6 @@ do_auth (app_t app, const char *keyidstr,
unsigned char **outdata, size_t *outdatalen )
{
int rc;
- unsigned char tmp_sn[20]; /* Actually 16 but we use it also for the fpr. */
- const char *s;
- int n;
- const char *fpr = NULL;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -4543,40 +4598,13 @@ do_auth (app_t app, const char *keyidstr,
/* Check whether an OpenPGP card of any version has been requested. */
if (!strcmp (keyidstr, "OPENPGP.3"))
;
- else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
else
{
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
+ rc = check_keyidstr (app, keyidstr, 3);
+ if (rc)
+ return rc;
}
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, gpg
- will detect a bogus signature anyway due to the
- verify-after-signing feature. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0;
- if (rc)
- return rc;
-
rc = verify_chv2 (app, pincb, pincb_arg);
if (!rc)
{
@@ -4594,7 +4622,7 @@ do_auth (app_t app, const char *keyidstr,
exmode = 0;
le_value = 0;
}
- rc = iso7816_internal_authenticate (app->slot, exmode,
+ rc = iso7816_internal_authenticate (app_get_slot (app), exmode,
indata, indatalen, le_value,
outdata, outdatalen);
if (gpg_err_code (rc) == GPG_ERR_TIMEOUT)
@@ -4612,11 +4640,8 @@ do_decipher (app_t app, const char *keyidstr,
unsigned char **outdata, size_t *outdatalen,
unsigned int *r_info)
{
- int rc;
- unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */
- const char *s;
int n;
- const char *fpr = NULL;
+ int rc;
int exmode, le_value;
unsigned char *fixbuf = NULL;
int padind = 0;
@@ -4628,39 +4653,13 @@ do_decipher (app_t app, const char *keyidstr,
/* Check whether an OpenPGP card of any version has been requested. */
if (!strcmp (keyidstr, "OPENPGP.2"))
;
- else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
else
{
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
+ rc = check_keyidstr (app, keyidstr, 2);
+ if (rc)
+ return rc;
}
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, the
- decryption won't produce the right plaintext anyway. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0;
- if (rc)
- return rc;
-
rc = verify_chv2 (app, pincb, pincb_arg);
if (rc)
return rc;
@@ -4818,7 +4817,7 @@ do_decipher (app_t app, const char *keyidstr,
else
exmode = le_value = 0;
- rc = iso7816_decipher (app->slot, exmode,
+ rc = iso7816_decipher (app_get_slot (app), exmode,
indata, indatalen, le_value, padind,
outdata, outdatalen);
xfree (fixbuf);
@@ -4876,38 +4875,19 @@ do_check_pin (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
- unsigned char tmp_sn[20];
- const char *s;
- int n;
int admin_pin = 0;
+ int rc;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
- /* Check whether an OpenPGP card of any version has been requested. */
- if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
+ rc = check_keyidstr (app, keyidstr, 0);
+ if (rc)
+ return rc;
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* No fingerprint given: we allow this for now. */
- else if (*s == '/')
- ; /* We ignore a fingerprint. */
- else if (!strcmp (s, "[CHV3]") )
+ if ((strlen (keyidstr) >= 32+6 && !strcmp (keyidstr+32, "[CHV3]"))
+ || (strlen (keyidstr) >= 40+6 && !strcmp (keyidstr+40, "[CHV3]")))
admin_pin = 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
/* Yes, there is a race conditions: The user might pull the card
right here and we won't notice that. However this is not a
@@ -4950,6 +4930,65 @@ do_check_pin (app_t app, const char *keyidstr,
return verify_chv2 (app, pincb, pincb_arg);
}
+static gpg_error_t
+do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str)
+{
+ int i;
+
+ /* Make sure we have load the public keys. */
+ for (i = 0; i < 3; i++)
+ get_public_key (app, i);
+
+ if (action == KEYGRIP_ACTION_LOOKUP)
+ {
+ if (keygrip_str == NULL)
+ return gpg_error (GPG_ERR_NOT_FOUND);
+
+ for (i = 0; i < 3; i++)
+ if (app->app_local->pk[i].read_done
+ && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str))
+ return 0; /* Found */
+ }
+ else
+ {
+ char idbuf[50];
+ char buf[65];
+ int data = (action == KEYGRIP_ACTION_SEND_DATA);
+
+ if (DIM (buf) < 2 * app->card->serialnolen + 1)
+ return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
+
+ bin2hex (app->card->serialno, app->card->serialnolen, buf);
+
+ if (keygrip_str == NULL)
+ {
+ for (i = 0; i < 3; i++)
+ if (app->app_local->pk[i].read_done)
+ {
+ sprintf (idbuf, "OPENPGP.%d", i+1);
+ send_keyinfo (ctrl, data,
+ app->app_local->pk[i].keygrip_str,buf, idbuf);
+ }
+ /* Return an error so that the dispatcher keeps on looping
+ * over the other applications. Only for clarity we use a
+ * different error code than for the not_found case. */
+ return gpg_error (GPG_ERR_TRUE);
+ }
+ else
+ {
+ for (i = 0; i < 3; i++)
+ if (app->app_local->pk[i].read_done
+ && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str))
+ {
+ sprintf (idbuf, "OPENPGP.%d", i+1);
+ send_keyinfo (ctrl, data, keygrip_str, buf, idbuf);
+ return 0;
+ }
+ }
+ }
+
+ return gpg_error (GPG_ERR_NOT_FOUND);
+}
/* Show information about card capabilities. */
static void
@@ -5170,13 +5209,36 @@ parse_algorithm_attribute (app_t app, int keyno)
xfree (relptr);
}
+
+/* Reselect the application. This is used by cards which support
+ * on-the-fly switching between applications. */
+static gpg_error_t
+do_reselect (app_t app, ctrl_t ctrl)
+{
+ gpg_error_t err;
+
+ (void)ctrl;
+
+ /* An extra check which should not be necessary because the caller
+ * should have made sure that a re-select is only called for
+ * approriate cards. */
+ if (app->card->cardtype != CARDTYPE_YUBIKEY)
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ /* Note that the card can't cope with P2=0xCO, thus we need to pass
+ * a special flag value. */
+ err = iso7816_select_application (app_get_slot (app),
+ openpgp_aid, sizeof openpgp_aid, 0x0001);
+ return err;
+}
+
+
/* Select the OpenPGP application on the card in SLOT. This function
must be used before any other OpenPGP application functions. */
gpg_error_t
app_select_openpgp (app_t app)
{
- static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
- int slot = app->slot;
+ int slot = app_get_slot (app);
int rc;
unsigned char *buffer;
size_t buflen;
@@ -5184,12 +5246,13 @@ app_select_openpgp (app_t app)
/* Note that the card can't cope with P2=0xCO, thus we need to pass a
special flag value. */
- rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001);
+ rc = iso7816_select_application (slot,
+ openpgp_aid, sizeof openpgp_aid, 0x0001);
if (!rc)
{
unsigned int manufacturer;
- app->apptype = "OPENPGP";
+ app->apptype = APPTYPE_OPENPGP;
app->did_chv1 = 0;
app->did_chv2 = 0;
@@ -5214,9 +5277,9 @@ app_select_openpgp (app_t app)
app->appversion |= buffer[7];
manufacturer = (buffer[8]<<8 | buffer[9]);
- xfree (app->serialno);
- app->serialno = buffer;
- app->serialnolen = buflen;
+ xfree (app->card->serialno);
+ app->card->serialno = buffer;
+ app->card->serialnolen = buflen;
buffer = NULL;
app->app_local = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
@@ -5319,6 +5382,7 @@ app_select_openpgp (app_t app)
dump_all_do (slot);
app->fnc.deinit = do_deinit;
+ app->fnc.reselect = do_reselect;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.readkey = do_readkey;
@@ -5332,6 +5396,7 @@ app_select_openpgp (app_t app)
app->fnc.decipher = do_decipher;
app->fnc.change_pin = do_change_pin;
app->fnc.check_pin = do_check_pin;
+ app->fnc.with_keygrip = do_with_keygrip;
}
leave: