diff options
| author | J08nY | 2018-11-06 16:12:09 +0100 |
|---|---|---|
| committer | J08nY | 2018-11-06 16:12:09 +0100 |
| commit | c676bacffd1305e1efc49b34d87ffd0a0a695ea7 (patch) | |
| tree | e3efe9f24d9be1064857ba9756de48134997a628 /src | |
| parent | 99e46d99005784ac1b8815c85cfd56994f8f1feb (diff) | |
| download | ECTester-c676bacffd1305e1efc49b34d87ffd0a0a695ea7.tar.gz ECTester-c676bacffd1305e1efc49b34d87ffd0a0a695ea7.tar.zst ECTester-c676bacffd1305e1efc49b34d87ffd0a0a695ea7.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/cz/crcs/ectester/applet/AppletBase.java | 878 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/AppletUtil.java | 29 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECKeyTester.java | 4 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECTesterApplet.java | 811 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECTesterAppletExtended.java | 61 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/ECTesterReader.java | 3 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/command/Command.java | 28 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/response/Response.java | 45 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/test/CardDefaultSuite.java | 5 |
9 files changed, 1036 insertions, 828 deletions
diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java new file mode 100644 index 0000000..aa6bc07 --- /dev/null +++ b/src/cz/crcs/ectester/applet/AppletBase.java @@ -0,0 +1,878 @@ +package cz.crcs.ectester.applet; + +import javacard.framework.*; +import javacard.security.*; + +public abstract class AppletBase extends Applet { + + // MAIN INSTRUCTION CLASS + public static final byte CLA_ECTESTERAPPLET = (byte) 0xB0; + + // INSTRUCTIONS + public static final byte INS_ALLOCATE = (byte) 0x5a; + public static final byte INS_CLEAR = (byte) 0x5b; + public static final byte INS_SET = (byte) 0x5c; + public static final byte INS_TRANSFORM = (byte) 0x5d; + public static final byte INS_GENERATE = (byte) 0x5e; + public static final byte INS_EXPORT = (byte) 0x5f; + public static final byte INS_ECDH = (byte) 0x70; + public static final byte INS_ECDH_DIRECT = (byte) 0x71; + public static final byte INS_ECDSA = (byte) 0x72; + public static final byte INS_ECDSA_SIGN = (byte) 0x73; + public static final byte INS_ECDSA_VERIFY = (byte) 0x74; + public static final byte INS_CLEANUP = (byte) 0x75; + public static final byte INS_ALLOCATE_KA = (byte) 0x76; + public static final byte INS_ALLOCATE_SIG = (byte) 0x77; + public static final byte INS_GET_INFO = (byte) 0x78; + + // PARAMETERS for P1 and P2 + public static final byte KEYPAIR_LOCAL = (byte) 0x01; + public static final byte KEYPAIR_REMOTE = (byte) 0x02; + public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE; + public static final byte EXPORT_TRUE = (byte) 0xff; + public static final byte EXPORT_FALSE = (byte) 0x00; + + // STATUS WORDS + public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1; + public static final short SW_DH_DHC_MISMATCH = (short) 0x0ee2; + public static final short SW_KEYPAIR_NULL = (short) 0x0ee3; + public static final short SW_KA_NULL = (short) 0x0ee4; + public static final short SW_SIGNATURE_NULL = (short) 0x0ee5; + public static final short SW_OBJECT_NULL = (short) 0x0ee6; + public static final short SW_Exception = (short) 0xff01; + public static final short SW_ArrayIndexOutOfBoundsException = (short) 0xff02; + public static final short SW_ArithmeticException = (short) 0xff03; + public static final short SW_ArrayStoreException = (short) 0xff04; + public static final short SW_NullPointerException = (short) 0xff05; + public static final short SW_NegativeArraySizeException = (short) 0xff06; + public static final short SW_CryptoException_prefix = (short) 0xf100; + public static final short SW_SystemException_prefix = (short) 0xf200; + public static final short SW_PINException_prefix = (short) 0xf300; + public static final short SW_TransactionException_prefix = (short) 0xf400; + public static final short SW_CardRuntimeException_prefix = (short) 0xf500; + + // + public static final short BASE_221 = (short) 0x0221; + public static final short BASE_222 = (short) 0x0222; + + // + public static final byte[] VERSION = {'v', '0', '.', '3', '.', '0'}; + + public static final short ARRAY_LENGTH = 0xff; + public static final short APDU_MAX_LENGTH = 1024; + + // TEMPORARRY ARRAY IN RAM + byte[] ramArray = null; + byte[] ramArray2 = null; + byte[] apduArray = null; + + RandomData randomData = null; + + ECKeyTester keyTester = null; + ECKeyGenerator keyGenerator = null; + KeyPair localKeypair = null; + KeyPair remoteKeypair = null; + + protected AppletBase(byte[] buffer, short offset, byte length) { + if (length > 9) { + /* + short dataOffset = offset; + // shift to privilege offset + dataOffset += (short) (1 + buffer[offset]); + // finally shift to Application specific offset + dataOffset += (short) (1 + buffer[dataOffset]); + // go to proprietary data + dataOffset++; + */ + + ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); + ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); + apduArray = JCSystem.makeTransientByteArray(APDU_MAX_LENGTH, JCSystem.CLEAR_ON_RESET); + + randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); + EC_Consts.randomData = randomData; + + keyGenerator = new ECKeyGenerator(); + keyTester = new ECKeyTester(); + } + } + + public void process(APDU apdu) throws ISOException { + // get the APDU buffer + byte[] apduBuffer = apdu.getBuffer(); + byte cla = apduBuffer[ISO7816.OFFSET_CLA]; + byte ins = apduBuffer[ISO7816.OFFSET_INS]; + + // ignore the applet select command dispatched to the process + if (selectingApplet()) { + return; + } + + if (cla == CLA_ECTESTERAPPLET) { + try { + readAPDU(apdu, apduArray, APDU_MAX_LENGTH); + + short length = 0; + switch (ins) { + case INS_ALLOCATE_KA: + length = insAllocateKA(apdu); + break; + case INS_ALLOCATE_SIG: + length = insAllocateSig(apdu); + break; + case INS_ALLOCATE: + length = insAllocate(apdu); + break; + case INS_CLEAR: + length = insClear(apdu); + break; + case INS_SET: + length = insSet(apdu); + break; + case INS_TRANSFORM: + length = insTransform(apdu); + break; + case INS_GENERATE: + length = insGenerate(apdu); + break; + case INS_EXPORT: + length = insExport(apdu); + break; + case INS_ECDH: + length = insECDH(apdu); + break; + case INS_ECDH_DIRECT: + length = insECDH_direct(apdu); + break; + case INS_ECDSA: + length = insECDSA(apdu); + break; + case INS_ECDSA_SIGN: + length = insECDSA_sign(apdu); + break; + case INS_ECDSA_VERIFY: + length = insECDSA_verify(apdu); + break; + case INS_CLEANUP: + length = insCleanup(apdu); + break; + case INS_GET_INFO: + length = insGetInfo(apdu); + break; + default: + // The INS code is not supported by the dispatcher + ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); + break; + } + apdu.setOutgoingAndSend((short) 0, length); + + } catch (ISOException e) { + throw e; // Our exception from code, just re-emit + } catch (ArrayIndexOutOfBoundsException e) { + ISOException.throwIt(SW_ArrayIndexOutOfBoundsException); + } catch (ArithmeticException e) { + ISOException.throwIt(SW_ArithmeticException); + } catch (ArrayStoreException e) { + ISOException.throwIt(SW_ArrayStoreException); + } catch (NullPointerException e) { + ISOException.throwIt(SW_NullPointerException); + } catch (NegativeArraySizeException e) { + ISOException.throwIt(SW_NegativeArraySizeException); + } catch (CryptoException e) { + ISOException.throwIt((short) (SW_CryptoException_prefix | e.getReason())); + } catch (SystemException e) { + ISOException.throwIt((short) (SW_SystemException_prefix | e.getReason())); + } catch (PINException e) { + ISOException.throwIt((short) (SW_PINException_prefix | e.getReason())); + } catch (TransactionException e) { + ISOException.throwIt((short) (SW_TransactionException_prefix | e.getReason())); + } catch (CardRuntimeException e) { + ISOException.throwIt((short) (SW_CardRuntimeException_prefix | e.getReason())); + } catch (Exception e) { + ISOException.throwIt(SW_Exception); + } + + } else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); + } + + private void readAPDU(APDU apdu, byte[] buffer, short length) { + short read = apdu.setIncomingAndReceive(); + read += getOffsetCdata(apdu); + short total = getIncomingLength(apdu); + if (total > length) { + return; + } + + byte[] apduBuffer = apdu.getBuffer(); + short sum = 0; + + do { + Util.arrayCopyNonAtomic(apduBuffer, (short) 0, buffer, sum, read); + sum += read; + read = apdu.receiveBytes((short) 0); + } while (sum < total); + } + + abstract short getOffsetCdata(APDU apdu); + + abstract short getIncomingLength(APDU apdu); + + abstract short getBase(); + + /** + * Allocates KeyAgreement object, returns allocate SW. + * + * @param apdu DATA = byte KeyAgreementType + * @return length of response + */ + private short insAllocateKA(APDU apdu) { + short cdata = getOffsetCdata(apdu); + byte kaType = apduArray[cdata]; + short sw = keyTester.allocateKA(kaType); + Util.setShort(apdu.getBuffer(), (short) 0, sw); + return 2; + } + + /** + * Allocates a Signature object, returns allocate SW. + * + * @param apdu DATA = byte SignatureType + * @return length of response + */ + private short insAllocateSig(APDU apdu) { + short cdata = getOffsetCdata(apdu); + byte sigType = apduArray[cdata]; + short sw = keyTester.allocateSig(sigType); + Util.setShort(apdu.getBuffer(), (short) 0, sw); + return 2; + } + + /** + * Allocates local and remote keyPairs. + * returns allocate SWs + * + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) + * P2 = + * DATA = short keyLength + * byte keyClass + * @return length of response + */ + private short insAllocate(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + short cdata = getOffsetCdata(apdu); + short keyLength = Util.getShort(apduArray, cdata); + byte keyClass = apduArray[(short) (cdata + 2)]; + + return allocate(keyPair, keyLength, keyClass, apdu.getBuffer(), (short) 0); + } + + /** + * Clears local and remote keyPair's keys {@code .clearKey()}. + * returns clearKey SWs + * + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) + * P2 = + * @return length of response + */ + private short insClear(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + + short len = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += clear(localKeypair, apdu.getBuffer(), (short) 0); + } + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += clear(remoteKeypair, apdu.getBuffer(), len); + } + + return len; + } + + /** + * Sets curve parameters on local and remote keyPairs. + * returns setCurve SWs + * + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) + * P2 = byte curve (EC_Consts.CURVE_*) + * DATA = short params (EC_Consts.PARAMETER_* | ...) + * <p> + * if curveID = CURVE_EXTERNAL: + * [short paramLength, byte[] param], + * for all params in params, + * in order: field,a,b,g,r,k,w,s + * @return length of response + */ + private short insSet(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + byte curve = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + short params = Util.getShort(apduArray, cdata); + + short len = 0; + + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += set(localKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), (short) 0); + } + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += set(remoteKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), len); + } + + return len; + } + + /** + * Transforms curve paramaters of local and remote keyPairs. + * returns transformCurve SWs + * + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) + * P2 = byte key (EC_Consts.KEY_* | ...) + * DATA = short params (EC_Consts.PARAMETER_* | ...) + * short transformation (EC_Consts.TRANSFORMATION_* || ...) + * @return length of response + */ + private short insTransform(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + byte key = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + short params = Util.getShort(apduArray, cdata); + short transformation = Util.getShort(apduArray, (short) (cdata + 2)); + + short len = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += transform(localKeypair, key, params, transformation, apdu.getBuffer(), (short) 0); + } + + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += transform(remoteKeypair, key, params, transformation, apdu.getBuffer(), len); + } + + return len; + } + + /** + * Generates the local and remote keyPairs. + * returns generate SWs + * + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) + * P2 = + * @return length of response + */ + private short insGenerate(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + + short len = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += generate(localKeypair, apdu.getBuffer(), (short) 0); + } + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += generate(remoteKeypair, apdu.getBuffer(), len); + } + + return len; + } + + /** + * Exports selected key and domain parameters from the selected keyPair and key. + * + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) + * P2 = byte key (EC_Consts.KEY_* | ...) + * DATA = short params + * @return length of response + */ + private short insExport(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + byte key = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + short params = Util.getShort(apduArray, cdata); + + short swOffset = 0; + short len = (short) (keyPair == KEYPAIR_BOTH ? 4 : 2); + + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += export(localKeypair, key, params, apdu.getBuffer(), swOffset, len); + swOffset += 2; + } + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += export(remoteKeypair, key, params, apdu.getBuffer(), swOffset, len); + } + + return len; + } + + /** + * Performs ECDH, between the pubkey specified in P1(local/remote) and the privkey specified in P2(local/remote). + * returns deriveSecret SW, {@code if(export == EXPORT_TRUE)} => short secretlen, byte[] secret + * + * @param apdu P1 = byte pubkey (KEYPAIR_*) + * P2 = byte privkey (KEYPAIR_*) + * DATA = byte export (EXPORT_TRUE || EXPORT_FALSE) + * short transformation (EC_Consts.TRANSFORMATION_* | ...) + * byte type (EC_Consts.KA_* | ...) + * @return length of response + */ + private short insECDH(APDU apdu) { + byte pubkey = apduArray[ISO7816.OFFSET_P1]; + byte privkey = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + byte export = apduArray[cdata]; + short transformation = Util.getShort(apduArray, (short) (cdata + 1)); + byte type = apduArray[(short) (cdata + 3)]; + + return ecdh(pubkey, privkey, export, transformation, type, apdu.getBuffer(), (short) 0); + } + + /** + * Performs ECDH, directly between the privkey specified in P1(local/remote) and the raw data + * + * @param apdu P1 = byte privkey (KEYPAIR_*) + * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) + * DATA = short transformation (EC_Consts.TRANSFORMATION_* | ...) + * byte type (EC_Consts.KA_* | ...) + * short length + * byte[] pubkey + * @return length of response + */ + private short insECDH_direct(APDU apdu) { + byte privkey = apduArray[ISO7816.OFFSET_P1]; + byte export = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + short transformation = Util.getShort(apduArray, cdata); + byte type = apduArray[(short) (cdata + 2)]; + short length = Util.getShort(apduArray, (short) (cdata + 3)); + + return ecdh_direct(privkey, export, transformation, type, (short) (cdata + 5), length, apdu.getBuffer(), (short) 0); + } + + /** + * Performs ECDSA signature and verification on data provided or random, using the keyPair in P1(local/remote). + * returns ecdsa SW, {@code if(export == EXPORT_TRUE)} => short signature_length, byte[] signature + * + * @param apdu P1 = byte keyPair (KEYPAIR_*) + * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) + * DATA = byte sigType + * short dataLength (00 = random data generated, !00 = data length) + * byte[] data + * @return length of response + */ + private short insECDSA(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + byte export = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + byte sigType = apduArray[cdata]; + + short len = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += ecdsa(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0); + } + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += ecdsa(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len); + } + + return len; + } + + /** + * @param apdu P1 = byte keyPair (KEYPAIR_*) + * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) + * DATA = byte sigType + * short dataLength (00 = random data generated, !00 = data length) + * byte[] data + * @return length of response + */ + private short insECDSA_sign(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + byte export = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + byte sigType = apduArray[cdata]; + + short len = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += ecdsa_sign(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0); + } + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += ecdsa_sign(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len); + } + return len; + } + + /** + * @param apdu P1 = byte keyPair (KEYPAIR_*) + * P2 = byte sigType + * DATA = short dataLength (00 = random data generated, !00 = data length) + * byte[] data + * short sigLength + * byte[] signature + * @return length of response + */ + private short insECDSA_verify(APDU apdu) { + byte keyPair = apduArray[ISO7816.OFFSET_P1]; + byte sigType = apduArray[ISO7816.OFFSET_P2]; + short cdata = getOffsetCdata(apdu); + + short len = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) { + len += ecdsa_verify(localKeypair, sigType, apduArray, cdata, apdu.getBuffer(), (short) 0); + } + if ((keyPair & KEYPAIR_REMOTE) != 0) { + len += ecdsa_verify(remoteKeypair, sigType, apduArray, cdata, apdu.getBuffer(), len); + } + return len; + } + + + /** + * Performs card memory cleanup via JCSystem.requestObjectDeletion() + * + * @param apdu no data + * @return length of response + */ + private short insCleanup(APDU apdu) { + byte[] apdubuf = apdu.getBuffer(); + + return cleanup(apdubuf, (short) 0); + } + + /** + * Gathers info about the applet and the card environment. + * + * @param apdu no data + * @return length of response + */ + private short insGetInfo(APDU apdu) { + byte[] apdubuf = apdu.getBuffer(); + + return getInfo(apdubuf, (short) 0); + } + + /** + * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) + * @param keyLength key length to set + * @param keyClass key class to allocate + * @param outBuffer buffer to write sw to + * @param outOffset offset into buffer + * @return length of data written to the buffer + */ + private short allocate(byte keyPair, short keyLength, byte keyClass, byte[] outBuffer, short outOffset) { + short length = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) { + localKeypair = keyGenerator.allocatePair(keyClass, keyLength); + Util.setShort(outBuffer, outOffset, keyGenerator.getSW()); + length += 2; + } + + if ((keyPair & KEYPAIR_REMOTE) != 0) { + remoteKeypair = keyGenerator.allocatePair(keyClass, keyLength); + Util.setShort(outBuffer, (short) (outOffset + length), keyGenerator.getSW()); + length += 2; + } + + return length; + } + + /** + * @param keyPair KeyPair to clear + * @param outBuffer buffer to write sw to + * @param outOffset offset into buffer + * @return length of data written to the buffer + */ + private short clear(KeyPair keyPair, byte[] outBuffer, short outOffset) { + short sw = keyGenerator.clearPair(keyPair, EC_Consts.KEY_BOTH); + Util.setShort(outBuffer, outOffset, sw); + + return 2; + } + + /** + * @param keyPair KeyPair to set params on + * @param curve curve to set (EC_Consts.CURVE_*) + * @param params parameters to set (EC_Consts.PARAMETER_* | ...) + * @param inBuffer buffer to read params from + * @param inOffset input offset in buffer + * @param outBuffer buffer to write sw to + * @param outOffset output offset in buffer + * @return length of data written to the buffer + */ + private short set(KeyPair keyPair, byte curve, short params, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { + short sw = ISO7816.SW_NO_ERROR; + + switch (curve) { + case EC_Consts.CURVE_default: + //default, dont set anything + break; + case EC_Consts.CURVE_external: + //external + sw = keyGenerator.setExternalCurve(keyPair, params, inBuffer, inOffset); + break; + default: + //custom + sw = keyGenerator.setCurve(keyPair, curve, params, ramArray, (short) 0); + break; + } + + Util.setShort(outBuffer, outOffset, sw); + return 2; + } + + /** + * @param keyPair KeyPair to transform + * @param key key to transform (EC_Consts.KEY_* | ...) + * @param params parameters to transform (EC_Consts.PARAMETER_* | ...) + * @param transformation transformation type (EC_Consts.TRANSFORMATION_*) + * @param outBuffer buffer to output sw to + * @param outOffset output offset in buffer + * @return length of data written to the buffer + */ + private short transform(KeyPair keyPair, byte key, short params, short transformation, byte[] outBuffer, short outOffset) { + short sw = keyGenerator.transformCurve(keyPair, key, params, transformation, ramArray, (short) 0); + Util.setShort(outBuffer, outOffset, sw); + return 2; + } + + /** + * @param keyPair KeyPair to generate + * @param outBuffer buffer to output sw to + * @param outOffset output offset in buffer + * @return length of data written to the buffer + */ + private short generate(KeyPair keyPair, byte[] outBuffer, short outOffset) { + short sw = keyGenerator.generatePair(keyPair); + Util.setShort(outBuffer, outOffset, sw); + + return 2; + } + + /** + * @param keyPair KeyPair to export from + * @param key which key to export from (EC_Consts.KEY_PUBLIC | EC_Consts.KEY_PRIVATE) + * @param params which params to export (EC_Consts.PARAMETER_* | ...) + * @param outBuffer buffer to export params to + * @param swOffset offset to output sw to buffer + * @param outOffset output offset in buffer + * @return length of data written to the buffer + */ + private short export(KeyPair keyPair, byte key, short params, byte[] outBuffer, short swOffset, short outOffset) { + short length = 0; + + short sw = ISO7816.SW_NO_ERROR; + if ((key & EC_Consts.KEY_PUBLIC) != 0) { + //export params from public + length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PUBLIC, params, outBuffer, outOffset); + sw = keyGenerator.getSW(); + } + if ((key & EC_Consts.KEY_PRIVATE) != 0 && sw == ISO7816.SW_NO_ERROR) { + //export params from private + length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PRIVATE, params, outBuffer, (short) (outOffset + length)); + sw = keyGenerator.getSW(); + } + Util.setShort(outBuffer, swOffset, sw); + + return length; + } + + /** + * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param export whether to export ECDH secret + * @param transformation whether to transform the pubkey before ECDH + * @param type KeyAgreement type to test + * @param outBuffer buffer to write sw to, and export ECDH secret {@code if(export == EXPORT_TRUE)} + * @param outOffset output offset in buffer + * @return length of data written to the buffer + */ + private short ecdh(byte pubkey, byte privkey, byte export, short transformation, byte type, byte[] outBuffer, short outOffset) { + short length = 0; + + KeyPair pub = ((pubkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; + KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; + + short secretLength = 0; + if (keyTester.getKaType() == type) { + secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation); + } else { + short allocateSW = keyTester.allocateKA(type); + if (allocateSW == ISO7816.SW_NO_ERROR) { + secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation); + } + } + Util.setShort(outBuffer, outOffset, keyTester.getSW()); + length += 2; + + if ((export == EXPORT_TRUE)) { + Util.setShort(outBuffer, (short) (outOffset + length), secretLength); + length += 2; + Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength); + length += secretLength; + } + + return length; + } + + private short ecdh_direct(byte privkey, byte export, short transformation, byte type, short keyOffset, short keyLength, byte[] outBuffer, short outOffset) { + short length = 0; + + KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; + + short secretLength = 0; + if (keyTester.getKaType() == type) { + secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation); + } else { + short allocateSW = keyTester.allocateKA(type); + if (allocateSW == ISO7816.SW_NO_ERROR) { + secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation); + } + } + + Util.setShort(outBuffer, outOffset, keyTester.getSW()); + length += 2; + + if ((export == EXPORT_TRUE)) { + Util.setShort(outBuffer, (short) (outOffset + length), secretLength); + length += 2; + Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength); + length += secretLength; + } + return length; + } + + /** + * @param sign keyPair to use for signing and verification + * @param sigType Signature type to use + * @param export whether to export ECDSA signature + * @param inBuffer buffer to read dataLength and data to sign from + * @param inOffset input offset in buffer + * @param outBuffer buffer to write sw to, and export ECDSA signature {@code if(export == EXPORT_TRUE)} + * @param outOffset output offset in buffer + * @return length of data written to the buffer + */ + private short ecdsa(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { + short length = 0; + + short dataLength = Util.getShort(inBuffer, inOffset); + if (dataLength == 0) { //no data to sign + //generate random + dataLength = 64; + randomData.generateData(ramArray, (short) 0, dataLength); + } else { + Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength); + } + + short signatureLength = 0; + if (keyTester.getSigType() == sigType) { + signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); + } else { + short allocateSW = keyTester.allocateSig(sigType); + if (allocateSW == ISO7816.SW_NO_ERROR) { + signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); + } + } + Util.setShort(outBuffer, outOffset, keyTester.getSW()); + length += 2; + + if (export == EXPORT_TRUE) { + Util.setShort(outBuffer, (short) (outOffset + length), signatureLength); + length += 2; + + Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength); + length += signatureLength; + } + + return length; + } + + private short ecdsa_sign(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { + short length = 0; + + short dataLength = Util.getShort(inBuffer, inOffset); + if (dataLength == 0) { //no data to sign + //generate random + dataLength = 64; + randomData.generateData(ramArray, (short) 0, dataLength); + } else { + Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength); + } + + short signatureLength = 0; + if (keyTester.getSigType() == sigType) { + signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); + } else { + short allocateSW = keyTester.allocateSig(sigType); + if (allocateSW == ISO7816.SW_NO_ERROR) { + signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); + } + } + Util.setShort(outBuffer, outOffset, keyTester.getSW()); + length += 2; + + if (export == EXPORT_TRUE) { + Util.setShort(outBuffer, (short) (outOffset + length), signatureLength); + length += 2; + + Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength); + length += signatureLength; + } + + return length; + } + + private short ecdsa_verify(KeyPair verify, byte sigType, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { + short length = 0; + + short dataLength = Util.getShort(inBuffer, inOffset); + short dataOffset = (short) (inOffset + 2); + short sigLength = Util.getShort(inBuffer, (short) (dataOffset + dataLength)); + short sigOffset = (short) (dataOffset + dataLength + 2); + + if (keyTester.getSigType() == sigType) { + keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength); + } else { + short allocateSW = keyTester.allocateSig(sigType); + if (allocateSW == ISO7816.SW_NO_ERROR) { + keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength); + } + } + Util.setShort(outBuffer, outOffset, keyTester.getSW()); + length += 2; + + return length; + } + + /** + * @param buffer buffer to write sw to + * @param offset output offset in buffer + * @return length of data written to the buffer + */ + private short cleanup(byte[] buffer, short offset) { + short sw = ISO7816.SW_NO_ERROR; + try { + if (JCSystem.isObjectDeletionSupported()) + JCSystem.requestObjectDeletion(); + } catch (CardRuntimeException crex) { + sw = crex.getReason(); + } + + Util.setShort(buffer, offset, sw); + return 2; + } + + /** + * @param buffer buffer to write sw to + * @param offset output offset in buffer + * @return length of data written to the buffer + */ + private short getInfo(byte[] buffer, short offset) { + short length = 0; + Util.setShort(buffer, (short) (offset + length), ISO7816.SW_NO_ERROR); + length += 2; + Util.setShort(buffer, (short) (offset + length), (short) VERSION.length); + length += 2; + Util.arrayCopyNonAtomic(VERSION, (short) 0, buffer, (short) (offset + length), (short) (VERSION.length)); + length += VERSION.length; + Util.setShort(buffer, (short) (offset + length), getBase()); + length += 2; + Util.setShort(buffer, (short) (offset + length), JCSystem.getVersion()); + length += 2; + Util.setShort(buffer, (short) (offset + length), (short) (JCSystem.isObjectDeletionSupported() ? 1 : 0)); + length += 2; + return length; + } +} diff --git a/src/cz/crcs/ectester/applet/AppletUtil.java b/src/cz/crcs/ectester/applet/AppletUtil.java index 532b44e..9869aa4 100644 --- a/src/cz/crcs/ectester/applet/AppletUtil.java +++ b/src/cz/crcs/ectester/applet/AppletUtil.java @@ -1,9 +1,7 @@ package cz.crcs.ectester.applet; -import javacard.framework.APDU; import javacard.framework.ISO7816; import javacard.framework.ISOException; -import javacard.framework.Util; import javacard.security.KeyAgreement; import javacard.security.KeyPair; import javacard.security.Signature; @@ -20,37 +18,18 @@ public class AppletUtil { } public static short objCheck(Object obj) { - return nullCheck(obj, ECTesterApplet.SW_OBJECT_NULL); + return nullCheck(obj, AppletBase.SW_OBJECT_NULL); } public static short keypairCheck(KeyPair keyPair) { - return nullCheck(keyPair, ECTesterApplet.SW_KEYPAIR_NULL); + return nullCheck(keyPair, AppletBase.SW_KEYPAIR_NULL); } public static short kaCheck(KeyAgreement keyAgreement) { - return nullCheck(keyAgreement, ECTesterApplet.SW_KA_NULL); + return nullCheck(keyAgreement, AppletBase.SW_KA_NULL); } public static short signCheck(Signature signature) { - return nullCheck(signature, ECTesterApplet.SW_SIGNATURE_NULL); - } - - public static short readAPDU(APDU apdu, byte[] buffer, short length) { - short read = apdu.setIncomingAndReceive(); - read += apdu.getOffsetCdata(); - short total = apdu.getIncomingLength(); - if (total > length) { - return 0; - } - byte[] apduBuffer = apdu.getBuffer(); - - short sum = 0; - - do { - Util.arrayCopyNonAtomic(apduBuffer, (short) 0, buffer, sum, read); - sum += read; - read = apdu.receiveBytes((short) 0); - } while (sum < total); - return 0; + return nullCheck(signature, AppletBase.SW_SIGNATURE_NULL); } } diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java index 6b5aa6b..0e46971 100644 --- a/src/cz/crcs/ectester/applet/ECKeyTester.java +++ b/src/cz/crcs/ectester/applet/ECKeyTester.java @@ -122,7 +122,7 @@ public class ECKeyTester { ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY); boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, length); if (!correct) { - sw = ECTesterApplet.SW_SIG_VERIFY_FAIL; + sw = AppletBase.SW_SIG_VERIFY_FAIL; } } catch (CardRuntimeException ce) { sw = ce.getReason(); @@ -170,7 +170,7 @@ public class ECKeyTester { ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY); boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, sigLength); if (!correct) { - sw = ECTesterApplet.SW_SIG_VERIFY_FAIL; + sw = AppletBase.SW_SIG_VERIFY_FAIL; } } catch (CardRuntimeException ce) { sw = ce.getReason(); diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index 17c8faf..41bee9b 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -26,9 +26,9 @@ */ package cz.crcs.ectester.applet; -import javacard.framework.*; -import javacard.security.*; -import javacardx.apdu.ExtendedLength; +import javacard.framework.APDU; +import javacard.framework.ISO7816; +import javacard.framework.ISOException; /** * Applet part of ECTester, a tool for testing Elliptic curve support on javacards. @@ -36,90 +36,9 @@ import javacardx.apdu.ExtendedLength; * @author Petr Svenda petr@svenda.com * @author Jan Jancar johny@neuromancer.sk */ -public class ECTesterApplet extends Applet implements ExtendedLength { - - // MAIN INSTRUCTION CLASS - public static final byte CLA_ECTESTERAPPLET = (byte) 0xB0; - - // INSTRUCTIONS - public static final byte INS_ALLOCATE = (byte) 0x5a; - public static final byte INS_CLEAR = (byte) 0x5b; - public static final byte INS_SET = (byte) 0x5c; - public static final byte INS_TRANSFORM = (byte) 0x5d; - public static final byte INS_GENERATE = (byte) 0x5e; - public static final byte INS_EXPORT = (byte) 0x5f; - public static final byte INS_ECDH = (byte) 0x70; - public static final byte INS_ECDH_DIRECT = (byte) 0x71; - public static final byte INS_ECDSA = (byte) 0x72; - public static final byte INS_ECDSA_SIGN = (byte) 0x73; - public static final byte INS_ECDSA_VERIFY = (byte) 0x74; - public static final byte INS_CLEANUP = (byte) 0x75; - public static final byte INS_ALLOCATE_KA = (byte) 0x76; - public static final byte INS_ALLOCATE_SIG = (byte) 0x77; - - - // PARAMETERS for P1 and P2 - public static final byte KEYPAIR_LOCAL = (byte) 0x01; - public static final byte KEYPAIR_REMOTE = (byte) 0x02; - public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE; - public static final byte EXPORT_TRUE = (byte) 0xff; - public static final byte EXPORT_FALSE = (byte) 0x00; - - // STATUS WORDS - public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1; - public static final short SW_DH_DHC_MISMATCH = (short) 0x0ee2; - public static final short SW_KEYPAIR_NULL = (short) 0x0ee3; - public static final short SW_KA_NULL = (short) 0x0ee4; - public static final short SW_SIGNATURE_NULL = (short) 0x0ee5; - public static final short SW_OBJECT_NULL = (short) 0x0ee6; - public static final short SW_Exception = (short) 0xff01; - public static final short SW_ArrayIndexOutOfBoundsException = (short) 0xff02; - public static final short SW_ArithmeticException = (short) 0xff03; - public static final short SW_ArrayStoreException = (short) 0xff04; - public static final short SW_NullPointerException = (short) 0xff05; - public static final short SW_NegativeArraySizeException = (short) 0xff06; - public static final short SW_CryptoException_prefix = (short) 0xf100; - public static final short SW_SystemException_prefix = (short) 0xf200; - public static final short SW_PINException_prefix = (short) 0xf300; - public static final short SW_TransactionException_prefix = (short) 0xf400; - public static final short SW_CardRuntimeException_prefix = (short) 0xf500; - - private static final short ARRAY_LENGTH = (short) 0xff; - private static final short APDU_MAX_LENGTH = (short) 1024; - // TEMPORARRY ARRAY IN RAM - private byte[] ramArray = null; - private byte[] ramArray2 = null; - private byte[] apduArray = null; - - private RandomData randomData = null; - - private ECKeyTester keyTester = null; - private ECKeyGenerator keyGenerator = null; - private KeyPair localKeypair = null; - private KeyPair remoteKeypair = null; - +public class ECTesterApplet extends AppletBase { protected ECTesterApplet(byte[] buffer, short offset, byte length) { - if (length > 9) { - /* - short dataOffset = offset; - // shift to privilege offset - dataOffset += (short) (1 + buffer[offset]); - // finally shift to Application specific offset - dataOffset += (short) (1 + buffer[dataOffset]); - // go to proprietary data - dataOffset++; - */ - - ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); - ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); - apduArray = JCSystem.makeTransientByteArray(APDU_MAX_LENGTH, JCSystem.CLEAR_ON_RESET); - - randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); - EC_Consts.randomData = randomData; - - keyGenerator = new ECKeyGenerator(); - keyTester = new ECKeyTester(); - } + super(buffer, offset, length); register(); } @@ -128,722 +47,16 @@ public class ECTesterApplet extends Applet implements ExtendedLength { new ECTesterApplet(bArray, bOffset, bLength); } - public void process(APDU apdu) throws ISOException { - // get the APDU buffer - byte[] apduBuffer = apdu.getBuffer(); - byte cla = apduBuffer[ISO7816.OFFSET_CLA]; - byte ins = apduBuffer[ISO7816.OFFSET_INS]; - - // ignore the applet select command dispached to the process - if (selectingApplet()) { - return; - } - - if (cla == CLA_ECTESTERAPPLET) { - try { - - AppletUtil.readAPDU(apdu, apduArray, APDU_MAX_LENGTH); - - short length = 0; - switch (ins) { - case INS_ALLOCATE_KA: - length = insAllocateKA(apdu); - break; - case INS_ALLOCATE_SIG: - length = insAllocateSig(apdu); - break; - case INS_ALLOCATE: - length = insAllocate(apdu); - break; - case INS_CLEAR: - length = insClear(apdu); - break; - case INS_SET: - length = insSet(apdu); - break; - case INS_TRANSFORM: - length = insTransform(apdu); - break; - case INS_GENERATE: - length = insGenerate(apdu); - break; - case INS_EXPORT: - length = insExport(apdu); - break; - case INS_ECDH: - length = insECDH(apdu); - break; - case INS_ECDH_DIRECT: - length = insECDH_direct(apdu); - break; - case INS_ECDSA: - length = insECDSA(apdu); - break; - case INS_ECDSA_SIGN: - length = insECDSA_sign(apdu); - break; - case INS_ECDSA_VERIFY: - length = insECDSA_verify(apdu); - break; - case INS_CLEANUP: - length = insCleanup(apdu); - break; - default: - // The INS code is not supported by the dispatcher - ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); - break; - } - apdu.setOutgoingAndSend((short) 0, length); - - } catch (ISOException e) { - throw e; // Our exception from code, just re-emit - } catch (ArrayIndexOutOfBoundsException e) { - ISOException.throwIt(SW_ArrayIndexOutOfBoundsException); - } catch (ArithmeticException e) { - ISOException.throwIt(SW_ArithmeticException); - } catch (ArrayStoreException e) { - ISOException.throwIt(SW_ArrayStoreException); - } catch (NullPointerException e) { - ISOException.throwIt(SW_NullPointerException); - } catch (NegativeArraySizeException e) { - ISOException.throwIt(SW_NegativeArraySizeException); - } catch (CryptoException e) { - ISOException.throwIt((short) (SW_CryptoException_prefix | e.getReason())); - } catch (SystemException e) { - ISOException.throwIt((short) (SW_SystemException_prefix | e.getReason())); - } catch (PINException e) { - ISOException.throwIt((short) (SW_PINException_prefix | e.getReason())); - } catch (TransactionException e) { - ISOException.throwIt((short) (SW_TransactionException_prefix | e.getReason())); - } catch (CardRuntimeException e) { - ISOException.throwIt((short) (SW_CardRuntimeException_prefix | e.getReason())); - } catch (Exception e) { - ISOException.throwIt(SW_Exception); - } - - } else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); - } - - /** - * Allocates KeyAgreement object, returns allocate SW. - * - * @param apdu DATA = byte KeyAgreementType - * @return length of response - */ - private short insAllocateKA(APDU apdu) { - short cdata = apdu.getOffsetCdata(); - byte kaType = apduArray[cdata]; - short sw = keyTester.allocateKA(kaType); - Util.setShort(apdu.getBuffer(), (short) 0, sw); - return 2; - } - - /** - * Allocates a Signature object, returns allocate SW. - * - * @param apdu DATA = byte SignatureType - * @return length of response - */ - private short insAllocateSig(APDU apdu) { - short cdata = apdu.getOffsetCdata(); - byte sigType = apduArray[cdata]; - short sw = keyTester.allocateSig(sigType); - Util.setShort(apdu.getBuffer(), (short) 0, sw); - return 2; - } - - /** - * Allocates local and remote keyPairs. - * returns allocate SWs - * - * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) - * P2 = - * DATA = short keyLength - * byte keyClass - * @return length of response - */ - private short insAllocate(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - short cdata = apdu.getOffsetCdata(); - short keyLength = Util.getShort(apduArray, cdata); - byte keyClass = apduArray[(short) (cdata + 2)]; - - return allocate(keyPair, keyLength, keyClass, apdu.getBuffer(), (short) 0); - } - - /** - * Clears local and remote keyPair's keys {@code .clearKey()}. - * returns clearKey SWs - * - * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) - * P2 = - * @return length of response - */ - private short insClear(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - - short len = 0; - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += clear(localKeypair, apdu.getBuffer(), (short) 0); - } - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += clear(remoteKeypair, apdu.getBuffer(), len); - } - - return len; - } - - /** - * Sets curve parameters on local and remote keyPairs. - * returns setCurve SWs - * - * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) - * P2 = byte curve (EC_Consts.CURVE_*) - * DATA = short params (EC_Consts.PARAMETER_* | ...) - * <p> - * if curveID = CURVE_EXTERNAL: - * [short paramLength, byte[] param], - * for all params in params, - * in order: field,a,b,g,r,k,w,s - * @return length of response - */ - private short insSet(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - byte curve = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - short params = Util.getShort(apduArray, cdata); - - short len = 0; - - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += set(localKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), (short) 0); - } - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += set(remoteKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), len); - } - - return len; - } - - /** - * Transforms curve paramaters of local and remote keyPairs. - * returns transformCurve SWs - * - * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) - * P2 = byte key (EC_Consts.KEY_* | ...) - * DATA = short params (EC_Consts.PARAMETER_* | ...) - * short transformation (EC_Consts.TRANSFORMATION_* || ...) - * @return length of response - */ - private short insTransform(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - byte key = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - short params = Util.getShort(apduArray, cdata); - short transformation = Util.getShort(apduArray, (short) (cdata + 2)); - - short len = 0; - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += transform(localKeypair, key, params, transformation, apdu.getBuffer(), (short) 0); - } - - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += transform(remoteKeypair, key, params, transformation, apdu.getBuffer(), len); - } - - return len; - } - - /** - * Generates the local and remote keyPairs. - * returns generate SWs - * - * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) - * P2 = - * @return length of response - */ - private short insGenerate(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - - short len = 0; - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += generate(localKeypair, apdu.getBuffer(), (short) 0); - } - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += generate(remoteKeypair, apdu.getBuffer(), len); - } - - return len; - } - - /** - * Exports selected key and domain parameters from the selected keyPair and key. - * - * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) - * P2 = byte key (EC_Consts.KEY_* | ...) - * DATA = short params - * @return length of response - */ - private short insExport(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - byte key = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - short params = Util.getShort(apduArray, cdata); - - short swOffset = 0; - short len = (short) (keyPair == KEYPAIR_BOTH ? 4 : 2); - - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += export(localKeypair, key, params, apdu.getBuffer(), swOffset, len); - swOffset += 2; - } - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += export(remoteKeypair, key, params, apdu.getBuffer(), swOffset, len); - } - - return len; - } - - /** - * Performs ECDH, between the pubkey specified in P1(local/remote) and the privkey specified in P2(local/remote). - * returns deriveSecret SW, {@code if(export == EXPORT_TRUE)} => short secretlen, byte[] secret - * - * @param apdu P1 = byte pubkey (KEYPAIR_*) - * P2 = byte privkey (KEYPAIR_*) - * DATA = byte export (EXPORT_TRUE || EXPORT_FALSE) - * short transformation (EC_Consts.TRANSFORMATION_* | ...) - * byte type (EC_Consts.KA_* | ...) - * @return length of response - */ - private short insECDH(APDU apdu) { - byte pubkey = apduArray[ISO7816.OFFSET_P1]; - byte privkey = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - byte export = apduArray[cdata]; - short transformation = Util.getShort(apduArray, (short) (cdata + 1)); - byte type = apduArray[(short) (cdata + 3)]; - - return ecdh(pubkey, privkey, export, transformation, type, apdu.getBuffer(), (short) 0); - } - - /** - * Performs ECDH, directly between the privkey specified in P1(local/remote) and the raw data - * - * @param apdu P1 = byte privkey (KEYPAIR_*) - * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) - * DATA = short transformation (EC_Consts.TRANSFORMATION_* | ...) - * byte type (EC_Consts.KA_* | ...) - * short length - * byte[] pubkey - * @return length of response - */ - private short insECDH_direct(APDU apdu) { - byte privkey = apduArray[ISO7816.OFFSET_P1]; - byte export = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - short transformation = Util.getShort(apduArray, cdata); - byte type = apduArray[(short) (cdata + 2)]; - short length = Util.getShort(apduArray, (short) (cdata + 3)); - - return ecdh_direct(privkey, export, transformation, type, (short) (cdata + 5), length, apdu.getBuffer(), (short) 0); - } - - /** - * Performs ECDSA signature and verification on data provided or random, using the keyPair in P1(local/remote). - * returns ecdsa SW, {@code if(export == EXPORT_TRUE)} => short signature_length, byte[] signature - * - * @param apdu P1 = byte keyPair (KEYPAIR_*) - * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) - * DATA = byte sigType - * short dataLength (00 = random data generated, !00 = data length) - * byte[] data - * @return length of response - */ - private short insECDSA(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - byte export = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - byte sigType = apduArray[cdata]; - - short len = 0; - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += ecdsa(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0); - } - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += ecdsa(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len); - } - - return len; - } - - /** - * @param apdu P1 = byte keyPair (KEYPAIR_*) - * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) - * DATA = byte sigType - * short dataLength (00 = random data generated, !00 = data length) - * byte[] data - * @return length of response - */ - private short insECDSA_sign(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - byte export = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - byte sigType = apduArray[cdata]; - - short len = 0; - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += ecdsa_sign(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0); - } - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += ecdsa_sign(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len); - } - return len; - } - - /** - * @param apdu P1 = byte keyPair (KEYPAIR_*) - * P2 = byte sigType - * DATA = short dataLength (00 = random data generated, !00 = data length) - * byte[] data - * short sigLength - * byte[] signature - * @return length of response - */ - private short insECDSA_verify(APDU apdu) { - byte keyPair = apduArray[ISO7816.OFFSET_P1]; - byte sigType = apduArray[ISO7816.OFFSET_P2]; - short cdata = apdu.getOffsetCdata(); - - short len = 0; - if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += ecdsa_verify(localKeypair, sigType, apduArray, cdata, apdu.getBuffer(), (short) 0); - } - if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += ecdsa_verify(remoteKeypair, sigType, apduArray, cdata, apdu.getBuffer(), len); - } - return len; - } - - - /** - * Performs card memory cleanup via JCSystem.requestObjectDeletion() - * - * @param apdu no data - * @return length of response - */ - private short insCleanup(APDU apdu) { - byte[] apdubuf = apdu.getBuffer(); - - return cleanup(apdubuf, (short) 0); - } - - /** - * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) - * @param keyLength key length to set - * @param keyClass key class to allocate - * @param outBuffer buffer to write sw to - * @param outOffset offset into buffer - * @return length of data written to the buffer - */ - private short allocate(byte keyPair, short keyLength, byte keyClass, byte[] outBuffer, short outOffset) { - short length = 0; - if ((keyPair & KEYPAIR_LOCAL) != 0) { - localKeypair = keyGenerator.allocatePair(keyClass, keyLength); - Util.setShort(outBuffer, outOffset, keyGenerator.getSW()); - length += 2; - } - - if ((keyPair & KEYPAIR_REMOTE) != 0) { - remoteKeypair = keyGenerator.allocatePair(keyClass, keyLength); - Util.setShort(outBuffer, (short) (outOffset + length), keyGenerator.getSW()); - length += 2; - } - - return length; - } - - /** - * @param keyPair KeyPair to clear - * @param outBuffer buffer to write sw to - * @param outOffset offset into buffer - * @return length of data written to the buffer - */ - private short clear(KeyPair keyPair, byte[] outBuffer, short outOffset) { - short sw = keyGenerator.clearPair(keyPair, EC_Consts.KEY_BOTH); - Util.setShort(outBuffer, outOffset, sw); - - return 2; - } - - /** - * @param keyPair KeyPair to set params on - * @param curve curve to set (EC_Consts.CURVE_*) - * @param params parameters to set (EC_Consts.PARAMETER_* | ...) - * @param inBuffer buffer to read params from - * @param inOffset input offset in buffer - * @param outBuffer buffer to write sw to - * @param outOffset output offset in buffer - * @return length of data written to the buffer - */ - private short set(KeyPair keyPair, byte curve, short params, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { - short sw = ISO7816.SW_NO_ERROR; - - switch (curve) { - case EC_Consts.CURVE_default: - //default, dont set anything - break; - case EC_Consts.CURVE_external: - //external - sw = keyGenerator.setExternalCurve(keyPair, params, inBuffer, inOffset); - break; - default: - //custom - sw = keyGenerator.setCurve(keyPair, curve, params, ramArray, (short) 0); - break; - } - - Util.setShort(outBuffer, outOffset, sw); - return 2; - } - - /** - * @param keyPair KeyPair to transform - * @param key key to transform (EC_Consts.KEY_* | ...) - * @param params parameters to transform (EC_Consts.PARAMETER_* | ...) - * @param transformation transformation type (EC_Consts.TRANSFORMATION_*) - * @param outBuffer buffer to output sw to - * @param outOffset output offset in buffer - * @return length of data written to the buffer - */ - private short transform(KeyPair keyPair, byte key, short params, short transformation, byte[] outBuffer, short outOffset) { - short sw = keyGenerator.transformCurve(keyPair, key, params, transformation, ramArray, (short) 0); - Util.setShort(outBuffer, outOffset, sw); - return 2; - } - - /** - * @param keyPair KeyPair to generate - * @param outBuffer buffer to output sw to - * @param outOffset output offset in buffer - * @return length of data written to the buffer - */ - private short generate(KeyPair keyPair, byte[] outBuffer, short outOffset) { - short sw = keyGenerator.generatePair(keyPair); - Util.setShort(outBuffer, outOffset, sw); - - return 2; - } - - /** - * @param keyPair KeyPair to export from - * @param key which key to export from (EC_Consts.KEY_PUBLIC | EC_Consts.KEY_PRIVATE) - * @param params which params to export (EC_Consts.PARAMETER_* | ...) - * @param outBuffer buffer to export params to - * @param swOffset offset to output sw to buffer - * @param outOffset output offset in buffer - * @return length of data written to the buffer - */ - private short export(KeyPair keyPair, byte key, short params, byte[] outBuffer, short swOffset, short outOffset) { - short length = 0; - - short sw = ISO7816.SW_NO_ERROR; - if ((key & EC_Consts.KEY_PUBLIC) != 0) { - //export params from public - length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PUBLIC, params, outBuffer, outOffset); - sw = keyGenerator.getSW(); - } - if ((key & EC_Consts.KEY_PRIVATE) != 0 && sw == ISO7816.SW_NO_ERROR) { - //export params from private - length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PRIVATE, params, outBuffer, (short) (outOffset + length)); - sw = keyGenerator.getSW(); - } - Util.setShort(outBuffer, swOffset, sw); - - return length; - } - - /** - * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) - * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) - * @param export whether to export ECDH secret - * @param transformation whether to transform the pubkey before ECDH - * @param type KeyAgreement type to test - * @param outBuffer buffer to write sw to, and export ECDH secret {@code if(export == EXPORT_TRUE)} - * @param outOffset output offset in buffer - * @return length of data written to the buffer - */ - private short ecdh(byte pubkey, byte privkey, byte export, short transformation, byte type, byte[] outBuffer, short outOffset) { - short length = 0; - - KeyPair pub = ((pubkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; - KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; - - short secretLength = 0; - if (keyTester.getKaType() == type) { - secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation); - } else { - short allocateSW = keyTester.allocateKA(type); - if (allocateSW == ISO7816.SW_NO_ERROR) { - secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation); - } - } - Util.setShort(outBuffer, outOffset, keyTester.getSW()); - length += 2; - - if ((export == EXPORT_TRUE)) { - Util.setShort(outBuffer, (short) (outOffset + length), secretLength); - length += 2; - Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength); - length += secretLength; - } - - return length; - } - - private short ecdh_direct(byte privkey, byte export, short transformation, byte type, short keyOffset, short keyLength, byte[] outBuffer, short outOffset) { - short length = 0; - - KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; - - short secretLength = 0; - if (keyTester.getKaType() == type) { - secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation); - } else { - short allocateSW = keyTester.allocateKA(type); - if (allocateSW == ISO7816.SW_NO_ERROR) { - secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation); - } - } - - Util.setShort(outBuffer, outOffset, keyTester.getSW()); - length += 2; - - if ((export == EXPORT_TRUE)) { - Util.setShort(outBuffer, (short) (outOffset + length), secretLength); - length += 2; - Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength); - length += secretLength; - } - return length; - } - - /** - * @param sign keyPair to use for signing and verification - * @param sigType Signature type to use - * @param export whether to export ECDSA signature - * @param inBuffer buffer to read dataLength and data to sign from - * @param inOffset input offset in buffer - * @param outBuffer buffer to write sw to, and export ECDSA signature {@code if(export == EXPORT_TRUE)} - * @param outOffset output offset in buffer - * @return length of data written to the buffer - */ - private short ecdsa(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { - short length = 0; - - short dataLength = Util.getShort(inBuffer, inOffset); - if (dataLength == 0) { //no data to sign - //generate random - dataLength = 64; - randomData.generateData(ramArray, (short) 0, dataLength); - } else { - Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength); - } - - short signatureLength = 0; - if (keyTester.getSigType() == sigType) { - signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); - } else { - short allocateSW = keyTester.allocateSig(sigType); - if (allocateSW == ISO7816.SW_NO_ERROR) { - signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); - } - } - Util.setShort(outBuffer, outOffset, keyTester.getSW()); - length += 2; - - if (export == EXPORT_TRUE) { - Util.setShort(outBuffer, (short) (outOffset + length), signatureLength); - length += 2; - - Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength); - length += signatureLength; - } - - return length; - } - - private short ecdsa_sign(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { - short length = 0; - - short dataLength = Util.getShort(inBuffer, inOffset); - if (dataLength == 0) { //no data to sign - //generate random - dataLength = 64; - randomData.generateData(ramArray, (short) 0, dataLength); - } else { - Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength); - } - - short signatureLength = 0; - if (keyTester.getSigType() == sigType) { - signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); - } else { - short allocateSW = keyTester.allocateSig(sigType); - if (allocateSW == ISO7816.SW_NO_ERROR) { - signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); - } - } - Util.setShort(outBuffer, outOffset, keyTester.getSW()); - length += 2; - - if (export == EXPORT_TRUE) { - Util.setShort(outBuffer, (short) (outOffset + length), signatureLength); - length += 2; - - Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength); - length += signatureLength; - } - - return length; + short getOffsetCdata(APDU apdu) { + return ISO7816.OFFSET_CDATA; } - private short ecdsa_verify(KeyPair verify, byte sigType, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) { - short length = 0; - - short dataLength = Util.getShort(inBuffer, inOffset); - short dataOffset = (short) (inOffset + 2); - short sigLength = Util.getShort(inBuffer, (short) (dataOffset + dataLength)); - short sigOffset = (short) (dataOffset + dataLength + 2); - - if (keyTester.getSigType() == sigType) { - keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength); - } else { - short allocateSW = keyTester.allocateSig(sigType); - if (allocateSW == ISO7816.SW_NO_ERROR) { - keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength); - } - } - Util.setShort(outBuffer, outOffset, keyTester.getSW()); - length += 2; - - return length; + short getIncomingLength(APDU apdu) { + byte[] apduBuffer = apdu.getBuffer(); + return apduBuffer[ISO7816.OFFSET_LC]; } - /** - * @param buffer buffer to write sw to - * @param offset output offset in buffer - * @return length of data written to the buffer - */ - private short cleanup(byte[] buffer, short offset) { - short sw = ISO7816.SW_NO_ERROR; - try { - if (JCSystem.isObjectDeletionSupported()) - JCSystem.requestObjectDeletion(); - } catch (CardRuntimeException crex) { - sw = crex.getReason(); - } - - Util.setShort(buffer, offset, sw); - return 2; + short getBase() { + return AppletBase.BASE_221; } } diff --git a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java new file mode 100644 index 0000000..83e0851 --- /dev/null +++ b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java @@ -0,0 +1,61 @@ +/* + * ECTester, tool for testing Elliptic curve cryptography implementations. + * Copyright (c) 2016-2018 Petr Svenda <petr@svenda.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* + * PACKAGEID: 4543546573746572 + * APPLETID: 45435465737465723031 + */ +package cz.crcs.ectester.applet; + +import javacard.framework.APDU; +import javacard.framework.ISOException; +import javacardx.apdu.ExtendedLength; + +/** + * Applet part of ECTester, a tool for testing Elliptic curve support on javacards. + * + * @author Petr Svenda petr@svenda.com + * @author Jan Jancar johny@neuromancer.sk + */ +public class ECTesterAppletExtended extends AppletBase implements ExtendedLength { + protected ECTesterAppletExtended(byte[] buffer, short offset, byte length) { + super(buffer, offset, length); + register(); + } + + public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException { + // applet instance creation + new ECTesterAppletExtended(bArray, bOffset, bLength); + } + + short getOffsetCdata(APDU apdu) { + return apdu.getOffsetCdata(); + } + + short getIncomingLength(APDU apdu) { + return apdu.getIncomingLength(); + } + + short getBase() { + return AppletBase.BASE_222; + } +} diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 0c04453..c3c0e13 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -144,9 +144,8 @@ public class ECTesterReader { cardManager.send(SELECT_ECTESTERAPPLET); } - // Setup logger, testWriter and respWriter + // Setup logger and respWriter logger = new OutputLogger(true, cfg.log); - respWriter = new ResponseWriter(logger.getPrintStream()); //do action diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 5a4af21..d2e08ee 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -864,5 +864,33 @@ public abstract class Command implements Cloneable { return "Request JCSystem object deletion"; } } + + /** + * + */ + public static class GetInfo extends Command { + + /** + * @param cardManager cardManager to send APDU through + */ + public GetInfo(CardMngr cardManager) { + super(cardManager); + + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0); + } + + @Override + public Response.GetInfo send() throws CardException { + long elapsed = -System.nanoTime(); + ResponseAPDU response = cardManager.send(cmd); + elapsed += System.nanoTime(); + return new Response.GetInfo(response, getDescription(), elapsed); + } + + @Override + public String getDescription() { + return "Get applet info"; + } + } } diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 4814e41..b0cd0f8 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -79,6 +79,10 @@ public abstract class Response { return resp; } + public byte[] getData() { + return resp.getData(); + } + public long getDuration() { return time; } @@ -424,4 +428,45 @@ public abstract class Response { parse(1, 0); } } + + /** + * + */ + public static class GetInfo extends Response { + private short base; + private short jcVersion; + private short cleanupSupport; + + public GetInfo(ResponseAPDU response, String description, long time) { + super(response, description, time); + + parse(1, 1); + int offset = 2 + 2 + getParamLength(0); + byte[] data = getData(); + base = ByteUtil.getShort(data, offset); + offset += 2; + jcVersion = ByteUtil.getShort(data, offset); + offset += 2; + cleanupSupport = ByteUtil.getShort(data, offset); + } + + public String getVersion() { + return new String(getParam(0)); + } + + public short getBase() { + return base; + } + + public float getJavaCardVersion() { + byte major = (byte) (jcVersion >> 8); + byte minor = (byte) (jcVersion & 0xff); + int minorSize = (int) Math.ceil(Math.log10(minor)); + return (major + ((float) (minor) / (minorSize * 10))); + } + + public boolean getCleanupSupport() { + return cleanupSupport == 1; + } + } } diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java index e495b00..60ab08c 100644 --- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -10,6 +10,7 @@ import cz.crcs.ectester.common.util.CardUtil; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; import javacard.security.KeyPair; import java.util.LinkedList; @@ -33,6 +34,10 @@ public class CardDefaultSuite extends CardTestSuite { @Override protected void runTests() throws Exception { + CommandTest getInfo = runTest(CommandTest.expect(new Command.GetInfo(this.card), ExpectedValue.SUCCESS)); + Response.GetInfo info = (Response.GetInfo) getInfo.getResponse(); + doTest(CompoundTest.all(ExpectedValue.SUCCESS, String.format("Get applet info: %s; %.1f; %s", info.getVersion(), info.getJavaCardVersion(), info.getBase() == ECTesterApplet.BASE_221 ? "basic" : "extended"), getInfo)); + if (cfg.primeField) { runDefault(KeyPair.ALG_EC_FP); } |
