[PATCH GnuPG 2/2] scd:p15: Add support for D-Trust Card 6.1/6.4
Mario Haustein
mario.haustein at hrz.tu-chemnitz.de
Sun Jan 4 17:07:33 CET 2026
* scd/app-p15.c (CARD_TYPE_STARCOS_37): New.
(CARD_PRODUCT_DTRUST6): New.
(read_p15_info): Add workaround for wrongly encoded PIN reference in
EF.AOD
(prepare_verify_pin): Use select_df_by_path to select application, as
the card operating system doesn't support path-based selections.
(do_sign): Support for key reference IDs longer than one byte.
Signed-off-by: Mario Haustein <mario.haustein at hrz.tu-chemnitz.de>
---
scd/app-p15.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 97 insertions(+), 5 deletions(-)
diff --git a/scd/app-p15.c b/scd/app-p15.c
index d12179bb4..4e187b364 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -77,7 +77,8 @@ typedef enum
CARD_TYPE_CARDOS_54,
CARD_TYPE_AET, /* A.E.T. Europe JCOP card. */
CARD_TYPE_BELPIC, /* Belgian eID card specs. */
- CARD_TYPE_STARCOS_32
+ CARD_TYPE_STARCOS_32,
+ CARD_TYPE_STARCOS_37
}
card_type_t;
@@ -90,6 +91,7 @@ typedef enum
CARD_PRODUCT_RSCS, /* Rohde&Schwarz Cybersecurity */
CARD_PRODUCT_DTRUST3, /* D-Trust GmbH (bundesdruckerei.de) */
CARD_PRODUCT_DTRUST4,
+ CARD_PRODUCT_DTRUST6,
CARD_PRODUCT_GENUA, /* GeNUA mbH */
CARD_PRODUCT_NEXUS, /* Technology Nexus */
CARD_PRODUCT_CVISION /* Cryptovision GmbH */
@@ -135,6 +137,9 @@ static struct
{ 25, X("\x3b\x9f\x96\x81\xb1\xfe\x45\x1f\x07\x00\x64\x05"
"\x1e\xb2\x00\x31\xb0\x73\x96\x21\xdb\x05\x90\x00\x5c"),
CARD_TYPE_STARCOS_32 },
+ { 21, X("\x3b\xda\x96\xff\x81\xb1\xfe\x45\x1f\x07\x80\x58"
+ "\x44\x54\x52\x20\x56\x31\x2e\x31\xe2"),
+ CARD_TYPE_STARCOS_37 },
{ 0 }
};
#undef X
@@ -144,7 +149,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)
+#define IS_STARCOS_3(a) ((a)->app_local->card_type == CARD_TYPE_STARCOS_32 \
+ || (a)->app_local->card_type ==
CARD_TYPE_STARCOS_37)
/* The default PKCS-15 home DF */
@@ -560,6 +566,7 @@ cardtype2str (card_type_t cardtype)
case CARD_TYPE_BELPIC: return "Belgian eID";
case CARD_TYPE_AET: return "AET";
case CARD_TYPE_STARCOS_32:return "STARCOS 3.2";
+ case CARD_TYPE_STARCOS_37:return "STARCOS 3.7";
}
return "";
}
@@ -573,6 +580,7 @@ cardproduct2str (card_product_t cardproduct)
case CARD_PRODUCT_RSCS: return "R&S";
case CARD_PRODUCT_DTRUST3: return "D-Trust 3";
case CARD_PRODUCT_DTRUST4: return "D-Trust 4.1/4.4";
+ case CARD_PRODUCT_DTRUST6: return "D-Trust 6.1/6.4";
case CARD_PRODUCT_GENUA: return "GeNUA";
case CARD_PRODUCT_NEXUS: return "Nexus";
case CARD_PRODUCT_CVISION: return "Cryptovison";
@@ -872,13 +880,11 @@ 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
@@ -3921,6 +3927,37 @@ read_p15_info (app_t app)
{
app->app_local->card_product = CARD_PRODUCT_DTRUST4;
}
+ if (!app->app_local->card_product
+ && app->app_local->token_label
+ && !strncmp (app->app_local->token_label, "D-TRUST Card 6.", 15)
+ && app->app_local->card_type == CARD_TYPE_STARCOS_37)
+ {
+ aodf_object_t aodf;
+
+ app->app_local->card_product = CARD_PRODUCT_DTRUST6;
+
+ for (prkdf = app->app_local->private_key_info; prkdf; prkdf = prkdf-
>next)
+ {
+ /* The card supports only OAEP and ECIES decryption, which are not
+ * supported by GnuPG right now. Thus we mask the respectiv usage
+ * flags. */
+ prkdf->usageflags.decrypt = 0;
+ prkdf->usageflags.unwrap = 0;
+ prkdf->usageflags.derive = 0;
+ }
+
+ for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next)
+ if (aodf->auth_type == AUTH_TYPE_PIN
+ && aodf->pin_reference_valid
+ && aodf->label != NULL
+ && !strcmp(aodf->label, "Authentication-PIN"))
+ {
+ /* D-Trust encoded the wrong PIN reference in EF.AOD so we have
to
+ * workaround it. */
+ aodf->pin_reference = 0x82;
+ break;
+ }
+ }
/* Now print the info about the PrKDF. */
@@ -5130,6 +5167,16 @@ prepare_verify_pin (app_t app, const char *keyref,
log_error ("p15: error selecting PKCS#15 AID for key %s: %s\n",
keyref, gpg_strerror (err));
}
+ else if (prkdf && app->app_local->card_product == CARD_PRODUCT_DTRUST6)
+ {
+ /* The card operating system does not support selecting the application
+ * by direct path selection. We need to select all file ids as a
+ * directory file. */
+ err = select_df_by_path (app, prkdf->path, prkdf->pathlen);
+ if (err)
+ log_error ("p15: error selecting directory file for key %s: %s\n",
+ keyref, gpg_strerror (err));
+ }
else if (prkdf)
{
/* Standard case: Select the key file. Note that this may
@@ -5731,7 +5778,8 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr,
int hashalgo,
}
if (app->app_local->card_type == CARD_TYPE_BELPIC
|| app->app_local->card_product == CARD_PRODUCT_NEXUS
- || app->app_local->card_product == CARD_PRODUCT_DTRUST4)
+ || app->app_local->card_product == CARD_PRODUCT_DTRUST4
+ || app->app_local->card_product == CARD_PRODUCT_DTRUST6)
{
/* The default for these cards is to use a plain hash. We
* assume that due to the used certificate the correct hash
@@ -5859,6 +5907,50 @@ 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_DTRUST6)
+ {
+ unsigned char mse[10];
+
+ i = 0;
+ err = 0;
+
+ /* D-Trust-Card uses 3 byte long (negative) key reference IDs */
+ mse[i++] = 0x84; /* Key reference. */
+ mse[i++] = 3;
+ mse[i++] = (prkdf->key_reference >> 16) & 0xff;
+ mse[i++] = (prkdf->key_reference >> 8) & 0xff;
+ mse[i++] = prkdf->key_reference & 0xff;
+
+ if (prkdf->is_ecc)
+ {
+ mse[i++] = 0x89;
+ mse[i++] = 2;
+ mse[i++] = 0x13;
+ mse[i++] = 0x35;
+ }
+ else
+ {
+ 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 (app->app_local->card_product == CARD_PRODUCT_CVISION)
{
/* I can't make the Starcos 3.2 work the correct way, so let's
--
2.52.0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 870 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.gnupg.org/pipermail/gnupg-devel/attachments/20260104/9cd24a35/attachment-0001.sig>
More information about the Gnupg-devel
mailing list