summaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2020-04-01 14:07:56 +0200
committerWerner Koch <wk@gnupg.org>2020-04-01 14:07:56 +0200
commitca4391399c690a45270cca30f03ac564c394c1f6 (patch)
treec6592e7b2cf7d423910d7ffe9e04b76457d98fd0 /scd
parentscd:p15: Factor PIN verification out to a new function. (diff)
downloadgnupg2-ca4391399c690a45270cca30f03ac564c394c1f6.tar.xz
gnupg2-ca4391399c690a45270cca30f03ac564c394c1f6.zip
scd:p15: Support decryption with CardOS 5 cards.
* scd/app-p15.c (do_decipher): New. -- tested using the D-TRUSt card and a SCR3310 reader. The Kobil KAAN Advanced, I used for the signing tests could not be used because it supports only Short APDU Level exchange. Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'scd')
-rw-r--r--scd/app-p15.c102
1 files changed, 100 insertions, 2 deletions
diff --git a/scd/app-p15.c b/scd/app-p15.c
index d981ef8d1..fc17e66ff 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -3501,7 +3501,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
return err;
}
- /* Manage security environment needs to be weaked for certain cards. */
+ /* Manage security environment needs to be tweaked for certain cards. */
if (mse_done)
err = 0;
else if (app->app_local->card_type == CARD_TYPE_TCOS)
@@ -3599,6 +3599,104 @@ do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
}
+/* Handler for the PKDECRYPT command. Decrypt the data in INDATA and
+ * return the allocated result in OUTDATA. If a PIN is required the
+ * PINCB will be used to ask for the PIN; it should return the PIN in
+ * an allocated buffer and put it into PIN. */
+static gpg_error_t
+do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
+ gpg_error_t (*pincb)(void*, const char *, char **),
+ void *pincb_arg,
+ const void *indata, size_t indatalen,
+ unsigned char **outdata, size_t *outdatalen,
+ unsigned int *r_info)
+{
+ gpg_error_t err;
+ prkdf_object_t prkdf; /* The private key object. */
+ aodf_object_t aodf; /* The associated authentication object. */
+ int exmode, le_value, padind;
+
+ (void)ctrl;
+ (void)r_info;
+
+ if (!keyidstr || !*keyidstr)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (!indatalen || !indata || !outdatalen || !outdata)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
+ if (err)
+ return err;
+ if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap))
+ {
+ log_error ("p15: key %s may not be used for decruption\n", keyidstr);
+ return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ }
+
+ /* Find the authentication object to this private key object. */
+ if (!prkdf->authid)
+ {
+ log_error ("p15: no authentication object defined for %s\n", keyidstr);
+ /* fixme: we might want to go ahead and do without PIN
+ verification. */
+ return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ }
+ for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next)
+ if (aodf->objidlen == prkdf->authidlen
+ && !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen))
+ break;
+ if (!aodf)
+ {
+ log_error ("p15: authentication object for %s missing\n", keyidstr);
+ return gpg_error (GPG_ERR_INV_CARD);
+ }
+
+
+ /* Verify the PIN. */
+ err = prepare_verify_pin (app, keyidstr, prkdf, aodf);
+ if (!err)
+ err = verify_pin (app, pincb, pincb_arg, prkdf, aodf);
+ if (err)
+ return err;
+
+
+ /* The next is guess work for CardOS. */
+ if (prkdf->key_reference_valid)
+ {
+ unsigned char mse[6];
+
+ mse[0] = 0x80; /* Algorithm reference. */
+ mse[1] = 1;
+ mse[2] = 0x0a; /* RSA, no padding. */
+ mse[3] = 0x84;
+ mse[4] = 1;
+ mse[5] = prkdf->key_reference;
+ err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
+ mse, sizeof mse);
+ if (err)
+ {
+ log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
+ return err;
+ }
+ }
+
+
+ exmode = le_value = 0;
+ padind = 0;
+ if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048)
+ {
+ exmode = 1; /* Extended length w/o a limit. */
+ le_value = prkdf->keynbits / 8;
+ }
+
+ err = iso7816_decipher (app_get_slot (app), exmode,
+ indata, indatalen,
+ le_value, padind,
+ outdata, outdatalen);
+ return err;
+}
+
+
/* Process the various keygrip based info requests. */
static gpg_error_t
do_with_keygrip (app_t app, ctrl_t ctrl, int action,
@@ -3882,7 +3980,7 @@ app_select_p15 (app_t app)
app->fnc.genkey = NULL;
app->fnc.sign = do_sign;
app->fnc.auth = do_auth;
- app->fnc.decipher = NULL;
+ app->fnc.decipher = do_decipher;
app->fnc.change_pin = NULL;
app->fnc.check_pin = NULL;
app->fnc.with_keygrip = do_with_keygrip;