aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app-p15.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/app-p15.c')
-rw-r--r--scd/app-p15.c142
1 files changed, 126 insertions, 16 deletions
diff --git a/scd/app-p15.c b/scd/app-p15.c
index 7a92da10b..d2ed15a59 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -59,11 +59,15 @@ static struct
"\x90\x00\x66",
CARD_TYPE_TCOS }, /* SLE66P */
{ 27, "\x3B\xFF\x94\x00\xFF\x80\xB1\xFE\x45\x1F\x03\x00\x68\xD2\x76\x00"
- "\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23",
+ "\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23",
CARD_TYPE_MICARDO }, /* German BMI card */
+ { 19, "\x3B\x6F\x00\xFF\x00\x68\xD2\x76\x00\x00\x28\xFF\x05\x1E\x31\x80"
+ "\x00\x90\x00",
+ CARD_TYPE_MICARDO }, /* German BMI card (ATR due to reader problem) */
{ 26, "\x3B\xFE\x94\x00\xFF\x80\xB1\xFA\x45\x1F\x03\x45\x73\x74\x45\x49"
"\x44\x20\x76\x65\x72\x20\x31\x2E\x30\x43",
CARD_TYPE_MICARDO }, /* EstEID (Estonian Big Brother card) */
+
{ 0 }
};
@@ -392,7 +396,7 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
}
-/* This function calls select file to read a file suing a complete
+/* This function calls select file to read a file using a complete
path which may or may not start at the master file (MF). */
static gpg_error_t
select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
@@ -2525,6 +2529,99 @@ do_readcert (app_t app, const char *certid,
}
+/* Micardo cards require special treatment. This is a helper for the
+ crypto functions to manage the security environment. We expect that
+ the key file has already been selected. FID is the one of the
+ selected key. */
+static gpg_error_t
+micardo_mse (app_t app, unsigned short fid)
+{
+ gpg_error_t err;
+ int recno;
+ unsigned short refdata = 0;
+ int se_num;
+ unsigned char msebuf[10];
+
+ /* Read the KeyD file containing extra information on keys. */
+ err = iso7816_select_file (app->slot, 0x0013, 0, NULL, NULL);
+ if (err)
+ {
+ log_error ("error reading EF_keyD: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ for (recno = 1, se_num = -1; ; recno++)
+ {
+ unsigned char *buffer;
+ size_t buflen;
+ size_t n, nn;
+ const unsigned char *p, *pp;
+
+ err = iso7816_read_record (app->slot, recno, 1, 0, &buffer, &buflen);
+ if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ break; /* ready */
+ if (err)
+ {
+ log_error ("error reading EF_keyD record: %s\n",
+ gpg_strerror (err));
+ return err;
+ }
+ log_printhex ("keyD record:", buffer, buflen);
+ p = find_tlv (buffer, buflen, 0x83, &n);
+ if (p && n == 4 && ((p[2]<<8)|p[3]) == fid)
+ {
+ refdata = ((p[0]<<8)|p[1]);
+ /* Locate the SE DO and the there included sec env number. */
+ p = find_tlv (buffer, buflen, 0x7b, &n);
+ if (p && n)
+ {
+ pp = find_tlv (p, n, 0x80, &nn);
+ if (pp && nn == 1)
+ {
+ se_num = *pp;
+ xfree (buffer);
+ break; /* found. */
+ }
+ }
+ }
+ xfree (buffer);
+ }
+ if (se_num == -1)
+ {
+ log_error ("CRT for keyfile %04hX not found\n", fid);
+ return gpg_error (GPG_ERR_NOT_FOUND);
+ }
+
+
+ /* Restore the security environment to SE_NUM if needed */
+ if (se_num)
+ {
+ err = iso7816_manage_security_env (app->slot, 0xf3, se_num, NULL, 0);
+ if (err)
+ {
+ log_error ("restoring SE to %d failed: %s\n",
+ se_num, gpg_strerror (err));
+ return err;
+ }
+ }
+
+ /* Set the DST reference data. */
+ msebuf[0] = 0x83;
+ msebuf[1] = 0x03;
+ msebuf[2] = 0x80;
+ msebuf[3] = (refdata >> 8);
+ msebuf[4] = refdata;
+ err = iso7816_manage_security_env (app->slot, 0x41, 0xb6, msebuf, 5);
+ if (err)
+ {
+ log_error ("setting SE to reference file %04hX failed: %s\n",
+ refdata, gpg_strerror (err));
+ return err;
+ }
+ return 0;
+}
+
+
/* Handler for the PKSIGN command.
@@ -2561,6 +2658,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
if (err)
return err;
+ if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover
+ ||prkdf->usageflags.non_repudiation))
+ {
+ log_error ("key %s may not be used for signing\n", keyidstr);
+ return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ }
+
if (!prkdf->authid)
{
log_error ("no authentication object defined for %s\n", keyidstr);
@@ -2597,6 +2701,16 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
return gpg_error (GPG_ERR_INV_CARD);
}
+ /* Select the key file. Note that this may change the security
+ environment thus we do it before PIN verification. */
+ err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
+ if (err)
+ {
+ log_error ("error selecting file for key %s: %s\n",
+ keyidstr, gpg_strerror (errno));
+ return err;
+ }
+
/* Now that we have all the information available, prepare and run
the PIN verification.*/
if (1)
@@ -2742,7 +2856,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
memcpy (data+15, indata, indatalen);
}
-
/* Manage security environment needs to be weaked for certain cards. */
if (app->app_local->card_type == CARD_TYPE_TCOS)
{
@@ -2751,10 +2864,10 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
}
else if (app->app_local->card_type == CARD_TYPE_MICARDO)
{
- /* Micardo cards are very special in that they need to restore a
- security environment using a infomration from a special
- file. */
- log_error ("WARNING: support for MICARDO cards is not yet available\n");
+ if (!prkdf->pathlen)
+ err = gpg_error (GPG_ERR_BUG);
+ else
+ err = micardo_mse (app, prkdf->path[prkdf->pathlen-1]);
}
else if (prkdf->key_reference_valid)
{
@@ -2767,11 +2880,11 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
err = iso7816_manage_security_env (app->slot,
0x41, 0xB6,
mse, sizeof mse);
- if (err)
- {
- log_error ("MSE failed: %s\n", gpg_strerror (err));
- return err;
- }
+ }
+ if (err)
+ {
+ log_error ("MSE failed: %s\n", gpg_strerror (err));
+ return err;
}
@@ -2782,9 +2895,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
-
-
-
/* Select the PKCS#15 application on the card in SLOT. */
gpg_error_t
app_select_p15 (app_t app)
@@ -2846,7 +2956,7 @@ app_select_p15 (app_t app)
the common APP structure. */
app->app_local->card_type = card_type;
- /* Read basic information and check whether this is a real
+ /* Read basic information and thus check whether this is a real
card. */
rc = read_p15_info (app);
if (rc)