aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app-nks.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/app-nks.c')
-rw-r--r--scd/app-nks.c123
1 files changed, 119 insertions, 4 deletions
diff --git a/scd/app-nks.c b/scd/app-nks.c
index 4656b238f..7e6c7f9a8 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -100,6 +100,11 @@ struct app_local_s {
int nks_version; /* NKS version. */
int sigg_active; /* True if switched to the SigG application. */
+ int sigg_msig_checked;/* True if we checked for a mass signature card. */
+ int sigg_is_msig; /* True if this is a mass signature card. */
+
+ int need_app_select; /* Need to re-select the application. */
+
};
@@ -120,6 +125,18 @@ do_deinit (app_t app)
}
+static int
+all_zero_p (void *buffer, size_t length)
+{
+ char *p;
+
+ for (p=buffer; length; length--, p++)
+ if (*p)
+ return 0;
+ return 1;
+}
+
+
/* Read the file with FID, assume it contains a public key and return
its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
static gpg_error_t
@@ -590,6 +607,65 @@ do_readcert (app_t app, const char *certid,
}
+/* Handle the READKEY command. On success a canonical encoded
+ S-expression with the public key will get stored at PK and its
+ length at PKLEN; the caller must release that buffer. On error PK
+ and PKLEN are not changed and an error code is returned. As of now
+ this function is only useful for the internal authentication key.
+ Other keys are automagically retrieved via by means of the
+ certificate parsing code in commands.c:cmd_readkey. For internal
+ use PK and PKLEN may be NULL to just check for an existing key. */
+static gpg_error_t
+do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
+{
+ gpg_error_t err;
+ unsigned char *buffer[2];
+ size_t buflen[2];
+ unsigned short path[1] = { 0x4500 };
+
+ /* We use a generic name to retrieve PK.AUT.IFD-SPK. */
+ if (!strcmp (keyid, "$IFDAUTHKEY") && app->app_local->nks_version >= 3)
+ ;
+ else /* Return the error code expected by cmd_readkey. */
+ return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+
+ /* Access the KEYD file which is always in the master directory. */
+ err = iso7816_select_path (app->slot, path, DIM (path), NULL, NULL);
+ if (err)
+ return err;
+ /* Due to the above select we need to re-select our application. */
+ app->app_local->need_app_select = 1;
+ /* Get the two records. */
+ err = iso7816_read_record (app->slot, 5, 1, 0, &buffer[0], &buflen[0]);
+ if (err)
+ return err;
+ if (all_zero_p (buffer[0], buflen[0]))
+ {
+ xfree (buffer[0]);
+ return gpg_error (GPG_ERR_NOT_FOUND);
+ }
+ err = iso7816_read_record (app->slot, 6, 1, 0, &buffer[1], &buflen[1]);
+ if (err)
+ {
+ xfree (buffer[0]);
+ return err;
+ }
+
+ if (pk && pklen)
+ {
+ *pk = make_canon_sexp_from_rsa_pk (buffer[0], buflen[0],
+ buffer[1], buflen[1],
+ pklen);
+ if (!*pk)
+ err = gpg_error_from_syserror ();
+ }
+
+ xfree (buffer[0]);
+ xfree (buffer[1]);
+ return err;
+}
+
+
static gpg_error_t
basic_pin_checks (const char *pinvalue, int minlen, int maxlen)
{
@@ -673,7 +749,6 @@ verify_pin (app_t app, int pwid, const char *desc,
}
-
/* Create the signature and return the allocated result in OUTDATA.
If a PIN is required the PINCB will be used to ask for the PIN;
that callback should return the PIN in an allocated buffer and
@@ -723,6 +798,12 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
if (rc)
return rc;
+ if (is_sigg && app->app_local->sigg_is_msig)
+ {
+ log_info ("mass signature cards are not allowed\n");
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+ }
+
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
|| !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
|| keyidstr[4])
@@ -1147,8 +1228,9 @@ switch_application (app_t app, int enable_sigg)
{
gpg_error_t err;
- if ((app->app_local->sigg_active && enable_sigg)
- || (!app->app_local->sigg_active && !enable_sigg) )
+ if (((app->app_local->sigg_active && enable_sigg)
+ || (!app->app_local->sigg_active && !enable_sigg))
+ && !app->app_local->need_app_select)
return 0; /* Already switched. */
log_info ("app-nks: switching to %s\n", enable_sigg? "SigG":"NKS");
@@ -1156,9 +1238,40 @@ switch_application (app_t app, int enable_sigg)
err = iso7816_select_application (app->slot, aid_sigg, sizeof aid_sigg, 0);
else
err = iso7816_select_application (app->slot, aid_nks, sizeof aid_nks, 0);
+
+ if (!err && enable_sigg && app->app_local->nks_version >= 3
+ && !app->app_local->sigg_msig_checked)
+ {
+ /* Check whether this card is a mass signature card. */
+ unsigned char *buffer;
+ size_t buflen;
+ const unsigned char *tmpl;
+ size_t tmpllen;
+
+ app->app_local->sigg_msig_checked = 1;
+ app->app_local->sigg_is_msig = 1;
+ err = iso7816_select_file (app->slot, 0x5349, 0, NULL, NULL);
+ if (!err)
+ err = iso7816_read_record (app->slot, 1, 1, 0, &buffer, &buflen);
+ if (!err)
+ {
+ tmpl = find_tlv (buffer, buflen, 0x7a, &tmpllen);
+ if (tmpl && tmpllen == 12
+ && !memcmp (tmpl,
+ "\x93\x02\x00\x01\xA4\x06\x83\x01\x81\x83\x01\x83",
+ 12))
+ app->app_local->sigg_is_msig = 0;
+ xfree (buffer);
+ }
+ if (app->app_local->sigg_is_msig)
+ log_info ("This is a mass signature card\n");
+ }
if (!err)
- app->app_local->sigg_active = enable_sigg;
+ {
+ app->app_local->need_app_select = 0;
+ app->app_local->sigg_active = enable_sigg;
+ }
else
log_error ("app-nks: error switching to %s: %s\n",
enable_sigg? "SigG":"NKS", gpg_strerror (err));
@@ -1193,8 +1306,10 @@ app_select_nks (app_t app)
app->fnc.deinit = do_deinit;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
+ app->fnc.readkey = do_readkey;
app->fnc.getattr = do_getattr;
app->fnc.setattr = NULL;
+ app->fnc.writekey = NULL;
app->fnc.genkey = NULL;
app->fnc.sign = do_sign;
app->fnc.auth = NULL;