-
Notifications
You must be signed in to change notification settings - Fork 712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GemSafe Card: Can't sign a SHA256 hash #508
Comments
Looks like some bugs. This driver has bee around a long time, and looks like it needs some work, to use with larger hashes. Can you try removing the check for 36? There may also be issues with 2048 bit keys as it appears some cards using this driver do not support 2048 RSA keys. On 8/2/2015 6:42 AM, velter wrote:
Douglas E. Engert [email protected] |
Thanks for looking at this. Unfortunately I have no build environment for opensc at hand (I'm calling opensc from a delphi app on windows x64). Will try to setup one. The key on my card is 2048bit, but as I understand it the problem will only arise when trying for example to generate a 2048bit keypair on an old card not supporting 2048bits. |
What is your expected result/behavior of OpenSC in this case? |
It was just a comment on dengert reply. Currently I only use my key for signing (my concern is that signing more than 36 bytes raise an error with this key). I have not even tried to generate a keypair. |
Maybe I'm missing some content. Is there something that does not work for you? Or did you simply want to have feedback about that single check (though it has never been a problem for your card)? |
Sorry for not being clear about this. My only problem right now is about the check in card-gemsafeV1.c which put a hard limit of 36 bytes to the size of the data being signed. This check prevent for example to sign a SHA256 hash. My card can handle this as it works with the gemalto provided pkcs11 lib. |
I finally got an opensc build environment up. I tried to just remove the check for datelen>36, but this does not work. Here are the relevant log. Let me know if I can do something else to help resolve this.
|
"not allowed" sounds like you forgot to verify your PIN first. does the same test case work for something else than SHA256? By the way, the check for |
I don't forgot. I also tried with SHA1 which does work. Here a the exact commands I used (just obscured the pin) : Regarding the asn encoding you are right, but if I'm not wrong, the limit for a one byte length is 127. With sha256, data_len is 51 so the asn1 length is correct in this case. |
Could you use the pkcs11-tool together with gemalto's pkcs11 lib? Make sure to log the APDUs via pcscd. This might reveal the relevant differences to OpenSC's implementation of this card. |
I only have access to the gemalto pkcs11 lib under windows. I confirm that pkcs11-tool + gclib.dll works with both SHA1 and SHA256. But I don't know how to capture APDUs on windows. |
A quick view at google results in
(I haven't tried any of the above) |
From previous note you card appears to be SC_CARD_TYPE_GEMSAFEV1_SEEID For SHA1 the header is 15 and the hash is 20 so the data_len is 35. The data sent in your modified APDU looks correct for a SHA256 header and See the tables in padding.c as about hash headers. The issue may be the card may have a built in test to only accept sha1 hashes if you have the card do the padding. If other drivers can sign a SHA256 hash, they could be doing a number of things: The ADPU command is different from what is in card-gemsafeV1.c to send a different size hash. The card can do RAW RSA and so the padding could be done in software rather then on the card. They use a trick where a decipher APDU of a padded hash returns the signature. So a APDU trace of a working sha256 signature would show what is getting sent to the card. On windows one way to get a APDU trace is to do a USB trace. There is a lot of extra data, but you Google for: Windows USB trace On 9/2/2015 6:19 AM, velter wrote:
Douglas E. Engert [email protected] |
Wireshark has some USB tracing too, even on Windows: |
I gave apdu inspect a try. Here is the log for a successful sha256 sign with gclib.dll The relevant apdu seem to be
data_len = $20 => 32 => 256bits The same for sha1 is
data_len = $14 => 20 => 160bits so it definitly seem to be a padding problem
|
Interesting, it is sending just the hash, and not the header and the hash as required by PKCS#1 padding. This could result in what looks like a valid signature, but will not verify with software that is expecting If the signature verifies with the public key, The card must be smart enough to add the header, based on the length of the hash: OpenSC debug output starting after the PIN is verified till after the sc_pkcs15_compute_signature fails In the glib trace the sec_env is sent: Do you have a OpenSC debug output of a SHA1 signature starting after the PIN is verified till after the sc_pkcs15_compute_signature On 9/2/2015 3:00 PM, velter wrote:
Douglas E. Engert [email protected] |
Yes, the difference should be in the command MSE:Set DST, Decipherment: Cryptographic mechanism reference ( Could you check which command precedes the signature operation in OpenSC (i.e. what does the MSE:Set DST look like)? OpenSC's
|
I apologize for jumping up on this thread without contributing to it. My question is rather naive, and related to the example signature you’re debugging for GemSafe. My card is not GemSafe but NEO. And the following seems to work fine (02 identifies the signing key): pkcs11-tool -s -m SHA256-RSA-PKCS --pin XXXXXX -d 02 -i mytest -o sha256.out The question is: how can I verify this signature, preferably using pkcs11-tool? Probably I should’ve been able to figure that out from the man page, but I couldn’t. :-( Thanks! On Sep 2, 2015, at 20:03 , Frank Morgner <[email protected]mailto:[email protected]> wrote: Yes, the difference should be in the command 00 22 41 b6 06 80 01 42 84 01 06 which means: MSE:Set DST, Decipherment: Cryptographic mechanism reference (0x80) = 0x41, Reference of a private key (0x84) = 0x06 Could you check which command precedes the signature operation in OpenSC (i.e. what does the MSE:Set DST look like)? OpenSC's gemsafe_flags2algref only uses 0x02 or 0x12 for the Cryptographic mechanism reference, but never 0x41. It seems that 0x41 should be used when sc_security_env->algorithm_flags is SC_ALGORITHM_HASH_NONE. However, this case (SC_ALGORITHM_HASH_NONE) is missing in gemsafe_flags2algref. If so, a workaround should be:
— Uri Blumenthal |
One way is to use openssl. Something like this: $# generate signature using card read pubkey from card:$ pkcs11-tool -r -y pubkey -d 02 -o pubkey.02 use openssl to verify signatire using pubkey$ openssl dgst -sha256 -verify pubkey.02 -keyform DER -signature signature < mytest openssl dgst -verify -signature sha256.out < mytest On 9/3/2015 12:57 AM, Mouse wrote:
Douglas E. Engert [email protected] |
Thank you!! Perfect! It worked exactly as you said. E.g.: $ pkcs11-tool -s -m SHA384-RSA-PKCS -d 02 -i mytest -o sha384.out Is there an analog for file encryption (probably openssl?) and decryption (using PKCS11 on the card)? NEO supports the following mechanisms: $ pkcs11-tool -M Using slot 1 with a present token (0x1) Supported mechanisms: SHA-1, digest SHA256, digest SHA384, digest SHA512, digest MD5, digest RIPEMD160, digest ECDSA, keySize={256,384}, hw, sign, other flags=0x1800000 ECDH1-COFACTOR-DERIVE, keySize={256,384}, hw, derive, other flags=0x1800000 ECDH1-DERIVE, keySize={256,384}, hw, derive, other flags=0x1800000 RSA-X-509, keySize={1024,3072}, hw, decrypt, sign, verify RSA-PKCS, keySize={1024,3072}, hw, decrypt, sign, verify SHA1-RSA-PKCS, keySize={1024,3072}, sign, verify SHA256-RSA-PKCS, keySize={1024,3072}, sign, verify SHA384-RSA-PKCS, keySize={1024,3072}, sign, verify SHA512-RSA-PKCS, keySize={1024,3072}, sign, verify MD5-RSA-PKCS, keySize={1024,3072}, sign, verify RIPEMD160-RSA-PKCS, keySize={1024,3072}, sign, verify From that I figure that only RSA-based encryption/decryption is available? Or is there something that pkcs11-tool does not show me? Like the ability to to ECIES or otherwise encrypt/decrypt using EC keys? Thanks! From: Doug Engert [[email protected]] One way is to use openssl. Something like this: $# generate signature using card read pubkey from card:$ pkcs11-tool -r -y pubkey -d 02 -o pubkey.02 use openssl to verify signatire using pubkey$ openssl dgst -sha256 -verify pubkey.02 -keyform DER -signature signature < mytest openssl dgst -verify -signature sha256.out < mytest On 9/3/2015 12:57 AM, Mouse wrote:
— |
Looking at the debug output you sent, the problem may be in where this line is not executed for your card: card-gemsafe.c sets: The reason I say this is because you are trying to send 51 bytes, rather then just the SHA256 32 byte hash I believe I asked you earlier to send an opensc-debug output that includes the sc_pkcs15_compute_signature up to the failure The debug output you have sent start with gemsafe_compute_signature which is too late. On 9/2/2015 3:00 PM, velter wrote:
Douglas E. Engert [email protected] |
Sorry the delay. Here are the logs
|
Looking at it more closely it seems that sc_pkcs1_encode line 452 of pkcs15-sec.c should not be called. so replacing line 449 of pkcs15-sec.c with if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { Make the card compute the signature without error, but the computed signatures are INVALID for both sha1 AND sha256. There must be something else. I also hacked the source to have set_security_env send the same apdu than gclib, but this give an error agin (return 0x42 in gemsafe_flags2algref and setting key_ref[0] to 6). As this seem very tricky, I will probably stay with an SHA1 hash. |
What was the command used for this? It looks like the hash has been done, and 0x20 or 32 bytes are to be signed, See other comments below. On 9/6/2015 8:02 AM, velter wrote:
Line 431 is printing the debug wrong, using %li, should be %i as buffer_len is unsigned int.
Line 444 is also using "%li but should be %i looks like x20 or 32 bytes need to be signed.
If the hash was already done, it not clear why 202 is not just 02.
Based on the 51 later, it looks like padding.c:248 and 249: are called to put the hash header back on 19+32=51 card-gensafeV1.c indicates it sets SC_ALGORITHM_RSA_HASH_NONE Looks like the line 248 should either be or the flag 0x202 should have been set to 0x02 once the hash was computed. Need to see more of the beginning of the log...
Douglas E. Engert [email protected] |
I can send you the full log. But is there a way to send you an attachment ? this is pretty big. |
@velter you could use pastebin or gist... |
The more I look at this, the problem appears to come from the code to add software hashes and the way the code in ./framework-pkcs15.c such as: This causes problems with the flags when trying to do the PKCS on the card. Can you try doing something like: pkcs11-tool -s -m RSA-PKCS --pin XXXXXX This does the the hash externally, then signs it with the card. What it should show is the card |
I tried this. There is no error while creating the signature, but the signature does not verify with openssl dgst -sha256 -verify pubkey.pem -keyform pem -signature sha256.out mytest This behavior is the same as with the fix of line 449 in pkcs15-sec.c I also tried the same with sha1 which also result in a bogus signature |
A signature requires the hash header and the hash. Which is length 19 + 32 = 51 for sha256. Without the manual for your card, it is not clear if it can sign a SHA256 hash by doing the padding on the card. As @frankmorgner pointed out the gclib is using the fact that a decrypt operation passed a padded hash header + hash "MSE:Set DST, Decipherment: Cryptographic mechanism reference (0x80) = 0x41, Reference of a private key (0x84) = 0x06" OpenSC has a number of routines, that can add a hash header, remove a hash header and can also use decipher in place of an sign/encrypt operation, So if the gclib can do it, OpenSC could do it, but it will take some work and testing to get it to work. On 9/8/2015 3:18 AM, velter wrote:
Douglas E. Engert [email protected] |
A very naive question (+ my apologies). Are you sure your public key is in PEM format rather than in DER? On Sep 8, 2015, at 4:18 , velter <[email protected]mailto:[email protected]> wrote: I tried this. There is no error while creating the signature, but the signature does not verify with openssl dgst -sha256 -verify pubkey.pem -keyform pem -signature sha256.out mytest
This behavior is the same as with the fix of line 449 in pkcs15-sec.c I also tried the same with sha1 which also result in a bogus signature Logs : https://gist.github.com/9eb15d2bac37de2dfffb.git — Uri Blumenthal |
@dengert I didn't imagine that this problem will open such a can of worms :( @mouse07410 yes my pubkey is in PEM format. And I'm sure it's right because pkcs11-tool -s -m SHA1-RSA-PKCS --pin XXXXXX -d 1d228aeee53d5b320aaede6715592afa6491791a -i mytest -o sha1-2.out openssl dgst -sha1 -binary -out mytest1.dgst < mytest SHA256 result in the same failure. |
Yes a can of worms... What usually happens is someone with a card ends up writting a driver or making changes, as it is almost impossible to debug code like this without a card. |
I've gotten my hands on a GemSAFE V3 card, it's not a Swedish eID card but uses the same applet and exhibits the same problems when signing a SHA256 hash. Reverse engineering Gemalto's gclib, it turns out the only differences between opensc and gclib are:
(There are some further differences which I believe to be irrelevant: gclib sends the PIN before MSE, opensc sends it after Compute Digital Signature fails with 0x69 82 and retries PSO plus Compute Digital Signature. gclib reads the hash after sending it, opensc just ignores the 0x61 result. gclib sets Le to 0x00 in the Compute Digital Signature command and receives the whole 256 byte signature from the card, opensc sets Le to 0x80 and receives it in two 128 byte chunks.) Bottom line: The card seems to be smart enough to prepend the proper header to the hash before signing it and it seems to select the header based on the algorithm tag. This is gclib's mode of use. Alternatively, the hash is passed with header and the algorithm tag is always set to 0x02. The card will then not prepend a header and sign the data as is. This is opensc's mode of use. Unfortunately this doesn't work with SHA256 hashes, the card always rejects these with 0x69 85 in response to the PSO command. If we want to emulate gclib's behaviour, we need to adjust the return value of Now what? Can we extend |
I just looked at the APDUs sent by gclib once more and realized that it sends MD5 hashes with header but SHA1 and SHA256 hashes without header. This clears up the confusion why gclib uses algo tag 0x02 for MD5 and opensc uses that same tag for all algorithms: 0x02 seems to mean "no header prepended, sign as is". |
@dengert wondered above why I guess I could hack |
Interesting. So in gemsafe_flags2algref Also look at sc_pkcs15_compute_signature, sc_pkcs15_derive, and sc_pkcs15_decipher. There really needs to be more debug information logged from these routines, as they are complicated and hard to understand. Each card has a different path through the code, making it hard to test. The information you need may already be in the sc_security_env in the algorithm_flags or supported sc_supported_algo_info. More debug info would help. For some reason line 423 and 424 in pkcs15-sec.c don't look correct to me:
They deal with stripping the hash header, but flags may have other bit set. |
Interesting. So in gemsafe_flags2algref ret = (card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) ? 0x02 : 0x12; is really seting what hash is being used based on the card type to either free form or SHA1. It's a bit different. One has to differentiate between GemSAFE V1 and V2V3 cards. On GemSAFE V1 cards, the cryptographic mechanism reference to sign free form data is 0x12. On GemSAFE V2V3, it's 0x02. The Swedish eID card seems to be a GemSAFE V3, the Portuguese eID card likewise (judging only by the code.) I also have an older GemSAFE V1 card here and just verified that opensc uses cryptographic mechanism reference 0x12 with it and sends the hash with header. gclib behaves identically. Basically on GemSAFE V2V3, gclib behaves differently if a SHA1 and SHA256 hash is signed: It sends those hashes without header to the card and indicates the header to prepend via the cryptographic mechanism reference, which is 0x42 for SHA256 and 0x12 for SHA1. I think it's a good thing to stay with free form signing, this allows us to support e.g. RIPEMD160 which gclib doesn't support. We only need to special case SHA256. However unless I'm mistaken, opensc is not flexible enough to indicate in the flags that the header needs to be present on all but one hash algorithm. So I think I'll solve this by hacking |
A preliminary patch is now at l1k/OpenSC@d1e222b. Kludgy but works. |
For a less kludgy solution, we'd need to add new functions to card.c which allow specification of flags when finding algorithms. And likewise we'd need to extend |
After endless fiddling I've come up with a somewhat less kludgy solution which is at l1k/OpenSC@a3fdc53. @velter: Please test if this works for you, it does for me. @dengert, @frankmorgner: Please let me know if you would consider a pull request with this solution. This is the simplest solution I've found that doesn't need changes to opensc core. It involves registering a fake RSA algorithm, the commit message explains this in detail. An alternative solution would e.g. be to extend Running |
Thanks, @l1k, for the detailed and comprehensive problem description in your commit message. I had a similar problem in #419 where the quick solution also was to modify (and break) the upper layers. While your commit is much less intrusive and impressingly small to achieve such a complex operation I think it is not very good to maintain. I solved my problem with 643080b and I think this would also be the correct (tm) solution for yours: Make the key capabilities explicit instead of using
You may use |
And as bonus, you may even specify the algorithm reference accordingly. |
I forgot to say that you need to link the extracted private keys to
|
@l1k, I just did the test with my gemsafe card and your patch allow me to successfully sign SHA1 and SHA256 hashs. Thanks for your work. |
@frankmorgner: Thanks a lot for your feedback. The interpretation of the card flags in After starring at the code for a while I don't see how defining all supported algorithms in For EC algorithms, we already declare an |
@dengert: Regarding the comment you left on l1k/OpenSC@a3fdc53: Would a more general fix be to look at the cards algorithm list and have the list define different flags for the sha256? Well yes, we could solve this by adding multiple RSA algorithms to the list, with the same
Or do we need a seperate flag to indicate that the hash header should not be sent to the card?#define SC_ALGORITHM_RSA_NO_HASH_HEADER 0x20000000This would only be set for SHA256 for the GemSafe cards. It's the other way round, we'd need an additional PAD flag to indicate that the DigestInfo header needs to be prepended, but the PKCS11 padding is done on the card. We'd need to add that new flag to the algorithm definitions for SHA1, RIPEMD160 and MD5. That's because register_mechanism has comments like:4639 /* 4640 * Mechanism handling 4641 * FIXME: We should consult the card's algorithm list to 4642 * find out what operations it supports 4643 */ That comment was added by @okirch 13 years ago. What @frankmorgner wrote sounds a bit like he wants to solve this by having |
@dengert What is in the comment is already solved, in my opinion. Unfortunately nobody updated the docs... @l1k do the following:
An application (such as
(I hope, I got all the bits and flags correctly...) |
@l1k maybe this can get you started: frankmorgner@dcbaa3b |
adopting 4734721 in absence of a better solution |
@frankmorgner: Apologies, I've been swamped with kernel work plus the usual year-end stress. I'll see to it that I test your proposed solution over the holidays. Thank you! |
@frankmorgner: I finally got around to take a closer look at your suggested solution. First of all, by default the card is bound with Second, SHA256 signing is only supported by V2V3 cards but not by V1 cards. Since PKCS#15 emulation apparently no longer works with V2V3 cards, I'm afraid the suggested approach is not viable. Once again apologies for my tardiness and sorry that I couldn't report success for the suggested solution. The (somewhat hacky) patch you've merged is probably the simplest way to solve this given the existing limitations of core libopensc code. (I.e., inability to specify that the hash header needs to be prepended only to some hashes.) |
OK, no problem. Thanks for the feedback! |
I'm trying to use a GemSafe card (OpenTrust KSign) with opensc pkcs11 interface (windows x64). All is work well except that I can't sign a SHA256 hash. Pkcs11 return a general error.
After enabling logging, the error come from
2015-08-02 13:08:58.513 [opensc-pkcs11] card-gemsafeV1.c:430:gemsafe_compute_signature: called
2015-08-02 13:08:58.513 error: input data too long: 51 bytes
2015-08-02 13:08:58.513 [opensc-pkcs11] sec.c:58:sc_compute_signature: returning with: -1300 (Invalid arguments)
There seem to be a hard limit in the code to 36 bytes.
I know the card is able to process more data than this with the Gemalto provided pkcs11 lib.
Is this check really necessary ?
Card ATR : 3b:7d:96:00:00:80:31:80:65:b0:83:11:00:c8:83:00:90:00
The text was updated successfully, but these errors were encountered: