mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Merge branch 'STABLE-BRANCH-2-4'
-- Fixed conflicts: NEWS configure.ac doc/gpg.texi
This commit is contained in:
commit
dfa60c09f5
88 changed files with 2655 additions and 1419 deletions
|
@ -56,8 +56,8 @@ typedef enum
|
|||
CARDTYPE_GENERIC = 0,
|
||||
CARDTYPE_GNUK,
|
||||
CARDTYPE_YUBIKEY,
|
||||
CARDTYPE_ZEITCONTROL
|
||||
|
||||
CARDTYPE_ZEITCONTROL,
|
||||
CARDTYPE_SCE7 /* G+D SmartCafe Expert 7.0 */
|
||||
} cardtype_t;
|
||||
|
||||
/* List of supported card applications. The source code for each
|
||||
|
|
155
scd/app-p15.c
155
scd/app-p15.c
|
@ -91,7 +91,8 @@ typedef enum
|
|||
CARD_PRODUCT_DTRUST3, /* D-Trust GmbH (bundesdruckerei.de) */
|
||||
CARD_PRODUCT_DTRUST4,
|
||||
CARD_PRODUCT_GENUA, /* GeNUA mbH */
|
||||
CARD_PRODUCT_NEXUS /* Technology Nexus */
|
||||
CARD_PRODUCT_NEXUS, /* Technology Nexus */
|
||||
CARD_PRODUCT_CVISION /* Cryptovision GmbH */
|
||||
}
|
||||
card_product_t;
|
||||
|
||||
|
@ -143,6 +144,8 @@ static struct
|
|||
#define IS_CARDOS_5(a) ((a)->app_local->card_type == CARD_TYPE_CARDOS_50 \
|
||||
|| (a)->app_local->card_type == CARD_TYPE_CARDOS_53 \
|
||||
|| (a)->app_local->card_type == CARD_TYPE_CARDOS_54)
|
||||
#define IS_STARCOS_3(a) ((a)->app_local->card_type == CARD_TYPE_STARCOS_32)
|
||||
|
||||
|
||||
/* The default PKCS-15 home DF */
|
||||
#define DEFAULT_HOME_DF 0x5015
|
||||
|
@ -532,8 +535,6 @@ struct app_local_s
|
|||
/*** Local prototypes. ***/
|
||||
static gpg_error_t select_ef_by_path (app_t app, const unsigned short *path,
|
||||
size_t pathlen);
|
||||
static gpg_error_t select_df_by_path (app_t app, const unsigned short *path,
|
||||
size_t pathlen);
|
||||
static gpg_error_t keygrip_from_prkdf (app_t app, prkdf_object_t prkdf);
|
||||
static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
|
||||
unsigned char **r_cert, size_t *r_certlen);
|
||||
|
@ -571,6 +572,7 @@ cardproduct2str (card_product_t cardproduct)
|
|||
case CARD_PRODUCT_DTRUST4: return "D-Trust 4.1/4.4";
|
||||
case CARD_PRODUCT_GENUA: return "GeNUA";
|
||||
case CARD_PRODUCT_NEXUS: return "Nexus";
|
||||
case CARD_PRODUCT_CVISION: return "Cryptovison";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -803,7 +805,7 @@ select_by_path (app_t app, const unsigned short *path, size_t pathlen,
|
|||
log_debug ("%s: path=", __func__);
|
||||
for (j=0; j < pathlen; j++)
|
||||
log_printf ("%s%04hX", j? "/":"", path[j]);
|
||||
log_printf ("%s\n",expect_df?" (DF requested)":"");
|
||||
log_printf ("%s", expect_df?" (DF requested)":"");
|
||||
log_printf ("%s\n",app->app_local->direct_path_selection?" (direct)":"");
|
||||
}
|
||||
|
||||
|
@ -867,11 +869,13 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
|
|||
}
|
||||
|
||||
|
||||
#if 0 /* Currently not used. */
|
||||
static gpg_error_t
|
||||
select_df_by_path (app_t app, const unsigned short *path, size_t pathlen)
|
||||
{
|
||||
return select_by_path (app, path, pathlen, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Parse a cert Id string (or a key Id string) and return the binary
|
||||
|
@ -3611,6 +3615,7 @@ read_p15_info (app_t app)
|
|||
gpg_error_t err;
|
||||
prkdf_object_t prkdf;
|
||||
unsigned int flag;
|
||||
const char *manu;
|
||||
|
||||
err = read_ef_tokeninfo (app);
|
||||
if (err)
|
||||
|
@ -3631,18 +3636,22 @@ read_p15_info (app_t app)
|
|||
release_lists (app);
|
||||
|
||||
/* Set a product type from the manufacturer_id. */
|
||||
if (IS_CARDOS_5 (app) && app->app_local->manufacturer_id)
|
||||
if (!(manu = app->app_local->manufacturer_id) || !*manu)
|
||||
; /* No manufacturer_id. */
|
||||
else if (app->app_local->card_product)
|
||||
; /* Already set. */
|
||||
else if (IS_CARDOS_5 (app))
|
||||
{
|
||||
const char *manu = app->app_local->manufacturer_id;
|
||||
|
||||
if (app->app_local->card_product)
|
||||
; /* Already set. */
|
||||
else if (!ascii_strcasecmp (manu, "GeNUA mbH"))
|
||||
if (!ascii_strcasecmp (manu, "GeNUA mbH"))
|
||||
app->app_local->card_product = CARD_PRODUCT_GENUA;
|
||||
else if (!ascii_strcasecmp (manu, "Technology Nexus"))
|
||||
app->app_local->card_product = CARD_PRODUCT_NEXUS;
|
||||
}
|
||||
|
||||
else if (app->app_local->card_type == CARD_TYPE_STARCOS_32)
|
||||
{
|
||||
if (strstr (manu, "cryptovision"))
|
||||
app->app_local->card_product = CARD_PRODUCT_CVISION;
|
||||
}
|
||||
|
||||
/* Read the ODF so that we know the location of all directory
|
||||
files. */
|
||||
|
@ -5053,11 +5062,18 @@ prepare_verify_pin (app_t app, const char *keyref,
|
|||
log_error ("p15: error selecting D-TRUST's AID for key %s: %s\n",
|
||||
keyref, gpg_strerror (err));
|
||||
}
|
||||
else if (prkdf && app->app_local->card_type == CARD_TYPE_STARCOS_32)
|
||||
else if (app->app_local->card_product == CARD_PRODUCT_CVISION)
|
||||
{
|
||||
err = select_df_by_path (app, prkdf->path, prkdf->pathlen);
|
||||
/* According to our protocol analysis we need to select the
|
||||
* PKCS#15 AID here. The traces actually show that this is done
|
||||
* two times but that looks more like a bug. Before that the
|
||||
* master file needs to be selected. */
|
||||
err = iso7816_select_mf (app_get_slot (app));
|
||||
if (!err)
|
||||
err = iso7816_select_application (app_get_slot (app),
|
||||
pkcs15_aid, sizeof pkcs15_aid, 0);
|
||||
if (err)
|
||||
log_error ("p15: error selecting file for key %s: %s\n",
|
||||
log_error ("p15: error selecting PKCS#15 AID for key %s: %s\n",
|
||||
keyref, gpg_strerror (err));
|
||||
}
|
||||
else if (prkdf)
|
||||
|
@ -5497,6 +5513,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||
unsigned char oidbuf[64];
|
||||
size_t oidbuflen;
|
||||
size_t n;
|
||||
int i;
|
||||
unsigned char *indata_buffer = NULL; /* Malloced helper. */
|
||||
|
||||
(void)ctrl;
|
||||
|
@ -5594,7 +5611,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||
{
|
||||
unsigned int framelen;
|
||||
unsigned char *frame;
|
||||
int i;
|
||||
|
||||
framelen = (prkdf->keynbits+7) / 8;
|
||||
if (!framelen)
|
||||
|
@ -5669,6 +5685,23 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||
memcpy (frame, indata, indatalen);
|
||||
framelen = indatalen;
|
||||
}
|
||||
else if (hashalgo && IS_STARCOS_3 (app)
|
||||
&& app->app_local->card_product != CARD_PRODUCT_CVISION)
|
||||
{
|
||||
/* For Starcos we need the plain hash w/o the prefix. */
|
||||
/* Note: This has never been tested because the cvision
|
||||
* sample cards seem not to work this way. */
|
||||
if (indatalen != oidbuflen + digestlen
|
||||
|| memcmp (indata, oidbuf, oidbuflen))
|
||||
{
|
||||
log_error ("p15: non-matching input data for Starcos:"
|
||||
" hash=%d len=%zu\n", hashalgo, indatalen);
|
||||
err = gpg_error (GPG_ERR_INV_VALUE);
|
||||
goto leave;
|
||||
}
|
||||
framelen = indatalen - oidbuflen;
|
||||
memcpy (frame, (const char*)indata + oidbuflen, framelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = 0;
|
||||
|
@ -5758,7 +5791,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||
else
|
||||
{
|
||||
/* The D-TRUST Card 4.x doesn't support setting a security
|
||||
* environment, at least as specified in the specs. Insted a
|
||||
* environment, at least as specified in the specs. Instead a
|
||||
* predefined security environment has to be loaded depending on the
|
||||
* cipher and message digest used. The spec states SE-ID 0x25 for
|
||||
* SHA256, 0x26 for SHA384 and 0x27 for SHA512, when using PKCS#1
|
||||
|
@ -5772,6 +5805,61 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||
0xf3, 0x25, NULL, 0);
|
||||
}
|
||||
}
|
||||
else if (app->app_local->card_product == CARD_PRODUCT_CVISION)
|
||||
{
|
||||
/* I can't make the Starcos 3.2 work the correct way, so let's
|
||||
* make them work in the same way the cryptovision product seems
|
||||
* to do it: Use the plain RSA decryption instead. */
|
||||
unsigned char mse[9];
|
||||
|
||||
i = 0;
|
||||
mse[i++] = 0x84; /* Key reference. */
|
||||
mse[i++] = 1;
|
||||
mse[i++] = prkdf->key_reference;
|
||||
mse[i++] = 0x89; /* Algorithm reference (BCD encoded). */
|
||||
mse[i++] = 2;
|
||||
mse[i++] = 0x11; /* RSA no padding (1 1 3 0). */
|
||||
mse[i++] = 0x30;
|
||||
log_assert (i <= DIM(mse));
|
||||
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
||||
mse, i);
|
||||
}
|
||||
else if (prkdf->key_reference_valid && IS_STARCOS_3 (app))
|
||||
{
|
||||
unsigned char mse[9];
|
||||
|
||||
i = 0;
|
||||
if (prkdf->is_ecc)
|
||||
{
|
||||
log_info ("Note: ECC is not yet implemented for Starcos 3 cards\n");
|
||||
err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = 0;
|
||||
mse[i++] = 0x84; /* Key reference. */
|
||||
mse[i++] = 1;
|
||||
mse[i++] = prkdf->key_reference;
|
||||
mse[i++] = 0x89; /* Algorithm reference (BCD encoded). */
|
||||
mse[i++] = 3;
|
||||
mse[i++] = 0x13; /* RSA PKCS#1 (standard) (1 3 2 3). */
|
||||
mse[i++] = 0x23;
|
||||
switch (hashalgo)
|
||||
{
|
||||
case GCRY_MD_SHA1: mse[i++] = 0x10; break;
|
||||
case GCRY_MD_RMD160: mse[i++] = 0x20; break;
|
||||
case GCRY_MD_SHA256: mse[i++] = 0x30; break;
|
||||
case GCRY_MD_SHA384: mse[i++] = 0x40; break;
|
||||
case GCRY_MD_SHA512: mse[i++] = 0x50; break;
|
||||
case GCRY_MD_SHA224: mse[i++] = 0x60; break;
|
||||
default: err = gpg_error (GPG_ERR_DIGEST_ALGO); break;
|
||||
}
|
||||
log_assert (i <= DIM(mse));
|
||||
if (!err)
|
||||
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB6,
|
||||
mse, i);
|
||||
}
|
||||
}
|
||||
else if (prkdf->key_reference_valid)
|
||||
{
|
||||
unsigned char mse[3];
|
||||
|
@ -5801,9 +5889,14 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||
le_value = 0;
|
||||
}
|
||||
|
||||
err = iso7816_compute_ds (app_get_slot (app),
|
||||
if (app->app_local->card_product == CARD_PRODUCT_CVISION)
|
||||
err = iso7816_decipher (app_get_slot (app),
|
||||
exmode, indata, indatalen,
|
||||
le_value, outdata, outdatalen);
|
||||
le_value, 0, outdata, outdatalen);
|
||||
else
|
||||
err = iso7816_compute_ds (app_get_slot (app),
|
||||
exmode, indata, indatalen,
|
||||
le_value, outdata, outdatalen);
|
||||
|
||||
leave:
|
||||
xfree (indata_buffer);
|
||||
|
@ -5862,6 +5955,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||
prkdf_object_t prkdf; /* The private key object. */
|
||||
aodf_object_t aodf; /* The associated authentication object. */
|
||||
int exmode, le_value, padind;
|
||||
int i;
|
||||
|
||||
(void)ctrl;
|
||||
(void)r_info;
|
||||
|
@ -5960,10 +6054,33 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||
0xF3, 0x31, NULL, 0);
|
||||
}
|
||||
}
|
||||
else if (prkdf->key_reference_valid && IS_STARCOS_3 (app))
|
||||
{
|
||||
unsigned char mse[9];
|
||||
|
||||
i = 0;
|
||||
if (prkdf->is_ecc)
|
||||
{
|
||||
log_info ("Note: ECC is not yet implemented for Starcos 3 cards\n");
|
||||
err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
}
|
||||
else
|
||||
{
|
||||
mse[i++] = 0x84; /* Key reference. */
|
||||
mse[i++] = 1;
|
||||
mse[i++] = prkdf->key_reference;
|
||||
mse[i++] = 0x89; /* Algorithm reference (BCD encoded). */
|
||||
mse[i++] = 2;
|
||||
mse[i++] = 0x11; /* RSA no padding (1 1 3 0). */
|
||||
mse[i++] = 0x30;
|
||||
log_assert (i <= DIM(mse));
|
||||
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
||||
mse, i);
|
||||
}
|
||||
}
|
||||
else if (prkdf->key_reference_valid)
|
||||
{
|
||||
unsigned char mse[9];
|
||||
int i;
|
||||
|
||||
/* Note: This works with CardOS but the D-Trust card has the
|
||||
* problem that the next created signature would be broken. */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* app-piv.c - The OpenPGP card application.
|
||||
* Copyright (C) 2019, 2020 g10 Code GmbH
|
||||
* Copyright (C) 2019, 2020, 2024 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
|
@ -3642,6 +3642,7 @@ app_select_piv (app_t app)
|
|||
size_t aptlen;
|
||||
const unsigned char *s;
|
||||
size_t n;
|
||||
void *relptr1 = NULL;
|
||||
|
||||
/* Note that we select using the AID without the 2 octet version
|
||||
* number. This allows for better reporting of future specs. We
|
||||
|
@ -3667,7 +3668,21 @@ app_select_piv (app_t app)
|
|||
|
||||
s = find_tlv (apt, aptlen, 0x4F, &n);
|
||||
/* Some cards (new Yubikey) return only the PIX, while others
|
||||
* (old Yubikey, PivApplet) return the RID+PIX. */
|
||||
* (old Yubikey, PivApplet) return the RID+PIX.
|
||||
* Sample APTs:
|
||||
* Yubikey 5.4.3: 6111 4f06 000010000100 7907 4f05 a000000308
|
||||
* SCE7.0-G-F-P : 610f 4f06 001000010000 7905 a000000308
|
||||
*/
|
||||
if (app->card->cardtype == CARDTYPE_SCE7
|
||||
&& s && apt && aptlen == 17
|
||||
&& !memcmp (apt, ("\x61\x0f\x4f\x06\x00\x10\x00\x01"
|
||||
"\x00\x00\x79\x05\xa0\x00\x00\x03\x08"), aptlen))
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info ("piv: assuming G&D SCE7.0-G-F-P\n");
|
||||
app->appversion = 0x0100; /* Let's assume this. */
|
||||
goto apt_checked;
|
||||
}
|
||||
if (!s || !((n == 6 && !memcmp (s, piv_aid+5, 4))
|
||||
|| (n == 11 && !memcmp (s, piv_aid, 9))))
|
||||
{
|
||||
|
@ -3702,6 +3717,7 @@ app_select_piv (app_t app)
|
|||
goto leave;
|
||||
}
|
||||
|
||||
apt_checked:
|
||||
app->app_local = xtrycalloc (1, sizeof *app->app_local);
|
||||
if (!app->app_local)
|
||||
{
|
||||
|
@ -3712,6 +3728,41 @@ app_select_piv (app_t app)
|
|||
if (app->card->cardtype == CARDTYPE_YUBIKEY)
|
||||
app->app_local->flags.yubikey = 1;
|
||||
|
||||
/* If we don't have a s/n construct it from the CHUID. */
|
||||
if (!APP_CARD(app)->serialno)
|
||||
{
|
||||
unsigned char *chuid;
|
||||
size_t chuidlen;
|
||||
|
||||
relptr1 = get_one_do (app, 0x5FC102, &chuid, &chuidlen, NULL);
|
||||
if (!relptr1)
|
||||
log_error ("piv: CHUID not found\n");
|
||||
else
|
||||
{
|
||||
s = find_tlv (chuid, chuidlen, 0x34, &n);
|
||||
if (!s || n != 16)
|
||||
{
|
||||
log_error ("piv: Card UUID %s in CHUID\n",
|
||||
s? "invalid":"missing");
|
||||
if (opt.debug && s)
|
||||
log_printhex (s, n, "got");
|
||||
}
|
||||
else
|
||||
{
|
||||
APP_CARD(app)->serialno = xtrymalloc (n);
|
||||
if (!APP_CARD(app)->serialno)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
memcpy (APP_CARD(app)->serialno, s, n);
|
||||
APP_CARD(app)->serialnolen = n;
|
||||
err = app_munge_serialno (APP_CARD(app));
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: Parse the optional and conditional DOs in the APT. */
|
||||
|
||||
|
@ -3739,6 +3790,7 @@ app_select_piv (app_t app)
|
|||
|
||||
|
||||
leave:
|
||||
xfree (relptr1);
|
||||
xfree (apt);
|
||||
if (err)
|
||||
do_deinit (app);
|
||||
|
|
53
scd/app.c
53
scd/app.c
|
@ -112,6 +112,7 @@ strcardtype (cardtype_t t)
|
|||
case CARDTYPE_GNUK: return "gnuk";
|
||||
case CARDTYPE_YUBIKEY: return "yubikey";
|
||||
case CARDTYPE_ZEITCONTROL: return "zeitcontrol";
|
||||
case CARDTYPE_SCE7: return "smartcafe";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
@ -549,6 +550,51 @@ card_reset (card_t card)
|
|||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Return the card type from (ATR,ATRLEN) or CARDTYPE_GENERIC in case
|
||||
* of error or if the ATR was not found. If ATR is NULL, SLOT is used
|
||||
* to retrieve the ATR from the reader. */
|
||||
static cardtype_t
|
||||
atr_to_cardtype (int slot, const unsigned char *atr, size_t atrlen)
|
||||
{
|
||||
#define X(a) ((unsigned char const *)(a))
|
||||
static struct
|
||||
{
|
||||
size_t atrlen;
|
||||
unsigned char const *atr;
|
||||
cardtype_t type;
|
||||
} atrlist[] = {
|
||||
{ 19, X("\x3b\xf9\x96\x00\x00\x80\x31\xfe"
|
||||
"\x45\x53\x43\x45\x37\x20\x0f\x00\x20\x46\x4e"),
|
||||
CARDTYPE_SCE7 },
|
||||
{ 0 }
|
||||
};
|
||||
#undef X
|
||||
unsigned char *atrbuf = NULL;
|
||||
cardtype_t cardtype = 0;
|
||||
int i;
|
||||
|
||||
if (atr)
|
||||
{
|
||||
atrbuf = apdu_get_atr (slot, &atrlen);
|
||||
if (!atrbuf)
|
||||
return 0;
|
||||
atr = atrbuf;
|
||||
}
|
||||
|
||||
for (i=0; atrlist[i].atrlen; i++)
|
||||
if (atrlist[i].atrlen == atrlen
|
||||
&& !memcmp (atrlist[i].atr, atr, atrlen))
|
||||
{
|
||||
cardtype = atrlist[i].type;
|
||||
break;
|
||||
}
|
||||
xfree (atrbuf);
|
||||
return cardtype;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
app_new_register (int slot, ctrl_t ctrl, const char *name,
|
||||
int periodical_check_needed)
|
||||
|
@ -666,13 +712,16 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
|
|||
}
|
||||
xfree (buf);
|
||||
}
|
||||
else
|
||||
card->cardtype = atr_to_cardtype (slot, NULL, 0);
|
||||
}
|
||||
else
|
||||
else /* Got 3F00 */
|
||||
{
|
||||
unsigned char *atr;
|
||||
size_t atrlen;
|
||||
|
||||
/* This is heuristics to identify different implementations. */
|
||||
/* FIXME: The first two checks are pretty OpenPGP card specific. */
|
||||
atr = apdu_get_atr (slot, &atrlen);
|
||||
if (atr)
|
||||
{
|
||||
|
@ -680,6 +729,8 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
|
|||
card->cardtype = CARDTYPE_GNUK;
|
||||
else if (atrlen == 21 && atr[7] == 0x75)
|
||||
card->cardtype = CARDTYPE_ZEITCONTROL;
|
||||
else
|
||||
card->cardtype = atr_to_cardtype (slot, atr, atrlen);
|
||||
xfree (atr);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue