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