Skip to content

Commit c66331e

Browse files
authored
Merge pull request #2 from vletoux/less_memory
Add support for Feitian cards
2 parents 1d8fbc1 + 24e2e88 commit c66331e

File tree

2 files changed

+115
-50
lines changed

2 files changed

+115
-50
lines changed

src/com/mysmartlogon/gidsApplet/GidsApplet.java

+66-43
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import javacard.security.KeyPair;
3636
import javacard.security.PrivateKey;
3737
import javacard.security.PublicKey;
38+
import javacard.security.RSAPrivateCrtKey;
3839
import javacard.security.RSAPublicKey;
3940
import javacardx.crypto.Cipher;
4041
import javacard.security.CryptoException;
@@ -426,6 +427,15 @@ public void processGenerateAsymmetricKeypair(APDU apdu) throws ISOException {
426427
break;
427428
}
428429
kp.genKeyPair();
430+
431+
// special Feitian workaround for A40CR and A22CR cards
432+
RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) kp.getPrivate();
433+
short pLen = priKey.getP(buf, (short) 0);
434+
priKey.setP(buf, (short) 0, pLen);
435+
short qLen = priKey.getQ(buf, (short) 0);
436+
priKey.setQ(buf, (short) 0, qLen);
437+
// end of workaround
438+
429439
} catch(CryptoException e) {
430440
if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
431441
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
@@ -766,7 +776,7 @@ private void computeDigitalSignature(APDU apdu) throws ISOException {
766776
if(lc > (short) 247) {
767777
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
768778
}
769-
779+
770780
rsaPkcs1Cipher.init(rsaKey, Cipher.MODE_ENCRYPT);
771781
sigLen = rsaPkcs1Cipher.doFinal(buf, ISO7816.OFFSET_CDATA, lc, ram_buf, (short)0);
772782

@@ -826,57 +836,70 @@ private void importPrivateKey(APDU apdu) throws ISOException {
826836
short recvLen;
827837
short len = 0, pos = 0;
828838
short innerPos = 0, innerLen = 0;
829-
byte[] ram_buf = transmitManager.GetRamBuffer();
839+
byte[] flash_buf = null;
830840
byte privKeyRef = -1;
831841
CRTKeyFile crt = null;
832842

833843
if( ! DEF_PRIVATE_KEY_IMPORT_ALLOWED) {
834844
ISOException.throwIt(ErrorCode.SW_COMMAND_NOT_ALLOWED_GENERAL);
835845
}
836-
837-
recvLen = transmitManager.doChainingOrExtAPDU(apdu);
838-
839-
try {
840-
innerPos = UtilTLV.findTag(ram_buf, (short) 0, recvLen, (byte) 0x70);
841-
innerLen = UtilTLV.decodeLengthField(ram_buf, (short)(innerPos+1));
842-
innerPos += 1 + UtilTLV.getLengthFieldLength(ram_buf, (short)(innerPos+1));
843-
} catch (Exception e) {
844-
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
845-
}
846-
847-
try {
848-
pos = UtilTLV.findTag(ram_buf, innerPos, innerLen, (byte) 0x84);
849-
len = UtilTLV.decodeLengthField(ram_buf, (short)(innerPos+1));
850-
if (len != 1) {
846+
try
847+
{
848+
// flash buffer is allocated in the next instruction
849+
recvLen = transmitManager.doChainingOrExtAPDUFlash(apdu);
850+
// if these 2 lines are reversed, flash_buf can be null
851+
flash_buf = transmitManager.GetFlashBuffer();
852+
853+
try {
854+
innerPos = UtilTLV.findTag(flash_buf, (short) 0, recvLen, (byte) 0x70);
855+
innerLen = UtilTLV.decodeLengthField(flash_buf, (short)(innerPos+1));
856+
innerPos += 1 + UtilTLV.getLengthFieldLength(flash_buf, (short)(innerPos+1));
857+
} catch (Exception e) {
851858
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
852859
}
853-
privKeyRef = ram_buf[(short) (pos+2)];
854-
} catch (Exception e) {
855-
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
856-
}
857-
try {
858-
pos = UtilTLV.findTag(ram_buf, innerPos, innerLen, (byte) 0xA5);
859-
len = UtilTLV.decodeLengthField(ram_buf, (short)(innerPos+1));
860-
} catch (Exception e) {
861-
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
862-
}
863-
if(privKeyRef == -1) {
864-
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
865-
}
866-
try {
867-
crt = fs.findKeyCRT(privKeyRef);
868-
} catch (NotFoundException e) {
869-
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
870-
}
871-
872-
crt.CheckPermission(pinManager, File.ACL_OP_KEY_PUTKEY);
873-
874-
try {
875-
crt.importKey(ram_buf, pos, len);
876-
} catch (InvalidArgumentsException e) {
877-
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
860+
861+
try {
862+
pos = UtilTLV.findTag(flash_buf, innerPos, innerLen, (byte) 0x84);
863+
len = UtilTLV.decodeLengthField(flash_buf, (short)(innerPos+1));
864+
if (len != 1) {
865+
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
866+
}
867+
privKeyRef = flash_buf[(short) (pos+2)];
868+
} catch (Exception e) {
869+
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
870+
}
871+
try {
872+
pos = UtilTLV.findTag(flash_buf, innerPos, innerLen, (byte) 0xA5);
873+
len = UtilTLV.decodeLengthField(flash_buf, (short)(innerPos+1));
874+
} catch (Exception e) {
875+
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
876+
}
877+
if(privKeyRef == -1) {
878+
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
879+
}
880+
try {
881+
crt = fs.findKeyCRT(privKeyRef);
882+
} catch (NotFoundException e) {
883+
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
884+
}
885+
886+
crt.CheckPermission(pinManager, File.ACL_OP_KEY_PUTKEY);
887+
888+
try {
889+
crt.importKey(flash_buf, pos, len);
890+
} catch (InvalidArgumentsException e) {
891+
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
892+
}
893+
// clear ressource and avoid leaking a private key in flash (if the private key is deleted after)
894+
transmitManager.ClearFlashBuffer();
895+
} catch(ISOException e) {
896+
if (e.getReason() != ISO7816.SW_NO_ERROR) {
897+
// clear ressource and avoid leaking a private key in flash (if the private key is deleted after)
898+
transmitManager.ClearFlashBuffer();
899+
}
900+
throw e;
878901
}
879-
902+
880903
}
881904

882905
} // class GidsApplet

src/com/mysmartlogon/gidsApplet/TransmitManager.java

+49-7
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,23 @@
2828
import javacard.framework.ISO7816;
2929
import javacard.framework.ISOException;
3030
import javacard.framework.JCSystem;
31+
import javacard.framework.SystemException;
3132
import javacard.framework.Util;
3233

3334
public class TransmitManager {
3435

3536
// a ram buffer for public key export (no need to allocate flash !)
36-
private static final short RAM_BUF_SIZE = (short) 1220;
37+
// memory buffer size is determined by copyRecordsToRamBuf=min 512
38+
private static final short RAM_BUF_SIZE = (short) 530;
39+
private static final short FLASH_BUF_SIZE = (short) 1220;
3740
private byte[] ram_buf = null;
3841
// internal variables to do chaining
3942
private short[] chaining_cache = null;
4043
// store special object to returns or if null, use the ram buffer
4144
private Object[] chaining_object = null;
4245

46+
private byte[] flash_buf = null;
47+
4348
// number of variables for the cache
4449
private static final short CHAINING_CACHE_SIZE = (short) 6;
4550
// index of the object (when sending Record[])
@@ -78,10 +83,27 @@ private void Clear(boolean buffer) {
7883
public byte[] GetRamBuffer() {
7984
return ram_buf;
8085
}
86+
87+
public byte[] GetFlashBuffer()
88+
{
89+
return flash_buf;
90+
}
8191

8292
public void ClearRamBuffer() {
8393
Clear(true);
8494
}
95+
96+
public void ClearFlashBuffer() {
97+
if (flash_buf != null)
98+
{
99+
if(JCSystem.isObjectDeletionSupported()) {
100+
flash_buf = null;
101+
JCSystem.requestObjectDeletion();
102+
} else {
103+
Util.arrayFillNonAtomic(flash_buf, (short)0, FLASH_BUF_SIZE, (byte)0x00);
104+
}
105+
}
106+
}
85107

86108
/**
87109
* \brief Parse the apdu's CLA byte to determine if the apdu is the first or second-last part of a chain.
@@ -161,15 +183,35 @@ public void processChainInitialization(APDU apdu) {
161183
* \throw ISOException SW_WRONG_LENGTH
162184
*/
163185
public short doChainingOrExtAPDU(APDU apdu) throws ISOException {
164-
byte[] buf = apdu.getBuffer();
186+
return doChainingOrExtAPDUWithBuffer(apdu, ram_buf, RAM_BUF_SIZE);
187+
}
188+
189+
public short doChainingOrExtAPDUFlash(APDU apdu) throws ISOException {
190+
// allocate flash buffer only when needed - it can remain for the rest of the card life
191+
if (flash_buf == null)
192+
{
193+
try {
194+
flash_buf = new byte[FLASH_BUF_SIZE];
195+
} catch(SystemException e) {
196+
if(e.getReason() == SystemException.NO_RESOURCE) {
197+
ISOException.throwIt(ISO7816.SW_FILE_FULL);
198+
}
199+
ISOException.throwIt(ISO7816.SW_UNKNOWN);
200+
}
201+
}
202+
return doChainingOrExtAPDUWithBuffer(apdu, flash_buf, FLASH_BUF_SIZE);
203+
}
204+
205+
private short doChainingOrExtAPDUWithBuffer(APDU apdu, byte[] databuffer, short bufferlen) throws ISOException {
206+
165207
short recvLen = apdu.setIncomingAndReceive();
166-
208+
byte[] buf = apdu.getBuffer();
167209
// Receive data (short or extended).
168210
while (recvLen > 0) {
169-
if((short)(chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] + recvLen) > RAM_BUF_SIZE) {
211+
if((short)(chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] + recvLen) > bufferlen) {
170212
ISOException.throwIt(ISO7816.SW_FILE_FULL);
171213
}
172-
Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, ram_buf, chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS], recvLen);
214+
Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, databuffer, chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS], recvLen);
173215
chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] += recvLen;
174216
recvLen = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
175217
}
@@ -213,8 +255,8 @@ private short copyRecordsToRamBuf(short le) {
213255
while (records[index] != null) {
214256
byte[] data = records[index].GetData();
215257
short dataToCopy = (short)(data.length - pos);
216-
if (dataToCopy > 512) {
217-
dataToCopy = 512;
258+
if ((short)(dataToCopy + dataCopied) > 512) {
259+
dataToCopy = (short) (512 - dataCopied);
218260
}
219261
Util.arrayCopyNonAtomic(data, pos, ram_buf, dataCopied, dataToCopy);
220262
if ((short) (dataCopied + dataToCopy) == le) {

0 commit comments

Comments
 (0)