Joao Pedro a écrit :
Hello everyone,
Hi Joao, All,
this message is intended as a "request for ideas/opinions/comments" on
how the CardEdge applet manages its memory.
[...]
Sylvain Ferey pointed out that, on all newer cards, it should be safe to
assume that they provide, at least, 1024 bytes of RAM memory.
1024 bytes allocated to transients data !
also pointed out that, even if the card has sufficient RAM, one must be
careful while using it, since it is possible that other applets (if
present on the card) may already have allocated it for its own purposes.
some explanations are may be required, even if at this end it looks like
this, I prefer to describe it as:
the JCRE (JavaCard Runtime Environment) of course needs RAM for its
own purpose and applets will never see or use that RAM.
for the amount of RAM not used by the runtime and thus available to
the applets, the JCRE split it into (at least) 2 entities:
- the APDU buffer
the block of RAM dedicated to the APDU buffer never changes during
the card life, no action (from applets or JCRE) can change it.
about 10 years ago, with first JavaCard 2.0, it was 5 + 32 bytes long,
so setIncomingAndReceive received only up to 32 bytes, one can still
find in some samples (including SUN ones) some loops like:
apdu.setIncomingAndReceive();
// process data
while (...){
length = apdu.receiveBytes((short) 5);
// process data
}
these process are fully useless nowadays, most of the card provides
an APDU buffer of (around) 280 bytes so enough to store a 2048-bit
pattern to be signed and enough to get all transmitted data at once
(except with extended length of course).
so coding like:
short bytesLeft = Util.makeShort((byte) 0, buffer[4]);
if (bytesLeft != apdu.setIncomingAndReceive())
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
shall NOT (no longer) exist !
1- the support of extended length won't be possible due to
the direct length reading.
2- the return of setIncomingAndReceive will ALWAYS be the
value of Lc (short lengths!)
3- the applet SHALL check the length of received data against
what it does expect, not against an obvious identity
(and if unlikely, the applet is loaded on a 8 years old card
with 32 bytes, the process will fail as expected since the
card won't be able to transmit the required length of data).
- the transient buffer(s)
an applet may request RAM storage that is automatically cleared
upon applet deselection or card reset; some cards use 2 different
buffers for these 2 reset conditions, other ones use a single
buffer.
in case of 2 buffers, the maximal length available for an applet
for transient deselect buffer is the size of that buffer (since
it will be shared between all applets, of course its content is
reset prior context switch).
in case of 1 buffer, , the maximal length available for an applet
for transient deselect buffer is the size of that buffer less the
cumul of all transient reset blocks allocated by each applet (since
a transient reset is not shared and only cleared during card reset).
the size of transient deselect an applet can use is so dependents
on other applets (do they allocate some transient reset?) and on
the platform (not all platform provide the same size, but recent
cards should provide around 1024 bytes).
With this in mind (and since I'm not rich, it would be nice that my card
lasted a little bit more :P), I've written a small patch that avoids
EEPROM memory usage altogether if the applet is compiled with the
extended APDU option. The applet will need to have 526 bytes of RAM
memory available (268 bytes for the incoming buffer, 258 bytes for the
outgoing buffer) - this can be much more optimized, but I think it
should be part of a bigger effort...)
you very seldom need an input AND an output buffer of the same size
at the same moment - none comes spontaneously to my mind.
for all "stream" functions, so encrypt / decrypt, you must process
data in place.
let imagine a card w/o extended length support and an encrypt process
with 3DES key, in block size shall be a multiple of 8, so 248 is the
upper limit (assuming 'plain' data are transmitted, meaning there is
no trans-encryption, eg decryption with GP keys, prior encryption
with proprietary keys), you will simply implement:
// a "Init Crypto context" was issued to initialise the cipher
// it could be an ISO Manage Security Environment APDU or a CIPHER_INIT
// I use CardEdge APDU hereafter:
"length" is a short, "int8" is a byte, both defined as local variables
of the process() method.
switch (buffer[1]){
case (byte) 0x36:
int8 = buffer[3]; // get operation
length = apdu.setIncomingAndReceive();
if (int8 == 1){
// initialize the cipher, not illustrated
}
else if (int8 == 2)
length = cipher.update(buffer,(short)5,length,buffer,(short)5);
else if (int8 == 3)
length = cipher.doFinal(buffer,(short)5,length,buffer,(short)5);
else
ISOException((short) 0x6A86);
apdu.setOutgoingAndSend((short) 5, length);
return;
no more, no less, no don't need 2 buffers, you only need the existing
APDU buffer.
I didn't bench such code as compared to an encryption of 1024 bytes
using a transient deselect buffer (that so imply a RAM to RAM copy),
the lower layers of the I/O will impact the resultat but they are
certainly quite similar.
The main advantages are:
- It's faster - "pkcs11-tool --login --test" appears to be ~20% faster;
- It will not kill the card's memory.
The disvantages are:
- It's less secure (?) - the original memory allocation with
ObjectManager creates ACLs on the allocated memory so only the creator
of the object can access it.
No, all code issued from the CardEdge package can access it, so the
applet the ObjectManager and the MemoryManager, and BTW indeed these
3 parts may need to access data.
the ACLs, as well as the keys or file-storage are allocated from
the EEPROM and the applet firewall grants that only this applet
(and utility classes if any) hace access to these blocks, there
is no security concerns around that, a file (a CardEgde's object)
should be a byte[] allocated with 14 + 'object size' bytes; a key
could be a JavaCard instance storing a Key instance and the 4-byte
ACLs.
To try to mitigate this, I've added code to clear the buffer after
it is used, but is this secure enough? What are the security
implications?;
the transient deselect buffers ?
they are cleared if another applet is selected, and of course if the
card is powered off.
- RAM is needed... - shouldn't be a problem on cards that support
extended APDUs. For example, my card has 8KB of RAM.
the APDU buffer is your friend !
some cards provide an APDU buffer of 500 bytes or more (635 for the
Cosmo v.7). did you check it ?
// assuming "buffer" is the result of apdu.getBuffer()
switch (INS){
case (byte) 0: // dummy get info
Util.setShort(buffer, (short) 5, (short) buffer.length);
apdu.setOutgoingAndSend((short) 5, (short) 2);
return;
Again, this patch only affects the applet if the WITH_EXT_APDU option is
enabled. If not, the old behavior is used. But, maybe, it could be a
good idea to use a smaller buffer even without the WITH_EXT_APDU option?
;-) yes it will be a good idea to NOT use any buffer (but APDU buffer).
I start a review of the full code recently downloaded, there are a lot
of things to clean up; my first try - since I'm using Eclipse - is to
let it understand the #ifdef clause ! is there any way to do that ?
another issue is that some points should be broken because they are
nosense (when data are returned they are prefixed by their length as
a short ?! the protocol does provides that information (the length of
returned data) as the very first data, why to duplicate it ??)
but is there a voluntary to implement a new middleware module?
Thanks everyone for the discussion on the last days. It's a privilege
(and a pleasure) to learn about smart card development with people like
you.
you're welcome.
Sylvain.
_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle