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
|
||||
return the length of the valid buffer. Plus unescaping is only
|
||||
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 --*/
|
||||
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_unescape (const char *string, int nulrepl);
|
||||
|
||||
|
@ -56,6 +56,17 @@ typedef enum
|
||||
}
|
||||
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. */
|
||||
#define X(a) ((unsigned char const *)(a))
|
||||
static struct
|
||||
@ -306,9 +317,12 @@ struct app_local_s
|
||||
hierarchy. Thus we assume this is directly below the MF. */
|
||||
unsigned short home_df;
|
||||
|
||||
/* The type of the card. */
|
||||
/* The type of the card's OS. */
|
||||
card_type_t card_type;
|
||||
|
||||
/* The vendor's product. */
|
||||
card_product_t card_product;
|
||||
|
||||
/* Flag indicating whether we may use direct path selection. */
|
||||
int direct_path_selection;
|
||||
|
||||
@ -2371,8 +2385,10 @@ read_ef_tokeninfo (app_t app)
|
||||
|
||||
xfree (app->app_local->manufacturer_id);
|
||||
app->app_local->manufacturer_id = NULL;
|
||||
app->app_local->card_product = CARD_PRODUCT_UNKNOWN;
|
||||
|
||||
err = select_and_read_binary (app->slot, 0x5032, "TokenInfo",
|
||||
&buffer, &buflen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -2467,6 +2483,10 @@ read_ef_tokeninfo (app_t app)
|
||||
{
|
||||
if (opt.verbose)
|
||||
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;
|
||||
n -= objlen;
|
||||
/* Get next TLV. */
|
||||
@ -3169,12 +3189,33 @@ prepare_verify_pin (app_t app, const char *keyref,
|
||||
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)
|
||||
{
|
||||
/* According to our protocol analysis we need to select a
|
||||
* special AID here. Before that the master file needs to be
|
||||
* 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;
|
||||
}
|
||||
@ -3706,10 +3747,30 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
|
||||
|
||||
/* 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];
|
||||
|
||||
/* 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[1] = 1;
|
||||
mse[2] = 0x0a; /* RSA, no padding. */
|
||||
@ -3718,13 +3779,13 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
mse[5] = prkdf->key_reference;
|
||||
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
||||
mse, sizeof mse);
|
||||
}
|
||||
/* Check for MSE error. */
|
||||
if (err)
|
||||
{
|
||||
log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exmode = le_value = 0;
|
||||
padind = 0;
|
||||
@ -3734,6 +3795,9 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
le_value = prkdf->keynbits / 8;
|
||||
}
|
||||
|
||||
if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
|
||||
padind = 0x81;
|
||||
|
||||
err = iso7816_decipher (app_get_slot (app), exmode,
|
||||
indata, indatalen,
|
||||
le_value, padind,
|
||||
@ -3886,6 +3950,8 @@ app_select_p15 (app_t app)
|
||||
the common APP structure. */
|
||||
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. */
|
||||
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
|
||||
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,
|
||||
const char *aid, size_t aidlen,
|
||||
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_path (int slot,
|
||||
const unsigned short *path, size_t pathlen);
|
||||
|
Loading…
x
Reference in New Issue
Block a user