mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
scd:p15: Fix decrypt followed by sign problem for D-Trust cards.
* scd/iso7816.c (iso7816_select_mf): New. * scd/app-p15.c (card_product_t): New. (struct app_local_s): Add field 'card_product'. (read_ef_tokeninfo): Detect D-Trust card. (prepare_verify_pin): Switch to D-Trust AID. (do_decipher): Restore a SE for D-TRust cards. Change the padding indicator to 0x81. * common/percent.c (percent_data_escape): new. Taken from master. -- Using what I learned from a USB trace running the Governikus Signer Software on Windows this fixes the left over problem with the new D-Trust card support. Signed-off-by: Werner Koch <wk@gnupg.org> Backported from master. This required to add the percent_data_escape function we introduced in master on 2018-07-02: commit 58baf40af641f8cbf597e508a292e85ae94688f1 common: New function percent_data_escape. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
4148976841
commit
471b06e91b
@ -87,6 +87,89 @@ percent_plus_escape (const char *string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a newly malloced string from (DATA,DATALEN) with embedded
|
||||||
|
* nuls quoted as %00. The standard percent unescaping can be used to
|
||||||
|
* reverse this encoding. With PLUS_ESCAPE set plus-escaping (spaces
|
||||||
|
* are replaced by a '+') and escaping of characters with values less
|
||||||
|
* than 0x20 is used. If PREFIX is not NULL it will be prepended to
|
||||||
|
* the output in standard escape format; that is PLUS_ESCAPING is
|
||||||
|
* ignored for PREFIX. */
|
||||||
|
char *
|
||||||
|
percent_data_escape (int plus_escape, const char *prefix,
|
||||||
|
const void *data, size_t datalen)
|
||||||
|
{
|
||||||
|
char *buffer, *p;
|
||||||
|
const unsigned char *s;
|
||||||
|
size_t n;
|
||||||
|
size_t length = 1;
|
||||||
|
|
||||||
|
if (prefix)
|
||||||
|
{
|
||||||
|
for (s = prefix; *s; s++)
|
||||||
|
{
|
||||||
|
if (*s == '%' || *s < 0x20)
|
||||||
|
length += 3;
|
||||||
|
else
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s=data, n=datalen; n; s++, n--)
|
||||||
|
{
|
||||||
|
if (!*s || *s == '%' || (plus_escape && (*s < ' ' || *s == '+')))
|
||||||
|
length += 3;
|
||||||
|
else
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = p = xtrymalloc (length);
|
||||||
|
if (!buffer)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (prefix)
|
||||||
|
{
|
||||||
|
for (s = prefix; *s; s++)
|
||||||
|
{
|
||||||
|
if (*s == '%' || *s < 0x20)
|
||||||
|
{
|
||||||
|
snprintf (p, 4, "%%%02X", *s);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*p++ = *s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s=data, n=datalen; n; s++, n--)
|
||||||
|
{
|
||||||
|
if (!*s)
|
||||||
|
{
|
||||||
|
memcpy (p, "%00", 3);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else if (*s == '%')
|
||||||
|
{
|
||||||
|
memcpy (p, "%25", 3);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else if (plus_escape && *s == ' ')
|
||||||
|
{
|
||||||
|
*p++ = '+';
|
||||||
|
}
|
||||||
|
else if (plus_escape && (*s < ' ' || *s == '+'))
|
||||||
|
{
|
||||||
|
snprintf (p, 4, "%%%02X", *s);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*p++ = *s;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Do the percent and plus/space unescaping from STRING to BUFFER and
|
/* Do the percent and plus/space unescaping from STRING to BUFFER and
|
||||||
return the length of the valid buffer. Plus unescaping is only
|
return the length of the valid buffer. Plus unescaping is only
|
||||||
done if WITHPLUS is true. An escaped Nul character will be
|
done if WITHPLUS is true. An escaped Nul character will be
|
||||||
|
@ -224,6 +224,8 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count);
|
|||||||
|
|
||||||
/*-- percent.c --*/
|
/*-- percent.c --*/
|
||||||
char *percent_plus_escape (const char *string);
|
char *percent_plus_escape (const char *string);
|
||||||
|
char *percent_data_escape (int plus_escape, const char *prefix,
|
||||||
|
const void *data, size_t datalen);
|
||||||
char *percent_plus_unescape (const char *string, int nulrepl);
|
char *percent_plus_unescape (const char *string, int nulrepl);
|
||||||
char *percent_unescape (const char *string, int nulrepl);
|
char *percent_unescape (const char *string, int nulrepl);
|
||||||
|
|
||||||
|
@ -56,6 +56,17 @@ typedef enum
|
|||||||
}
|
}
|
||||||
card_type_t;
|
card_type_t;
|
||||||
|
|
||||||
|
/* The OS of card as specified by card_type_t is not always
|
||||||
|
* sufficient. Thus we also distinguish the actual product build upon
|
||||||
|
* the given OS. */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CARD_PRODUCT_UNKNOWN,
|
||||||
|
CARD_PRODUCT_DTRUST /* D-Trust GmbH (bundesdruckerei.de) */
|
||||||
|
}
|
||||||
|
card_product_t;
|
||||||
|
|
||||||
|
|
||||||
/* A list card types with ATRs noticed with these cards. */
|
/* A list card types with ATRs noticed with these cards. */
|
||||||
#define X(a) ((unsigned char const *)(a))
|
#define X(a) ((unsigned char const *)(a))
|
||||||
static struct
|
static struct
|
||||||
@ -306,9 +317,12 @@ struct app_local_s
|
|||||||
hierarchy. Thus we assume this is directly below the MF. */
|
hierarchy. Thus we assume this is directly below the MF. */
|
||||||
unsigned short home_df;
|
unsigned short home_df;
|
||||||
|
|
||||||
/* The type of the card. */
|
/* The type of the card's OS. */
|
||||||
card_type_t card_type;
|
card_type_t card_type;
|
||||||
|
|
||||||
|
/* The vendor's product. */
|
||||||
|
card_product_t card_product;
|
||||||
|
|
||||||
/* Flag indicating whether we may use direct path selection. */
|
/* Flag indicating whether we may use direct path selection. */
|
||||||
int direct_path_selection;
|
int direct_path_selection;
|
||||||
|
|
||||||
@ -2371,8 +2385,10 @@ read_ef_tokeninfo (app_t app)
|
|||||||
|
|
||||||
xfree (app->app_local->manufacturer_id);
|
xfree (app->app_local->manufacturer_id);
|
||||||
app->app_local->manufacturer_id = NULL;
|
app->app_local->manufacturer_id = NULL;
|
||||||
|
app->app_local->card_product = CARD_PRODUCT_UNKNOWN;
|
||||||
|
|
||||||
err = select_and_read_binary (app->slot, 0x5032, "TokenInfo",
|
err = select_and_read_binary (app->slot, 0x5032, "TokenInfo",
|
||||||
|
&buffer, &buflen);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -2467,6 +2483,10 @@ read_ef_tokeninfo (app_t app)
|
|||||||
{
|
{
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info ("p15: label ........: %.*s\n", (int)objlen, p);
|
log_info ("p15: label ........: %.*s\n", (int)objlen, p);
|
||||||
|
if (objlen > 15 && !memcmp (p, "D-TRUST Card V3", 15)
|
||||||
|
&& app->app_local->card_type == CARD_TYPE_CARDOS_50)
|
||||||
|
app->app_local->card_product = CARD_PRODUCT_DTRUST;
|
||||||
|
|
||||||
p += objlen;
|
p += objlen;
|
||||||
n -= objlen;
|
n -= objlen;
|
||||||
/* Get next TLV. */
|
/* Get next TLV. */
|
||||||
@ -3169,12 +3189,33 @@ prepare_verify_pin (app_t app, const char *keyref,
|
|||||||
return gpg_error (GPG_ERR_INV_CARD);
|
return gpg_error (GPG_ERR_INV_CARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select the key file. Note that this may change the security
|
|
||||||
* environment thus we need to do it before PIN verification. */
|
if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
|
||||||
err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
|
{
|
||||||
if (err)
|
/* According to our protocol analysis we need to select a
|
||||||
log_error ("p15: error selecting file for key %s: %s\n",
|
* special AID here. Before that the master file needs to be
|
||||||
keyref, gpg_strerror (err));
|
* selected. (RID A000000167 is assigned to IBM) */
|
||||||
|
static char const dtrust_aid[] =
|
||||||
|
{ 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E };
|
||||||
|
|
||||||
|
err = iso7816_select_mf (app_get_slot (app));
|
||||||
|
if (!err)
|
||||||
|
err = iso7816_select_application (app_get_slot (app),
|
||||||
|
dtrust_aid, sizeof dtrust_aid, 0);
|
||||||
|
if (err)
|
||||||
|
log_error ("p15: error selecting D-TRUST's AID for key %s: %s\n",
|
||||||
|
keyref, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Standard case: Select the key file. Note that this may
|
||||||
|
* change the security environment thus we need to do it before
|
||||||
|
* PIN verification. */
|
||||||
|
err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
|
||||||
|
if (err)
|
||||||
|
log_error ("p15: error selecting file for key %s: %s\n",
|
||||||
|
keyref, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -3706,10 +3747,30 @@ do_decipher (app_t app, const char *keyidstr,
|
|||||||
|
|
||||||
|
|
||||||
/* The next is guess work for CardOS. */
|
/* The next is guess work for CardOS. */
|
||||||
if (prkdf->key_reference_valid)
|
if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
|
||||||
|
{
|
||||||
|
/* From analyzing an USB trace of a Windows signing application
|
||||||
|
* we see that the SE is simply reset to 0x14. It seems to be
|
||||||
|
* sufficient to do this for decryption; signing still works
|
||||||
|
* with the standard code despite that our trace showed that
|
||||||
|
* there the SE is restored to 0x09. Note that the special
|
||||||
|
* D-Trust AID is in any case select by prepare_verify_pin.
|
||||||
|
*
|
||||||
|
* Hey, D-Trust please hand over the specs so that you can
|
||||||
|
* actually sell your cards and we can properly implement it;
|
||||||
|
* other vendors understand this and do not demand ridiculous
|
||||||
|
* paper work or complicated procedures to get samples. */
|
||||||
|
err = iso7816_manage_security_env (app_get_slot (app),
|
||||||
|
0xF3, 0x14, NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (prkdf->key_reference_valid)
|
||||||
{
|
{
|
||||||
unsigned char mse[6];
|
unsigned char mse[6];
|
||||||
|
|
||||||
|
/* Note: This works with CardOS but the D-Trust card has the
|
||||||
|
* problem that the next created signature would be broken. */
|
||||||
|
|
||||||
mse[0] = 0x80; /* Algorithm reference. */
|
mse[0] = 0x80; /* Algorithm reference. */
|
||||||
mse[1] = 1;
|
mse[1] = 1;
|
||||||
mse[2] = 0x0a; /* RSA, no padding. */
|
mse[2] = 0x0a; /* RSA, no padding. */
|
||||||
@ -3718,13 +3779,13 @@ do_decipher (app_t app, const char *keyidstr,
|
|||||||
mse[5] = prkdf->key_reference;
|
mse[5] = prkdf->key_reference;
|
||||||
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
||||||
mse, sizeof mse);
|
mse, sizeof mse);
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* Check for MSE error. */
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
exmode = le_value = 0;
|
exmode = le_value = 0;
|
||||||
padind = 0;
|
padind = 0;
|
||||||
@ -3734,6 +3795,9 @@ do_decipher (app_t app, const char *keyidstr,
|
|||||||
le_value = prkdf->keynbits / 8;
|
le_value = prkdf->keynbits / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
|
||||||
|
padind = 0x81;
|
||||||
|
|
||||||
err = iso7816_decipher (app_get_slot (app), exmode,
|
err = iso7816_decipher (app_get_slot (app), exmode,
|
||||||
indata, indatalen,
|
indata, indatalen,
|
||||||
le_value, padind,
|
le_value, padind,
|
||||||
@ -3886,6 +3950,8 @@ app_select_p15 (app_t app)
|
|||||||
the common APP structure. */
|
the common APP structure. */
|
||||||
app->app_local->card_type = card_type;
|
app->app_local->card_type = card_type;
|
||||||
|
|
||||||
|
app->app_local->card_product = CARD_PRODUCT_UNKNOWN;
|
||||||
|
|
||||||
/* Store whether we may and should use direct path selection. */
|
/* Store whether we may and should use direct path selection. */
|
||||||
app->app_local->direct_path_selection = direct;
|
app->app_local->direct_path_selection = direct;
|
||||||
|
|
||||||
|
@ -139,6 +139,32 @@ iso7816_select_application (int slot, const char *aid, size_t aidlen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This is the same as iso7816_select_application but may return data
|
||||||
|
* at RESULT,RESULTLEN). */
|
||||||
|
gpg_error_t
|
||||||
|
iso7816_select_application_ext (int slot, const char *aid, size_t aidlen,
|
||||||
|
unsigned int flags,
|
||||||
|
unsigned char **result, size_t *resultlen)
|
||||||
|
{
|
||||||
|
int sw;
|
||||||
|
sw = apdu_send (slot, 0, 0x00, CMD_SELECT_FILE, 4,
|
||||||
|
(flags&1)? 0:0x0c, aidlen, aid,
|
||||||
|
result, resultlen);
|
||||||
|
return map_sw (sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Simple MF selection as supported by some cards. */
|
||||||
|
gpg_error_t
|
||||||
|
iso7816_select_mf (int slot)
|
||||||
|
{
|
||||||
|
int sw;
|
||||||
|
|
||||||
|
sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 0x000, 0x0c, -1, NULL);
|
||||||
|
return map_sw (sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
iso7816_select_file (int slot, int tag, int is_dir)
|
iso7816_select_file (int slot, int tag, int is_dir)
|
||||||
{
|
{
|
||||||
|
@ -51,6 +51,12 @@ gpg_error_t iso7816_map_sw (int sw);
|
|||||||
gpg_error_t iso7816_select_application (int slot,
|
gpg_error_t iso7816_select_application (int slot,
|
||||||
const char *aid, size_t aidlen,
|
const char *aid, size_t aidlen,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
gpg_error_t iso7816_select_application_ext (int slot,
|
||||||
|
const char *aid, size_t aidlen,
|
||||||
|
unsigned int flags,
|
||||||
|
unsigned char **result,
|
||||||
|
size_t *resultlen);
|
||||||
|
gpg_error_t iso7816_select_mf (int slot);
|
||||||
gpg_error_t iso7816_select_file (int slot, int tag, int is_dir);
|
gpg_error_t iso7816_select_file (int slot, int tag, int is_dir);
|
||||||
gpg_error_t iso7816_select_path (int slot,
|
gpg_error_t iso7816_select_path (int slot,
|
||||||
const unsigned short *path, size_t pathlen);
|
const unsigned short *path, size_t pathlen);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user