Hi list,

This is an attempt to persuade you to add functionality to opensc.
I have already made a patch that implements what is needed. This file is 
attached.

The patch make it possible to sign with keys on CardOS cards that was generated 
to use only the decryption card command.
This is because you can not generate keys on CardOS that accepts both the sign 
and decryption commands.

Sometimes you want keys that is capable of both signing and decryption.
Even when a key only should be used for signing it could be preferable to use 
the decryption command. This is when you use a padding where the MSB in
the RSA input differs 0 in the input (of modulus length) to the RSA algorithm.

All CardOS keys created by PrimeCard (see 
http://primekey.se/primekey/en/Products/PrimeCard.html) are keys where only the 
decrypt card command could
be used. But some of these keys are intended only for signing.

The patch is only tested with cards issued by PrimeCard. https authentication 
works fine with firefox using the opensc p11.
So you have to test that I have not messed anything up regarding other card but 
I don't think it will be any problems with that.

I will be happy to send PrimeCard issued cards to those of you that will test 
and add this patch to opensc as well as to maintainers of the project.
Just give me the mailing addresses.

Best Regards
Lars
diff -Naur opensc-0.11.3/src/libopensc/card-cardos.c opensc-0.11.3-new/src/libopensc/card-cardos.c
--- opensc-0.11.3/src/libopensc/card-cardos.c	2007-07-09 10:17:32.000000000 +0200
+++ opensc-0.11.3-new/src/libopensc/card-cardos.c	2007-08-01 22:46:30.000000000 +0200
@@ -686,6 +686,12 @@
 	SC_FUNC_RETURN(card->ctx, 1, r);
 }
 
+/* 
+ * Saved when cardos_set_security_env is called. 
+ * To be used when signing if decryption command must be used.
+ * The object of the pointer is on the stack of pkcs15-sec.c:sc_pkcs15_compute_signature
+ */
+static sc_security_env_t *pEnvSaved;
 /*
  * Set the security context
  * Things get a little messy here. It seems you cannot do any
@@ -704,7 +710,7 @@
 	sc_apdu_t apdu;
 	u8	data[3];
 	int	key_id, r;
-
+	pEnvSaved = env;
 	assert(card != NULL && env != NULL);
 
 	if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)
@@ -774,6 +780,35 @@
 		SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
 }
 
+/* Internal function using the decryption command of the card to do the RSA operation in a signing. Used when the signing command on the card does not work for a key. */
+static int
+do_decryption(sc_card_t *card, const u8 *data, size_t datalen,
+             u8 *out, size_t outlen)
+{
+    int r;
+    sc_apdu_t apdu;
+
+    /* INS: 0x2A  PERFORM SECURITY OPERATION
+     * P1:  0x80  Resp: Decryption
+     * P2:  0x86  Cmd: Input for Decrytption */
+    sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
+    apdu.resp    = out;
+    apdu.le      = outlen;
+    apdu.resplen = outlen;
+
+    apdu.data    = data-1;	/* a first extra byte must be appended when the decryption command is used for the RSA operation */
+    apdu.lc      = datalen+1;	/* this byte is allocated by pkcs15-sec.c:sc_pkcs15_compute_signature */
+    apdu.datalen = datalen+1;
+    apdu.sensitive = 1;
+    r = sc_transmit_apdu(card, &apdu);
+    SC_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
+        SC_FUNC_RETURN(card->ctx, 4, apdu.resplen);
+    else
+        SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
+}
+
 static int
 cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen,
 			 u8 *out, size_t outlen)
@@ -831,7 +866,18 @@
 	r = sc_pkcs1_strip_digest_info_prefix(NULL,buf,tmp_len,buf,&buf_len);
 	if (r != SC_SUCCESS)
 		SC_FUNC_RETURN(ctx, 4, r);
-	return do_compute_signature(card, buf, buf_len, out, outlen);
+	sc_ctx_suppress_errors_on(ctx);
+	r = do_compute_signature(card, buf, buf_len, out, outlen);
+	sc_ctx_suppress_errors_off(ctx);
+	if (r >= SC_SUCCESS)    
+		SC_FUNC_RETURN(ctx, 4, r);
+	/* maybe it is only possible to use the decryption command of the card for this key.*/
+	/* pEnvSaved is set in the call to cardos_set_security_env */
+	pEnvSaved->operation = SC_SEC_OPERATION_DECIPHER;
+	r = sc_set_security_env(card, pEnvSaved, 0);
+	if (r != SC_SUCCESS)    
+		SC_FUNC_RETURN(ctx, 4, r);
+	return do_decryption(card, data, datalen, out, outlen);
 }
 
 static int
diff -Naur opensc-0.11.3/src/libopensc/pkcs15-sec.c opensc-0.11.3-new/src/libopensc/pkcs15-sec.c
--- opensc-0.11.3/src/libopensc/pkcs15-sec.c	2007-04-20 09:12:54.000000000 +0200
+++ opensc-0.11.3-new/src/libopensc/pkcs15-sec.c	2007-08-01 21:46:19.000000000 +0200
@@ -143,7 +143,7 @@
 	sc_context_t *ctx = p15card->card->ctx;
 	sc_algorithm_info_t *alg_info;
 	const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
-	u8 buf[512], *tmp;
+	u8 buf[513], *tmp;
 	size_t modlen = prkey->modulus_length / 8;
 	unsigned long pad_flags = 0, sec_flags = 0;
 
@@ -167,10 +167,14 @@
 	senv.algorithm = SC_ALGORITHM_RSA;
 
 	/* Probably never happens, but better make sure */
-	if (inlen > sizeof(buf) || outlen < modlen)
+	if (inlen+1 > sizeof(buf) || outlen < modlen)
 		return SC_ERROR_BUFFER_TOO_SMALL;
-	memcpy(buf, in, inlen);
-	tmp = buf;
+	memcpy(buf+1, in, inlen);
+	/* First byte buf[0] to be used when the decryption command of the card has to be used for the RSA operation in the signing. */
+	/* Only used when the signing command of the card can't be used on a key. When signing command is used for RSA operation buf[0] is not used.*/
+	/* All calls to the signing implementation function are done with the data input pointer pointing to buf[1] */
+	tmp = buf+1;
+	*buf = 0;
 
 	/* flags: the requested algo
 	 * algo_info->flags: what is supported by the card 
@@ -181,7 +185,7 @@
 	if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
 	    !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) {
 		unsigned int algo;
-		size_t tmplen = sizeof(buf);
+		size_t tmplen = sizeof(buf)-1;
 		r = sc_pkcs1_strip_digest_info_prefix(&algo, tmp, inlen, tmp, &tmplen);
 		if (r != SC_SUCCESS || algo == SC_ALGORITHM_RSA_HASH_NONE) {
 			sc_mem_clear(buf, sizeof(buf));
@@ -201,14 +205,14 @@
 
 	/* add the padding bytes (if necessary) */
 	if (pad_flags != 0) {
-		size_t tmplen = sizeof(buf);
+		size_t tmplen = sizeof(buf)-1;
 		r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen);
 		SC_TEST_RET(ctx, r, "Unable to add padding");
 		inlen = tmplen;
 	} else if ((flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) {
 		/* Add zero-padding if input is shorter than the modulus */
 		if (inlen < modlen) {
-			if (modlen > sizeof(buf))
+			if (modlen+1 > sizeof(buf))
 				return SC_ERROR_BUFFER_TOO_SMALL;
 			memmove(tmp+modlen-inlen, tmp, inlen);
 			memset(tmp, 0, modlen-inlen);
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to