aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--scd/app-common.h5
-rw-r--r--scd/app-openpgp.c63
-rw-r--r--scd/app-piv.c36
-rw-r--r--scd/app.c189
-rw-r--r--scd/command.c4
5 files changed, 178 insertions, 119 deletions
diff --git a/scd/app-common.h b/scd/app-common.h
index ed2a549ae..ad96fc2d6 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -235,9 +235,10 @@ const char *strapptype (apptype_t t);
void app_update_priority_list (const char *arg);
gpg_error_t app_send_card_list (ctrl_t ctrl);
gpg_error_t app_send_active_apps (card_t card, ctrl_t ctrl);
-char *card_get_serialno (card_t card, int is_canonical);
+char *card_get_serialno (card_t card);
char *app_get_serialno (app_t app);
-char *yubikey_get_serialno (app_t app);
+char *card_get_dispserialno (card_t card, int nofallback);
+char *app_get_dispserialno (app_t app, int nofallback);
void app_dump_state (void);
void application_notify_card_reset (int slot);
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 0e3b3daad..440c4d027 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1102,9 +1102,10 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
if (table[idx].special == -1)
{
- /* The serial number is very special. We could have used the
- AID DO to retrieve it. The AID DO is available anyway but
- not hex formatted. */
+ /* The serial number is very special. We can't use the the AID
+ DO (0x4f) becuase this is the serialno per specs with the
+ correct appversion. We might however use a serialno with the
+ version set to 0.0 and that is what we need to return. */
char *serial = app_get_serialno (app);
if (serial)
@@ -1147,17 +1148,14 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
}
if (table[idx].special == -4)
{
- char *serial = app_get_serialno (app);
+ char *serial;
- if (serial)
+ if ((serial = app_get_dispserialno (app, 0)))
{
- if (strlen (serial) > 16+12)
- {
- send_status_info (ctrl, table[idx].name, serial+16, 12, NULL, 0);
- xfree (serial);
- return 0;
- }
+ send_status_info (ctrl, table[idx].name,
+ serial, strlen (serial), NULL, 0);
xfree (serial);
+ return 0;
}
return gpg_error (GPG_ERR_INV_NAME);
}
@@ -1383,39 +1381,6 @@ get_disp_name (app_t app)
}
-/*
- * Yubikey has its own serial number at app->serialno. When Yubikey
- * is used for OpenPGP card app, we get the serial number for OpenPGP
- * card from its AID data object.
- */
-char *
-yubikey_get_serialno (app_t app)
-{
- void *relptr;
- unsigned char *buffer;
- size_t buflen;
- char *serial;
-
- relptr = get_one_do (app, 0x004F, &buffer, &buflen, NULL);
- if (!relptr)
- return NULL;
- if (buflen != 16)
- {
- xfree (relptr);
- return NULL;
- }
-
- serial = xtrymalloc (32 + 1);
- if (!serial)
- return NULL;
-
- serial[32] = 0;
- bin2hex (buffer, buflen, serial);
- xfree (relptr);
- return serial;
-}
-
-
/* Return the pretty formatted serialnumber. On error NULL is
* returned. */
static char *
@@ -6113,7 +6078,15 @@ app_select_openpgp (app_t app)
app->appversion |= buffer[7];
manufacturer = (buffer[8]<<8 | buffer[9]);
- /* For Yubikey, serialno is set in app.c, already. */
+ /* For Yubikey, serialno is set in app.c, already. The problem
+ * is that the OpenPGP appversion has been set to 0.0 because we
+ * are not able to deduce this if the OpenPGP app has not been
+ * enabled. Thus we here to to use the appversion from DO 0x4f
+ * but return a serialno with a version 0.0 as set by app.c.
+ * Users of scdaemon taking the version from the serialno won't
+ * work anymore and need to be modified. Recall that our
+ * architecture requires exactly one serilano per card.
+ */
if (app->card->cardtype == CARDTYPE_YUBIKEY)
xfree (buffer);
else
diff --git a/scd/app-piv.c b/scd/app-piv.c
index 0288d8528..36324e630 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -746,38 +746,6 @@ parse_chv_keyref (const char *keyrefstr)
}
-/* Return an allocated string with the serial number in a format to be
- * show to the user. With FAILMODE is true return NULL if such an
- * abbreviated S/N is not available, else return the full serial
- * number as a hex string. May return NULL on malloc problem. */
-static char *
-get_dispserialno (app_t app, int failmode)
-{
- char *result;
-
- if (app->card && app->card->serialno && app->card->serialnolen == 3+1+4
- && !memcmp (app->card->serialno, "\xff\x02\x00", 3))
- {
- /* This is a 4 byte S/N of a Yubikey which seems to be printed
- * on the token in decimal. Maybe they will print larger S/N
- * also in decimal but we can't be sure, thus do it only for
- * these 32 bit numbers. */
- unsigned long sn;
- sn = app->card->serialno[4] * 16777216;
- sn += app->card->serialno[5] * 65536;
- sn += app->card->serialno[6] * 256;
- sn += app->card->serialno[7];
- result = xtryasprintf ("yk-%lu", sn);
- }
- else if (failmode)
- result = NULL; /* No Abbreviated S/N. */
- else
- result = app_get_serialno (app);
-
- return result;
-}
-
-
/* The verify command can be used to retrieve the security status of
* the card. Given the PIN name (e.g. "PIV.80" for the application
* pin, a ISO7817_VERIFY_* code is returned or a non-negative number
@@ -842,7 +810,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
}
else if (table[idx].special == -3)
{
- char *tmp = get_dispserialno (app, 1);
+ char *tmp = app_get_dispserialno (app, 1);
if (tmp)
{
@@ -1789,7 +1757,7 @@ make_prompt (app_t app, int remaining, const char *firstline)
{
char *serial, *tmpbuf, *result;
- serial = get_dispserialno (app, 0);
+ serial = app_get_dispserialno (app, 0);
if (!serial)
return NULL;
diff --git a/scd/app.c b/scd/app.c
index 872eb0ab2..f17e2d62b 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -302,7 +302,7 @@ app_send_devinfo (ctrl_t ctrl)
char *serialno;
char card_info[80];
- serialno = card_get_serialno (c, 0);
+ serialno = card_get_serialno (c);
snprintf (card_info, sizeof card_info, "DEVICE %s %s",
strcardtype (c->cardtype), serialno);
xfree (serialno);
@@ -514,10 +514,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
card->serialno[2] = 0x0;
card->serialno[3] = formfactor;
memcpy (card->serialno + 4, s0, n);
- /* Note that we do not clear the error
- * so that no further serial number
- * testing is done. After all we just
- * set the serial number. */
+ err = app_munge_serialno (card);
}
}
@@ -559,11 +556,11 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
}
}
- if (!err)
+ if (!err && card->cardtype != CARDTYPE_YUBIKEY)
err = iso7816_select_file (slot, 0x2F02, 0);
- if (!err)
+ if (!err && card->cardtype != CARDTYPE_YUBIKEY)
err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
- if (!err)
+ if (!err && card->cardtype != CARDTYPE_YUBIKEY)
{
size_t n;
const unsigned char *p;
@@ -1142,7 +1139,9 @@ card_unref_locked (card_t card)
FF 00 00 = For serial numbers starting with an FF
FF 01 00 = Some german p15 cards return an empty serial number so the
serial number from the EF(TokenInfo) is used instead.
- FF 02 00 = Serial number from Yubikey config
+ FF 02 00 = Serial number from Yubikey config.
+ This is normally not seen because we modify this here
+ to an OpenPGP Card s/n.
FF 7F 00 = No serialno.
All other serial numbers not starting with FF are used as they are.
@@ -1150,7 +1149,48 @@ card_unref_locked (card_t card)
gpg_error_t
app_munge_serialno (card_t card)
{
- if (card->serialnolen && card->serialno[0] == 0xff)
+ if (card->cardtype == CARDTYPE_YUBIKEY
+ && card->serialnolen == 3 + 1 + 4
+ && !memcmp (card->serialno, "\xff\x02\x00", 3))
+ {
+ /* An example for a serial number is
+ * FF020001008A77C1
+ * ~~~~~~--~~~~~~~~
+ * ! ! !--------- 4 byte s/n
+ * ! !----------- Form factor
+ * !----------------- Our prefix
+ * Yubico seems to use the decimalized version of their S/N
+ * as the OpenPGP card S/N. Thus in theory we can contruct the
+ * number from this information so that we do not rely on having
+ * the OpenPGP app enabled.
+ */
+ unsigned long sn;
+ sn = card->serialno[4] * 16777216;
+ sn += card->serialno[5] * 65536;
+ sn += card->serialno[6] * 256;
+ sn += card->serialno[7];
+ if (sn <= 99999999ul)
+ {
+ char *buf = xtrymalloc (16);
+ if (!buf)
+ return gpg_error_from_syserror ();
+ memcpy (buf, "\xD2\x76\x00\x01\x24\x01", 6);
+ buf[6] = 0; /* Application version which we don't know */
+ buf[7] = 0; /* thus we use 0.0 and don't use this directly. */
+ buf[8] = 0; /* Manufacturer: Yubico (0x0006). */
+ buf[9] = 6;
+ buf[10] = (sn >> 24);
+ buf[11] = (sn >> 16);
+ buf[12] = (sn >> 8);
+ buf[13] = sn;
+ buf[14] = 0; /* Last two bytes are RFU. */
+ buf[15] = 0;
+ xfree (card->serialno);
+ card->serialno = buf;
+ card->serialnolen = 16;
+ }
+ }
+ else if (card->serialnolen && card->serialno[0] == 0xff)
{
/* The serial number starts with our special prefix. This
requires that we put our default prefix "FF0000" in front. */
@@ -1182,7 +1222,7 @@ app_munge_serialno (card_t card)
returned as a malloced string (hex encoded) in SERIAL. Caller must
free SERIAL unless the function returns an error. */
char *
-card_get_serialno (card_t card, int is_canonical)
+card_get_serialno (card_t card)
{
char *serial;
@@ -1191,43 +1231,120 @@ card_get_serialno (card_t card, int is_canonical)
if (!card->serialnolen)
serial = xtrystrdup ("FF7F00");
- else if (card->cardtype == CARDTYPE_YUBIKEY && !is_canonical
- && card->app && card->app->apptype == APPTYPE_OPENPGP)
- {
- app_t a;
+ else
+ serial = bin2hex (card->serialno, card->serialnolen, NULL);
- for (a = card->app; a; a = a->next)
- if (a->apptype == APPTYPE_OPENPGP)
- break;
+ return serial;
+}
- /* Found the OpenPGP app */
- if (a->apptype == APPTYPE_OPENPGP)
- {
- if (card->app != a)
- run_reselect (NULL, card, a, card->app);
+/* Same as card_get_serialno but takes an APP object. */
+char *
+app_get_serialno (app_t app)
+{
+ if (!app || !app->card)
+ {
+ gpg_err_set_errno (0);
+ return NULL;
+ }
+ return card_get_serialno (app->card);
+}
- serial = yubikey_get_serialno (a);
- if (card->app != a)
- run_reselect (NULL, card, card->app, a);
- }
+/* Return an allocated string with the serial number in a format to be
+ * show to the user. With NOFALLBACK set to true return NULL if such an
+ * abbreviated S/N is not available, else return the full serial
+ * number as a hex string. May return NULL on malloc problem. */
+char *
+card_get_dispserialno (card_t card, int nofallback)
+{
+ char *result, *p;
+ unsigned long sn;
+
+ if (card && card->serialno && card->serialnolen == 3+1+4
+ && !memcmp (card->serialno, "\xff\x02\x00", 3))
+ {
+ /* This is a 4 byte S/N of a Yubikey which seems to be printed
+ * on the token in decimal. Maybe they will print larger S/N
+ * also in decimal but we can't be sure, thus do it only for
+ * these 32 bit numbers. */
+ sn = card->serialno[4] * 16777216;
+ sn += card->serialno[5] * 65536;
+ sn += card->serialno[6] * 256;
+ sn += card->serialno[7];
+ if ((card->cardversion >> 16) >= 5)
+ result = xtryasprintf ("%lu %03lu %03lu",
+ (sn/1000000ul),
+ (sn/1000ul % 1000ul),
+ (sn % 1000ul));
else
- goto other;
+ result = xtryasprintf ("%lu", sn);
}
+ else if (card && card->cardtype == CARDTYPE_YUBIKEY)
+ {
+ /* Get back the printed Yubikey number from the OpenPGP AID
+ * Example: D2760001240100000006008A77C10000
+ */
+ result = card_get_serialno (card);
+ if (result && strlen (result) >= 28 && !strncmp (result+16, "0006", 4))
+ {
+ sn = xtoi_2 (result+20) * 16777216;
+ sn += xtoi_2 (result+22) * 65536;
+ sn += xtoi_2 (result+24) * 256;
+ sn += xtoi_2 (result+26);
+ if ((card->cardversion >> 16) >= 5)
+ p = xtryasprintf ("%lu %03lu %03lu",
+ (sn/1000000ul),
+ (sn/1000ul % 1000ul),
+ (sn % 1000ul));
+ else
+ p = xtryasprintf ("%lu", sn);
+ if (p)
+ {
+ xfree (result);
+ result = p;
+ }
+ }
+ else if (nofallback)
+ {
+ xfree (result);
+ result = NULL;
+ }
+ }
+ else if (card && card->app && card->app->apptype == APPTYPE_OPENPGP)
+ {
+ /* Extract number from standard OpenPGP AID. */
+ result = card_get_serialno (card);
+ if (result && strlen (result) > 16+12)
+ {
+ memcpy (result, result+16, 4);
+ result[4] = ' ';
+ memcpy (result+5, result+20, 8);
+ result[13] = 0;
+ }
+ else if (nofallback)
+ {
+ xfree (result);
+ result = NULL;
+ }
+ }
+ else if (nofallback)
+ result = NULL; /* No Abbreviated S/N. */
else
- other:
- serial = bin2hex (card->serialno, card->serialnolen, NULL);
+ result = card_get_serialno (card);
- return serial;
+ return result;
}
-/* Same as card_get_serialno but takes an APP object. */
+/* Same as card_get_dispserialno but takes an APP object. */
char *
-app_get_serialno (app_t app)
+app_get_dispserialno (app_t app, int nofallback)
{
if (!app || !app->card)
- return NULL;
- return card_get_serialno (app->card, 0);
+ {
+ gpg_err_set_errno (0);
+ return NULL;
+ }
+ return card_get_dispserialno (app->card, nofallback);
}
@@ -2136,7 +2253,7 @@ send_serialno_and_app_status (card_t card, int with_apps, ctrl_t ctrl)
membuf_t mb;
int any = 0;
- serial = card_get_serialno (card, 1);
+ serial = card_get_serialno (card);
if (!serial)
return 0; /* Oops. */
diff --git a/scd/command.c b/scd/command.c
index 5eb97fb20..457347121 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -345,7 +345,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
return rc;
}
- serial = card_get_serialno (ctrl->card_ctx, 0);
+ serial = card_get_serialno (ctrl->card_ctx);
if (!serial)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -521,7 +521,7 @@ cmd_learn (assuan_context_t ctx, char *line)
send_status_direct (ctrl, "READER", reader);
/* No need to free the string of READER. */
- serial = card_get_serialno (ctrl->card_ctx, 1);
+ serial = card_get_serialno (ctrl->card_ctx);
if (!serial)
return gpg_error (GPG_ERR_INV_VALUE);