Hello Martin,

I'm sorry I didn't provide the patch yet. This was mainly because I
couldn't figure out why my device (Aladdin eToken PRO) behaved weirdly
as described. But it could be a driver-related problem. I attached the
code I have so far, maybe you could experiment with that and see
whether other devices behave correctly in the case I described.
If you'd like to apply this, just let me know, then I could also
integrate this with engine_pkcs11!

Best regards,
Martin Boßlet

2010/12/14 Martin Paljak <mar...@paljak.pri.ee>:
> Hello Martin,
>
> On Oct 26, 2010, at 11:31 PM, Martin Boßlet wrote:
>
>> I implemented computation of the hash on-device, and it works fine except 
>> for one odd problem:
>
> What happened to your implementation? Is it available somewhere? Do you have 
> a patch?
>
> It feels an important and interesting development. Unfortunately I'm not sure 
> if I have hardware that can do the last round hashing on the card (need to 
> check though...)
>
>
>
>>
>> I am using an Aladdin eToken for performing tests, and I call C_SignInit, 
>> C_SignUpdate and finally C_SignFinal on the PKCS#11 level using mechanism 
>> CKM_SHA1_RSA_PKCS for SHA-1 (similar for SHA-2 family). This works perfectly 
>> fine unless the byte array I pass to C_SignUpdate is less than or equal to 
>> the block size of the underlying hash algorithm, in the case of SHA-1, 64 
>> bytes. Any input longer than 64 bytes will be accepted, but for smaller 
>> input buffers I receive an error from my eToken.
>> I don't get this behaviour, because the token should be perfectly capable of 
>> padding a message shorter than 64 bytes correctly and then compute the hash 
>> value for this padded block, as it does it anyway for the final block of any 
>> message larger than 64 bytes.
>>
>> Has anyone encountered this before (probably with different hardware)? Even 
>> better, can anyone explain this weird behavior?
>>
>> Regards,
>> Martin
>>
>> 2010/10/20 Martin Boßlet <martin.boss...@googlemail.com>
>> I looked into the SHA-1specification and into PKCS#11 to see how I could 
>> perform the last round of the hash on-device and came up with the following 
>> approach:
>> If e.g. the last block of the message digest calculation should be computed 
>> on-device and the previous blocks in software, then I would have to transfer 
>> the result of my last computation in software as the initial value of the 
>> state variables on the card. There seems to be no way to do this with 
>> PKCS#11. But then I thought about this and I figured that this optimization 
>> will actually be done by the PKCS#11 driver when using mechanism 
>> CKM_SHA1_RSA_PKCS, right?
>> Therefore I could use CKM_SHA1_RSA_PKCS directly and the driver would do the 
>> trick? Did I understand this correctly?
>>
>> Regards,
>> Martin
>>
>> 2010/10/19 Martin Boßlet <martin.boss...@googlemail.com>
>>
>> As mentioned, computing the last round of the hash on the device and
>> the previous rounds in software would be the perfect thing to have.
>> Is it ok if I try to implement this for libp11 and submit the solution
>> for review? If the solution is accepted I could then move on to
>> integrate this feature into enginePkcs11!
>>
>
> --
> @MartinPaljak.net
> +3725156495
>
>
Index: src/libp11.exports
===================================================================
--- src/libp11.exports	(revision 196)
+++ src/libp11.exports	(working copy)
@@ -28,6 +28,9 @@
 PKCS11_store_public_key
 PKCS11_store_certificate
 PKCS11_sign
+PKCS11_sign_init
+PKCS11_sign_update
+PKCS11_sign_final
 PKCS11_private_encrypt
 PKCS11_private_decrypt
 PKCS11_verify
Index: src/p11_ops.c
===================================================================
--- src/p11_ops.c	(revision 196)
+++ src/p11_ops.c	(working copy)
@@ -24,6 +24,8 @@
 #include <string.h>
 #include "libp11-int.h"
 
+static CK_MECHANISM_TYPE pkcs11_type_for_nid(int nid);
+
 int
 PKCS11_sign(int type, const unsigned char *m, unsigned int m_len,
 		unsigned char *sigret, unsigned int *siglen, const PKCS11_KEY * key)
@@ -32,7 +34,7 @@
 	unsigned char *encoded = NULL;
 	int sigsize;
 
-	if (key == NULL)
+        if (key == NULL)
 		return 0;
 
 	sigsize = PKCS11_get_key_size(key);
@@ -139,6 +141,104 @@
 }
 
 int
+PKCS11_sign_init(int type, const PKCS11_KEY *key)
+{
+    PKCS11_KEY_private *priv;
+    PKCS11_SLOT *slot;
+    PKCS11_CTX *ctx;
+    CK_SESSION_HANDLE session;
+    CK_MECHANISM mechanism;
+    int rv;
+
+    if (key == NULL)
+        return -1;
+    ctx = KEY2CTX(key);
+    priv = PRIVKEY(key);
+    slot = TOKEN2SLOT(priv->parent);
+    session = PRIVSLOT(slot)->session;
+
+    memset(&mechanism, 0, sizeof(mechanism));
+    mechanism.mechanism = pkcs11_type_for_nid(type);
+    if (mechanism.mechanism == 0) {
+        PKCS11err(PKCS11_F_PKCS11_RSA_SIGN_INIT, PKCS11_NOT_SUPPORTED);
+        return -1;
+    }
+
+    rv = CRYPTOKI_call(ctx,
+                       C_SignInit(session, &mechanism, priv->object));
+
+    if (rv) {
+        PKCS11err(PKCS11_F_PKCS11_RSA_SIGN, pkcs11_map_err(rv));
+        return -1;
+    }
+
+    return CKR_OK;
+}
+
+int
+PKCS11_sign_update(const unsigned char *m, unsigned int mlen,
+        const PKCS11_KEY *key)
+{
+    PKCS11_KEY_private *priv;
+    PKCS11_SLOT *slot;
+    PKCS11_CTX *ctx;
+    CK_SESSION_HANDLE session;
+    int rv;
+
+    if (key == NULL || m == NULL)
+        return -1;
+
+    ctx = KEY2CTX(key);
+    priv = PRIVKEY(key);
+    slot = TOKEN2SLOT(priv->parent);
+    session = PRIVSLOT(slot)->session;
+
+    rv = CRYPTOKI_call(ctx,
+                       C_SignUpdate(session, (CK_BYTE *)m, mlen));
+    if (rv) {
+        PKCS11err(PKCS11_F_PKCS11_RSA_SIGN_UPDATE, pkcs11_map_err(rv));
+        return -1;
+    }
+
+    return CKR_OK;
+}
+
+int
+PKCS11_sign_final(unsigned char *sigret, unsigned int *siglen,
+        const PKCS11_KEY *key)
+{
+    PKCS11_KEY_private *priv;
+    PKCS11_SLOT *slot;
+    PKCS11_CTX *ctx;
+    CK_SESSION_HANDLE session;
+    int rv;
+    CK_ULONG ck_sigsize;
+
+    if (key == NULL)
+        return -1;
+
+    ctx = KEY2CTX(key);
+    priv = PRIVKEY(key);
+    slot = TOKEN2SLOT(priv->parent);
+    session = PRIVSLOT(slot)->session;
+    *siglen = PKCS11_get_key_size(key);
+
+    rv = CRYPTOKI_call(ctx,
+                       C_SignFinal(session, sigret, &ck_sigsize));
+    if (rv) {
+        PKCS11err(PKCS11_F_PKCS11_RSA_SIGN_FINAL, pkcs11_map_err(rv));
+        return -1;
+    }
+
+    if ((*siglen) != ck_sigsize) {
+        *siglen = 0;
+        return -1;
+    }
+
+    return CKR_OK;
+}
+
+int
 PKCS11_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
 		   PKCS11_KEY * key, int padding)
 {
@@ -181,7 +281,7 @@
 
 int
 PKCS11_verify(int type, const unsigned char *m, unsigned int m_len,
-		  unsigned char *signature, unsigned int siglen, PKCS11_KEY * key)
+		  unsigned char *signature, unsigned int siglen, PKCS11_KEY *key)
 {
 
 	/* PKCS11 calls go here */
@@ -189,3 +289,20 @@
 	return -1;
 }
 
+static CK_MECHANISM_TYPE pkcs11_type_for_nid(int nid)
+{
+    switch (nid) {
+        case NID_md5WithRSA:
+        case NID_md5WithRSAEncryption:
+            return CKM_MD5_RSA_PKCS;
+        case NID_sha1WithRSA:
+        case NID_sha1WithRSAEncryption:
+            return CKM_SHA1_RSA_PKCS;
+        case NID_sha256WithRSAEncryption:
+            return CKM_SHA256_RSA_PKCS;
+        case NID_sha512WithRSAEncryption:
+            return CKM_SHA512_RSA_PKCS;
+        default:
+            return 0;
+    }
+}
Index: src/libp11.h
===================================================================
--- src/libp11.h	(revision 196)
+++ src/libp11.h	(working copy)
@@ -353,11 +353,86 @@
 		PKCS11_CERT **ret_cert);
 
 /* rsa private key operations */
+/**
+ * Signs data by computing the hash in software and then signing the result
+ * on-device.
+ *
+ * @param type      the nid representing the message digest algorithm to be
+ *                  used for computing the hash (e.g. NID_sha1)
+ * @param m         the message to be signed
+ * @param m_len     the length of the message to be signed
+ * @param sigret    contains the signature upon success
+ * @param siglen    contains the length of the signature upon success
+ * @param key       the key which the message is to be signed with
+ * @return          -1 in cases of a failure, 0 otherwise
+ */
 extern int PKCS11_sign(int type, const unsigned char *m, unsigned int m_len,
-	unsigned char *sigret, unsigned int *siglen, const PKCS11_KEY * key);
+	unsigned char *sigret, unsigned int *siglen, const PKCS11_KEY *key);
+/**
+ * Signs the bytes contained in from using the padding given (currently only
+ * RSA_PKCS1_PADDING supported). Please note that the message length plus the
+ * length of the padding (11 for PKCS#1) must not exceed the key length. No
+ * message digest is computed before signing, the data is only padded and signed
+ * afterwards.
+ *
+ * @param flen      the length of the message to be signed
+ * @param from      the data to be signed
+ * @param to        contains the resulting signature on success
+ * @param rsa       the key to be used for the signature
+ * @param padding   the padding to be used for the signature (currently only
+ *                  RSA_PKCS1_PADDING is supported)
+ * @return          -1 in cases of failure, 0 otherwise
+ */
 extern int PKCS11_private_encrypt(int flen, const unsigned char *from,
-	unsigned char *to, const PKCS11_KEY * rsa, int padding);
+	unsigned char *to, const PKCS11_KEY *rsa, int padding);
+
 /**
+ * PKCS11_sign_init, PKCS11_sign_update and PKCS11_sign_final are needed if
+ * a signature is to be produced by computing the final round of the hash
+ * on-device in addition to just computing the signature of an already-computed
+ * hash on the device.
+ * Call this initially for setting up the device with the signature algorithm
+ * of your choice.
+ * @param type      the signature algorithm (i.e. message digest + signature) to
+ *                  be used for the signature (e.g. NID_sha1WithRSA)
+ * @param key       the key to be used for the signature
+ * @return          -1 if an error occurred, 0 otherwise
+ */
+extern int PKCS11_sign_init(int type, const PKCS11_KEY *key);
+/**
+ * PKCS11_sign_init, PKCS11_sign_update and PKCS11_sign_final are needed if
+ * a signature is to be produced by computing the final round of the hash
+ * on-device in addition to just computing the signature of an already-computed
+ * hash on the device.
+ * Call this successively to pass chunks of the message to be signed to the
+ * device until the entire message has been sent.
+ *
+ * @param m     a part (or the entire) of the message to be signed
+ * @param mlen  the length of m, that is of the current chunk sent to the device
+ * @param key   the key to be used for the signature
+ * @return      -1 in failure case, 0 otherwise
+ */
+extern int PKCS11_sign_update(const unsigned char *m, unsigned int mlen,
+        const PKCS11_KEY *key);
+/**
+ * PKCS11_sign_init, PKCS11_sign_update and PKCS11_sign_final are needed if
+ * a signature is to be produced by computing the final round of the hash
+ * on-device in addition to just computing the signature of an already-computed
+ * hash on the device.
+ * Call this once the entire message to be signed has been sent to the device.
+ * This triggers that hash computation will be finished, the padding (currently
+ * only PKCS#1 padding supported) will be applied and finally the padded message
+ * digest will be signed.
+ *
+ * @param sigret    contains the signature if the operation was successful
+ * @param siglen    contains the length of the signature is successful
+ * @param key       the key to be used for the signature
+ * @return          -1 if errors occurred, 0 otherwise
+ */
+extern int PKCS11_sign_final(unsigned char *sigret, unsigned int *siglen,
+        const PKCS11_KEY *key);
+
+/**
  * Decrypts data using the private key
  * 
  * @param  flen     length of the encrypted data
@@ -368,9 +443,9 @@
  * @return the length of the decrypted data or 0 if an error occurred
  */
 extern int PKCS11_private_decrypt(int flen, const unsigned char *from,
-	unsigned char *to, PKCS11_KEY * key, int padding);
+	unsigned char *to, PKCS11_KEY *key, int padding);
 extern int PKCS11_verify(int type, const unsigned char *m, unsigned int m_len,
-	unsigned char *signature, unsigned int siglen, PKCS11_KEY * key);
+	unsigned char *signature, unsigned int siglen, PKCS11_KEY *key);
 
 /* access random number generator */
 extern int PKCS11_seed_random(PKCS11_SLOT *, const unsigned char *s, unsigned int s_len);
@@ -412,6 +487,9 @@
 #define PKCS11_F_PKCS11_SEED_RANDOM		20
 #define PKCS11_F_PKCS11_GENERATE_RANDOM		21
 #define PKCS11_F_PKCS11_CHANGE_PIN		22
+#define PKCS11_F_PKCS11_RSA_SIGN_INIT           23
+#define PKCS11_F_PKCS11_RSA_SIGN_UPDATE         24
+#define PKCS11_F_PKCS11_RSA_SIGN_FINAL          25
 #define PKCS11_F_PKCS11_GETATTR			40
 
 #define PKCS11_ERR_BASE				1024
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to