diff --git a/src/com/mysmartlogon/gidsApplet/GidsApplet.java b/src/com/mysmartlogon/gidsApplet/GidsApplet.java index 5e245e4..2b8cb60 100644 --- a/src/com/mysmartlogon/gidsApplet/GidsApplet.java +++ b/src/com/mysmartlogon/gidsApplet/GidsApplet.java @@ -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; @@ -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); @@ -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); @@ -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 diff --git a/src/com/mysmartlogon/gidsApplet/TransmitManager.java b/src/com/mysmartlogon/gidsApplet/TransmitManager.java index 74027a9..595e396 100644 --- a/src/com/mysmartlogon/gidsApplet/TransmitManager.java +++ b/src/com/mysmartlogon/gidsApplet/TransmitManager.java @@ -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[]) @@ -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. @@ -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); } @@ -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) {