Open bitlogik opened 3 years ago
Dynamic calls to getInstances
have been removed in everydays' operations (sign, decipher).
There are no setters in the KeyPair
class, so it is mandatory to create new objects when needed, which occurs only when keys are changed (either imported or generated on board).
We have no problem with our (older) JCOP card. Could you check if you still encounter the repeated signature problem on you J3R110 with v1.17 version of the applet ?
I had tested it with NIST P-521 keys and J3H145 card. Smart card did >5000 signatures successfully and without visible degradation.
Reader ...........: ACS ACR 38U-CCID 00 00
Application ID ...: D276000124010304AFAF00FF00000000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00FF0000
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: nistp521 nistp521 nistp521
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 5073
KDF setting ......: off
Signature key ....: 3428 871A 731A 4C2C 7084 6B0F EA47 D36E 2C6B 949B
created ....: 2021-03-13 13:57:40
Encryption key....: 4127 CB21 4A1C 6584 E721 0BA2 24A9 A00E 4A92 3CD1
created ....: 2021-03-13 13:57:40
Authentication key: F1E9 2D39 4182 4866 288A EE75 DA6F 42C8 5C4F D9F2
created ....: 2021-03-13 13:57:40
General key info..:
pub nistp521/EA47D36E2C6B949B 2021-03-13 Smart card test
sec> nistp521/EA47D36E2C6B949B created: 2021-03-13 expires: never
card-no: AFAF 00FF0000
ssb> nistp521/DA6F42C85C4FD9F2 created: 2021-03-13 expires: never
card-no: AFAF 00FF0000
ssb> nistp521/24A9A00E4A923CD1 created: 2021-03-13 expires: never
card-no: AFAF 00FF0000
Is J3R110 a real product form NXP? Smartcardfocus doesn't carry them and all sellers I can find for the card are Chinese which is really strange considering that they don't carry cards other than J2A040 and J3D081, and all of those are normally uninitialized.
I'm asking because it may be a buggy knockoff like the Feitian JavaCOS A22 and ACS ACOSJ. Both of those have serious memory management issues (with A22 using an abnormally huge amount of transient memory on any crypto operations and ACOSJ (speculatively) corrupting the EEPROM all the way until bricking the card).
This is JCOP "4" 3.0.5 on NXP P71 SmartMX3. The bigger J3R320 version might be more common by the way. We'll test with other chip in this familly, one day if we take time about this topic. Still, we are using NXP NDA proprietary JC package on these card for some applets, and oberving the compatbility and also the chip seped, we can be sure there are real NXP P71. This product seems to have a poor memory management, poorer than previsous versions. Or maybe just a reduced overhead because the JCOP system takes more resources, and that exacerbates this issue. Recently on a product we design, all was static except the PIN where it was created at each card reset cycle, and we ended up to put the PIN in "static" also to avoid this kind of issue.
For the KeyPair what you can do is :
private ECPrivateKey keyPrivate;
private ECPublicKey keyPublic;
private KeyPair keypair;
and in the applet or class object instanciation : (adjust memory type accordingly, here this example is for ephemeral keys such a secure channel key).
this.keyPrivate = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_EC_FP_PRIVATE,JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT, (short)256, false);
this.keyPublic = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_EC_FP_PUBLIC, JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT, (short)256, false);
this.keypair = new KeyPair(this.keyPublic, this.keyPrivate);
Just as it is, but creating the object once. And during the generate methods, it only setup the key parameters. And clear the keys at reset.
But here for SmartPGP, the culprit is here, where a new signature object is created every time a signature is performed.
This should be done with that in applet class :
private Signature sig;
And as a pointer initialization.
self.sig = null;
@bitlogik you did not answer to my question in https://github.com/ANSSI-FR/SmartPGP/issues/29#issuecomment-782880025 : do you still have "batch" signatures issue on the J3R110 with version v1.17 of the applet ?
Sorry, we let this project aside since that time. We need to confirm. Because yes we just see there were some works relative to this issue, and I totally missed that. Not sure if the specific issue about signature was solved, maybe only a signature pointer during each signature is created and not a full object? The work about this issue can be pushed forward with RSA and EC keys set as "static" and using clearKey() and setXparam(), for the lifecycle management, with set parameters on the private/public counterpart objects of the keypair. We'll try to test if we have some time this week.
We tested the applet v1.17+ on J3R cards, and it fixed the signatures issue. No more hazardous memory leak for signatures. 👍
But, quite as expected, the key generation after a reset is affected by this issue.
After some a dozens of resets :
Sending 0x20 command with 8 bytes data
-> 00 20 00 83 08 31 32 33 34 35 36 37 38
Received 0 bytes data : SW 0x9000 - duration: 16.0 ms
Sending 0xE6 command with 0 bytes data
-> 00 E6 00 00 00
Received 0 bytes data : SW 0x9000 - duration: 10.8 ms
Sending 0x44 command with 0 bytes data
-> 00 44 00 00 00
Received 0 bytes data : SW 0x9000 - duration: 158.4 ms
PGP device reset
Sending 0x47 command with 2 bytes data
-> 00 47 81 00 02 B6 00
Received 0 bytes data : SW 0x6A88 - duration: 7.7 ms
Setup the new device
Sending 0x20 command with 8 bytes data
-> 00 20 00 83 08 31 32 33 34 35 36 37 38
Received 0 bytes data : SW 0x9000 - duration: 16.5 ms
Put data 132A8648CE3D030107 in 0x00C1
Sending 0xDA command with 9 bytes data
-> 00 DA 00 C1 09 13 2A 86 48 CE 3D 03 01 07
Received 0 bytes data : SW 0x9000 - duration: 23.6 ms
Sending 0x47 command with 2 bytes data
-> 00 47 80 00 02 B6 00
Received 0 bytes data : SW 0x6F00 - duration: 116.4 ms
Crash, game over.
SFYL !
Error: 0x6f00
And the card applet is bricked (requires new applet loading).
Tested on J3R110 and J3R200 (JCOP on NXP P71) with javacard-3.0.4 v1.21-3.0.4.
One last modification is required about the keys objects :
The good part is that keypair doesn't need to be used with initialized key, but only a key pair from KeyBuilder.buildKey, and can be instantiated once (right after the key pair instantiation, done once). And the setParams can be done on a key after a clearKey (or on a new key the first time).
Thank you for those tests.
There is no simple solution for the key generation/import. The user can change the key attributes (RSA key size, switch to EC, change EC curve, ...) and we cannot create static instances for each possible value.
We have created a branch named test-issue-29
where object deletion is requested if the card supports it. You can test if your card supports it with the TestApplet in the test_applet
directory from that branch and the test.py
script (you can comment out other tests).
If your card supports object deletion, could you try the SmartPGPApplet from that branch for repeated key import/generation ?
We tested the applet v1.17+ on J3R cards, and it fixed the signatures issue. No more hazardous memory leak for signatures. +1
But, quite as expected, the key generation after a reset is affected by this issue.
After some a dozens of resets :
Sending 0x20 command with 8 bytes data -> 00 20 00 83 08 31 32 33 34 35 36 37 38 Received 0 bytes data : SW 0x9000 - duration: 16.0 ms Sending 0xE6 command with 0 bytes data -> 00 E6 00 00 00 Received 0 bytes data : SW 0x9000 - duration: 10.8 ms Sending 0x44 command with 0 bytes data -> 00 44 00 00 00 Received 0 bytes data : SW 0x9000 - duration: 158.4 ms PGP device reset Sending 0x47 command with 2 bytes data -> 00 47 81 00 02 B6 00 Received 0 bytes data : SW 0x6A88 - duration: 7.7 ms Setup the new device Sending 0x20 command with 8 bytes data -> 00 20 00 83 08 31 32 33 34 35 36 37 38 Received 0 bytes data : SW 0x9000 - duration: 16.5 ms Put data 132A8648CE3D030107 in 0x00C1 Sending 0xDA command with 9 bytes data -> 00 DA 00 C1 09 13 2A 86 48 CE 3D 03 01 07 Received 0 bytes data : SW 0x9000 - duration: 23.6 ms Sending 0x47 command with 2 bytes data -> 00 47 80 00 02 B6 00 Received 0 bytes data : SW 0x6F00 - duration: 116.4 ms Crash, game over. SFYL ! Error: 0x6f00
And the card applet is bricked (requires new applet loading).
Tested on J3R110 and J3R200 (JCOP on NXP P71) with javacard-3.0.4 v1.21-3.0.4.
One last modification is required about the keys objects :
* define once in static part * instantiate in applet initialization/installation, or at object module creation * when reset use clearKey() * when generate use setParams and generate and set also the secret value
The good part is that keypair doesn't need to be used with initialized key, but only a key pair from KeyBuilder.buildKey, and can be instantiated once (right after the key pair instantiation, done once). And the setParams can be done on a key after a clearKey (or on a new key the first time).
After rebasing test-issue-29
atop v1.22.1-3.0.4
, test applet says that my J3R180 supports object deletion, and SmartPGPApplet built from rebased test-issue-29
can pass 300 times repeated key generation performed with https://gist.github.com/wreps8Owt/504234e0e09df2ca10e7c34ddcc225fb , while the latest release will fail on the 174th key generation (the index starts from 0):
PublicKey 173 for signature : 0x0454cabea466a4142e61c97d799ddeaba0a8b5789328f469321187ee041f96b646f4cdc84f9da87294ec3deb23f5c3ea94640e0226b3bc3fdb8d2bf55e211d288f Crash, game over. SFYL ! Error status : 0x6F00
We identified a memory leak in this applet. Memory management on Javacard is very hard, especially because the limited RAM resource of the card chip which is approximately 2-3kB free maximum.
We believe this issue affects all cards on all JCOP versions. This is just a matter of how many operations are required to fill up the memory. This is a very annoying bug, as the card for example can't no more sign after a given number of signatures. Our tests show that even a power cycle of the card doesn't free the memory. This is a "feature" of JCOP, hence requiring some special techniques about memory management. Also, a applet reset (Terminate+Activate) doesn't clear the transient memory. This issue can lead to disastrous consequences as this can prevent any new signatures or others cryptographic operations with keys which only exists in the secure applet. Only an applet re-installation put the applet on the right track.
We have even decreased some RAM constants parameters, and the issue is nearly the same. The signature crashes forever after around 20 signatures.
For now, our team doesn't have some much time to fix this issue. But here are some recommendations to fix this :
Note that the instantiation of nearly everything at the applet installation can lead to an other similar issue. The install function process is always performed in a transactional reversible process, which means every steps are saved in RAM. So the processing can't take too much memory. Most of the time this is OK. Still, if this happens, one should defer the instantiation at a later stage, like splitting the instantiation in 2 parts. For example at the very first select or at the first. The difficult part then in this case is to locate when this second instantiation part should happen.
Log details about the issue : Performs with https://gist.github.com/bitlogik/44a7502f0b303ec10a3f45a810ac82fa using OpenPGPpy on a J3R110.