Skip to content

Commit

Permalink
Merge pull request #2 from vletoux/less_memory
Browse files Browse the repository at this point in the history
Add support for Feitian cards
  • Loading branch information
vletoux authored Jul 4, 2016
2 parents 1d8fbc1 + 24e2e88 commit c66331e
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 50 deletions.
109 changes: 66 additions & 43 deletions src/com/mysmartlogon/gidsApplet/GidsApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import javacard.security.KeyPair;
import javacard.security.PrivateKey;
import javacard.security.PublicKey;
import javacard.security.RSAPrivateCrtKey;
import javacard.security.RSAPublicKey;
import javacardx.crypto.Cipher;
import javacard.security.CryptoException;
Expand Down Expand Up @@ -426,6 +427,15 @@ public void processGenerateAsymmetricKeypair(APDU apdu) throws ISOException {
break;
}
kp.genKeyPair();

// special Feitian workaround for A40CR and A22CR cards
RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) kp.getPrivate();
short pLen = priKey.getP(buf, (short) 0);
priKey.setP(buf, (short) 0, pLen);
short qLen = priKey.getQ(buf, (short) 0);
priKey.setQ(buf, (short) 0, qLen);
// end of workaround

} catch(CryptoException e) {
if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
Expand Down Expand Up @@ -766,7 +776,7 @@ private void computeDigitalSignature(APDU apdu) throws ISOException {
if(lc > (short) 247) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}

rsaPkcs1Cipher.init(rsaKey, Cipher.MODE_ENCRYPT);
sigLen = rsaPkcs1Cipher.doFinal(buf, ISO7816.OFFSET_CDATA, lc, ram_buf, (short)0);

Expand Down Expand Up @@ -826,57 +836,70 @@ private void importPrivateKey(APDU apdu) throws ISOException {
short recvLen;
short len = 0, pos = 0;
short innerPos = 0, innerLen = 0;
byte[] ram_buf = transmitManager.GetRamBuffer();
byte[] flash_buf = null;
byte privKeyRef = -1;
CRTKeyFile crt = null;

if( ! DEF_PRIVATE_KEY_IMPORT_ALLOWED) {
ISOException.throwIt(ErrorCode.SW_COMMAND_NOT_ALLOWED_GENERAL);
}

recvLen = transmitManager.doChainingOrExtAPDU(apdu);

try {
innerPos = UtilTLV.findTag(ram_buf, (short) 0, recvLen, (byte) 0x70);
innerLen = UtilTLV.decodeLengthField(ram_buf, (short)(innerPos+1));
innerPos += 1 + UtilTLV.getLengthFieldLength(ram_buf, (short)(innerPos+1));
} catch (Exception e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}

try {
pos = UtilTLV.findTag(ram_buf, innerPos, innerLen, (byte) 0x84);
len = UtilTLV.decodeLengthField(ram_buf, (short)(innerPos+1));
if (len != 1) {
try
{
// flash buffer is allocated in the next instruction
recvLen = transmitManager.doChainingOrExtAPDUFlash(apdu);
// if these 2 lines are reversed, flash_buf can be null
flash_buf = transmitManager.GetFlashBuffer();

try {
innerPos = UtilTLV.findTag(flash_buf, (short) 0, recvLen, (byte) 0x70);
innerLen = UtilTLV.decodeLengthField(flash_buf, (short)(innerPos+1));
innerPos += 1 + UtilTLV.getLengthFieldLength(flash_buf, (short)(innerPos+1));
} catch (Exception e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
privKeyRef = ram_buf[(short) (pos+2)];
} catch (Exception e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
try {
pos = UtilTLV.findTag(ram_buf, innerPos, innerLen, (byte) 0xA5);
len = UtilTLV.decodeLengthField(ram_buf, (short)(innerPos+1));
} catch (Exception e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
if(privKeyRef == -1) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
try {
crt = fs.findKeyCRT(privKeyRef);
} catch (NotFoundException e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}

crt.CheckPermission(pinManager, File.ACL_OP_KEY_PUTKEY);

try {
crt.importKey(ram_buf, pos, len);
} catch (InvalidArgumentsException e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);

try {
pos = UtilTLV.findTag(flash_buf, innerPos, innerLen, (byte) 0x84);
len = UtilTLV.decodeLengthField(flash_buf, (short)(innerPos+1));
if (len != 1) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
privKeyRef = flash_buf[(short) (pos+2)];
} catch (Exception e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
try {
pos = UtilTLV.findTag(flash_buf, innerPos, innerLen, (byte) 0xA5);
len = UtilTLV.decodeLengthField(flash_buf, (short)(innerPos+1));
} catch (Exception e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
if(privKeyRef == -1) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
try {
crt = fs.findKeyCRT(privKeyRef);
} catch (NotFoundException e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}

crt.CheckPermission(pinManager, File.ACL_OP_KEY_PUTKEY);

try {
crt.importKey(flash_buf, pos, len);
} catch (InvalidArgumentsException e) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
// clear ressource and avoid leaking a private key in flash (if the private key is deleted after)
transmitManager.ClearFlashBuffer();
} catch(ISOException e) {
if (e.getReason() != ISO7816.SW_NO_ERROR) {
// clear ressource and avoid leaking a private key in flash (if the private key is deleted after)
transmitManager.ClearFlashBuffer();
}
throw e;
}

}

} // class GidsApplet
56 changes: 49 additions & 7 deletions src/com/mysmartlogon/gidsApplet/TransmitManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,23 @@
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.SystemException;
import javacard.framework.Util;

public class TransmitManager {

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

private byte[] flash_buf = null;

// number of variables for the cache
private static final short CHAINING_CACHE_SIZE = (short) 6;
// index of the object (when sending Record[])
Expand Down Expand Up @@ -78,10 +83,27 @@ private void Clear(boolean buffer) {
public byte[] GetRamBuffer() {
return ram_buf;
}

public byte[] GetFlashBuffer()
{
return flash_buf;
}

public void ClearRamBuffer() {
Clear(true);
}

public void ClearFlashBuffer() {
if (flash_buf != null)
{
if(JCSystem.isObjectDeletionSupported()) {
flash_buf = null;
JCSystem.requestObjectDeletion();
} else {
Util.arrayFillNonAtomic(flash_buf, (short)0, FLASH_BUF_SIZE, (byte)0x00);
}
}
}

/**
* \brief Parse the apdu's CLA byte to determine if the apdu is the first or second-last part of a chain.
Expand Down Expand Up @@ -161,15 +183,35 @@ public void processChainInitialization(APDU apdu) {
* \throw ISOException SW_WRONG_LENGTH
*/
public short doChainingOrExtAPDU(APDU apdu) throws ISOException {
byte[] buf = apdu.getBuffer();
return doChainingOrExtAPDUWithBuffer(apdu, ram_buf, RAM_BUF_SIZE);
}

public short doChainingOrExtAPDUFlash(APDU apdu) throws ISOException {
// allocate flash buffer only when needed - it can remain for the rest of the card life
if (flash_buf == null)
{
try {
flash_buf = new byte[FLASH_BUF_SIZE];
} catch(SystemException e) {
if(e.getReason() == SystemException.NO_RESOURCE) {
ISOException.throwIt(ISO7816.SW_FILE_FULL);
}
ISOException.throwIt(ISO7816.SW_UNKNOWN);
}
}
return doChainingOrExtAPDUWithBuffer(apdu, flash_buf, FLASH_BUF_SIZE);
}

private short doChainingOrExtAPDUWithBuffer(APDU apdu, byte[] databuffer, short bufferlen) throws ISOException {

short recvLen = apdu.setIncomingAndReceive();

byte[] buf = apdu.getBuffer();
// Receive data (short or extended).
while (recvLen > 0) {
if((short)(chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] + recvLen) > RAM_BUF_SIZE) {
if((short)(chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] + recvLen) > bufferlen) {
ISOException.throwIt(ISO7816.SW_FILE_FULL);
}
Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, ram_buf, chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS], recvLen);
Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, databuffer, chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS], recvLen);
chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] += recvLen;
recvLen = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
}
Expand Down Expand Up @@ -213,8 +255,8 @@ private short copyRecordsToRamBuf(short le) {
while (records[index] != null) {
byte[] data = records[index].GetData();
short dataToCopy = (short)(data.length - pos);
if (dataToCopy > 512) {
dataToCopy = 512;
if ((short)(dataToCopy + dataCopied) > 512) {
dataToCopy = (short) (512 - dataCopied);
}
Util.arrayCopyNonAtomic(data, pos, ram_buf, dataCopied, dataToCopy);
if ((short) (dataCopied + dataToCopy) == le) {
Expand Down

0 comments on commit c66331e

Please sign in to comment.