aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/applets/SimpleECCApplet.java165
-rw-r--r--src/simpleapdu/SimpleAPDU.java102
2 files changed, 222 insertions, 45 deletions
diff --git a/src/applets/SimpleECCApplet.java b/src/applets/SimpleECCApplet.java
index c3aa700..5519104 100644
--- a/src/applets/SimpleECCApplet.java
+++ b/src/applets/SimpleECCApplet.java
@@ -23,6 +23,7 @@ public class SimpleECCApplet extends javacard.framework.Applet
final static byte INS_TESTECSUPPORTALL_FP = (byte) 0x5e;
final static byte INS_TESTECSUPPORTALL_F2M = (byte) 0x5f;
final static byte INS_TESTEC_GENERATEINVALID_FP = (byte) 0x70;
+ final static byte INS_TESTEC_LASTUSEDPARAMS = (byte) 0x40;
@@ -43,6 +44,8 @@ public class SimpleECCApplet extends javacard.framework.Applet
public final static byte ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE = (byte) 0xc6;
public final static byte ECTEST_ECDH_AGREEMENT_VALID_POINT = (byte) 0xc7;
public final static byte ECTEST_ECDH_AGREEMENT_INVALID_POINT = (byte) 0xc8;
+ public final static byte ECTEST_EXECUTED_REPEATS = (byte) 0xc9;
+ public final static byte ECTEST_DH_GENERATESECRET = (byte) 0xca;
public final static short FLAG_ECTEST_ALLOCATE_KEYPAIR = (short) 0x0001;
public final static short FLAG_ECTEST_GENERATE_KEYPAIR_DEFCURVE = (short) 0x0002;
@@ -55,8 +58,15 @@ public class SimpleECCApplet extends javacard.framework.Applet
public final static short FLAG_ECTEST_ALL = (short) 0x00ff;
+ public final static short CORRUPT_B_FULLRANDOM = (short) 0x0001;
+ public final static short CORRUPT_B_ONEBYTERANDOM = (short) 0x0002;
+ public final static short CORRUPT_B_LASTBYTEINCREMENT = (short) 0x0003;
+
+
+
public final static short SW_SKIPPED = (short) 0x0ee1;
public final static short SW_KEYPAIR_GENERATED_INVALID = (short) 0x0ee2;
+ public final static short SW_INVALID_CORRUPTION_TYPE = (short) 0x0ee3;
/*
public static final byte[] EC192_FP_PUBLICW = new byte[]{
(byte) 0x04, (byte) 0xC9, (byte) 0xC0, (byte) 0xED, (byte) 0xFB, (byte) 0x27,
@@ -105,6 +115,8 @@ public class SimpleECCApplet extends javacard.framework.Applet
private byte m_ramArray2[] = null;
// PERSISTENT ARRAY IN EEPROM
private byte m_dataArray[] = null;
+
+ short m_lenB = 0;
protected SimpleECCApplet(byte[] buffer, short offset, byte length) {
short dataOffset = offset;
@@ -168,7 +180,9 @@ public class SimpleECCApplet extends javacard.framework.Applet
case INS_TESTEC_GENERATEINVALID_FP:
TestEC_FP_GenerateInvalidCurve(apdu);
break;
-
+ case INS_TESTEC_LASTUSEDPARAMS:
+ TestECSupportInvalidCurve_lastUsedParams(apdu);
+ break;
/*
case INS_ALLOCATEKEYPAIRS:
AllocateKeyPairs(apdu);
@@ -453,15 +467,23 @@ public class SimpleECCApplet extends javacard.framework.Applet
byte[] apdubuf = apdu.getBuffer();
short len = apdu.setIncomingAndReceive();
+ short offset = ISO7816.OFFSET_CDATA;
+ short repeats = Util.getShort(apdubuf, offset);
+ offset += 2;
+ short corruptionType = Util.getShort(apdubuf, offset);
+ offset += 2;
+ byte bRewindOnSuccess = apdubuf[offset];
+ offset++;
+
short dataOffset = 0;
// FP
- dataOffset += TestECSupportInvalidCurve(KeyPair.ALG_EC_FP, (short) 160, apdubuf, dataOffset, apdubuf[ISO7816.OFFSET_P1]);
+ dataOffset += TestECSupportInvalidCurve(KeyPair.ALG_EC_FP, (short) 160, apdubuf, dataOffset, repeats, corruptionType, bRewindOnSuccess);
apdu.setOutgoingAndSend((short) 0, dataOffset);
}
- short TestECSupportInvalidCurve(byte keyClass, short keyLen, byte[] buffer, short bufferOffset, short repeats) {
+ short TestECSupportInvalidCurve(byte keyClass, short keyLen, byte[] buffer, short bufferOffset, short repeats, short corruptionType, byte bRewindOnSuccess) {
short baseOffset = bufferOffset;
short testFlags = FLAG_ECTEST_ALL;
@@ -476,6 +498,9 @@ public class SimpleECCApplet extends javacard.framework.Applet
bufferOffset++;
Util.setShort(buffer, bufferOffset, keyLen);
bufferOffset += 2;
+
+ short numExecutionsOffset = bufferOffset; // num executions to be stored later
+ bufferOffset += 2;
//
// 1. Allocate KeyPair object
@@ -516,35 +541,112 @@ public class SimpleECCApplet extends javacard.framework.Applet
//
EC_Consts.m_random = randomData;
EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, keyClass, keyLen, m_ramArray);
- short lenB = ecPubKey.getB(m_ramArray, (short) 0); // store valid B
-
+
+ m_lenB = ecPubKey.getB(m_ramArray, (short) 0); // store valid B
+ Util.arrayCopyNonAtomic(m_ramArray, (short) 0, m_ramArray2, (short) 0, m_lenB); // also in m_ramArray2
+
short startOffset = bufferOffset;
-// for (short i = 0; i < repeats; i++) {
- for (short i = 0; i < (short) 1000; i++) {
+ short i;
+ for (i = 0; i < repeats; i++) {
if ((testFlags & FLAG_ECTEST_SET_INVALIDCURVE) != (short) 0) {
- bufferOffset = startOffset;
-
+ if (bRewindOnSuccess == 1) {
+ // if nothing unexpected happened, rewind bufferOffset back again
+ bufferOffset = startOffset;
+ }
+
+ // Store valid curve B param
+ ecPubKey.getB(m_ramArray, (short) 0); // store valid B
+ Util.arrayCopyNonAtomic(m_ramArray, (short) 0, m_ramArray2, (short) 0, m_lenB); // also in m_ramArray2
+
// set invalid curve
buffer[bufferOffset] = ECTEST_SET_INVALIDCURVE;
bufferOffset++;
- randomData.generateData(m_ramArray2, (short) 0, lenB);
- ecPubKey.setB(m_ramArray2, (short) 0, lenB);
- ecPrivKey.setB(m_ramArray2, (short) 0, lenB);
- Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
- bufferOffset += 2;
+ // Supported types of invalid curve:
+ // 1. Completely random B
+ // 2. Valid B but with one random byte randomly changed
+ // 3. Valid B but with last byte incremented
+ switch (corruptionType) {
+ case CORRUPT_B_FULLRANDOM:
+ randomData.generateData(m_ramArray2, (short) 0, m_lenB);
+ break;
+ case CORRUPT_B_ONEBYTERANDOM:
+ // Copy valid B into m_ramArray2
+ Util.arrayCopyNonAtomic(m_ramArray, (short) 0, m_ramArray2, (short) 0, m_lenB);
+ // Generate random position and one random byte for subsequent change
+ // Note - we are using same array m_ramArray2, but in area unsued by stored B
+ randomData.generateData(m_ramArray2, m_lenB, (short) 2);
+
+ short rngPos = m_ramArray2[m_lenB]; // random position (within B)
+ if (rngPos < 0) { rngPos = (short) -rngPos; } // make it positive
+ rngPos %= m_lenB;
+ m_ramArray2[rngPos] = m_ramArray2[(short) (m_lenB + 1)]; // set random byte on random position
+ // Make sure its not the valid byte again
+ if (m_ramArray[rngPos] == m_ramArray2[rngPos]) {
+ m_ramArray2[rngPos] += 1; // if yes, just increment
+ }
+
+ break;
+ case CORRUPT_B_LASTBYTEINCREMENT:
+ m_ramArray2[(short) (m_lenB - 1)] += 1;
+ // Make sure its not the valid byte again
+ if (m_ramArray[(short) (m_lenB - 1)] == m_ramArray2[(short) (m_lenB - 1)]) {
+ m_ramArray2[(short) (m_lenB - 1)] += 1; // if yes, increment once more
+ }
+ break;
+ default:
+ ISOException.throwIt(SW_INVALID_CORRUPTION_TYPE);
+ break;
+ }
+
+
+ // Set corrupted B parameter
+ try {
+ ecPubKey.setB(m_ramArray2, (short) 0, m_lenB);
+ ecPrivKey.setB(m_ramArray2, (short) 0, m_lenB);
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); // ok if setB itself will not emit exception
+ bufferOffset += 2;
+ }catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason());
+ bufferOffset += 2;
+ // if we reach this line, we are interested in value of B that caused incorrect response
+ break; // stop execution, return B
+ }catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ // if we reach this line, we are interested in value of B that caused incorrect response
+ break; // stop execution, return B
+ }
+
// Gen key pair with invalid curve
try {
buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE;
bufferOffset++;
// Should fail
ecKeyPair.genKeyPair();
- // If this line is reached, we generated valid key pair - what should not happen
- Util.setShort(buffer, bufferOffset, SW_KEYPAIR_GENERATED_INVALID);
+ // If this line is reached, we generated key pair - what should not happen
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
bufferOffset += 2;
+
// if we reach this line, we are interested in value of B
- Util.arrayCopyNonAtomic(m_ramArray2, (short) 0, buffer, bufferOffset, lenB);
- bufferOffset += lenB;
+ try {
+ buffer[bufferOffset] = ECTEST_DH_GENERATESECRET;
+ bufferOffset++;
+ ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate();
+ if (dhKeyAgreement == null) {
+ dhKeyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
+ }
+ dhKeyAgreement.init(ecPrivKey);
+ short lenW = ecPubKey.getW(m_ramArray2, (short) 0); // store valid B
+ dhKeyAgreement.generateSecret(m_ramArray2, (short) 0, lenW, m_ramArray, (short) 0);
+ } catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason());
+ bufferOffset += 2;
+ } catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ }
+
break; // stop execution, return B
} catch (CryptoException e) {
Util.setShort(buffer, bufferOffset, e.getReason());
@@ -555,13 +657,14 @@ public class SimpleECCApplet extends javacard.framework.Applet
}
//
- // Generate keypair with valid curve
+ // Generate keypair with valid curve - to check that whole engine is not somehow blocked
+ // after previous attempt with invalid curve
//
// set valid curve
buffer[bufferOffset] = ECTEST_SET_VALIDCURVE;
bufferOffset++;
- ecPubKey.setB(m_ramArray, (short) 0, lenB); // valid B
- ecPrivKey.setB(m_ramArray, (short) 0, lenB);
+ EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, keyClass, keyLen, m_ramArray);
+
Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
bufferOffset += 2;
@@ -571,15 +674,19 @@ public class SimpleECCApplet extends javacard.framework.Applet
bufferOffset++;
// Should succeed
ecKeyPair.genKeyPair();
- // If this line is reached, we generated valid key pair
+ // If this line is reached, we generated valid key pair (expected)
Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
bufferOffset += 2;
} catch (CryptoException e) {
Util.setShort(buffer, bufferOffset, e.getReason());
bufferOffset += 2;
+ // if we reach this line, we are interested in value of B that caused incorrect response
+ break; // stop execution, return B
} catch (Exception e) {
Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
bufferOffset += 2;
+ // if we reach this line, we are interested in value of B that caused incorrect response
+ break; // stop execution, return B
}
// If we reach this line => everything was as expected
@@ -591,9 +698,23 @@ public class SimpleECCApplet extends javacard.framework.Applet
}
}
+ // Set number of executed repeats
+ Util.setShort(buffer, numExecutionsOffset, i);
+
return (short) (bufferOffset - baseOffset);
}
+ void TestECSupportInvalidCurve_lastUsedParams(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+ apdu.setIncomingAndReceive();
+
+ short offset = 0;
+ Util.arrayCopyNonAtomic(m_ramArray2, (short) 0, apdubuf, offset, m_lenB);
+ offset += m_lenB;
+
+ apdu.setOutgoingAndSend((short) 0, offset);
+ }
+
void AllocateKeyPairReturnDefCourve(APDU apdu) {
byte[] apdubuf = apdu.getBuffer();
apdu.setIncomingAndReceive();
diff --git a/src/simpleapdu/SimpleAPDU.java b/src/simpleapdu/SimpleAPDU.java
index 5898916..eb6a1b4 100644
--- a/src/simpleapdu/SimpleAPDU.java
+++ b/src/simpleapdu/SimpleAPDU.java
@@ -7,6 +7,7 @@ import javacard.framework.ISO7816;
import javacard.security.CryptoException;
import javacard.security.KeyPair;
import javax.smartcardio.ResponseAPDU;
+import org.bouncycastle.util.Arrays;
/**
*
@@ -20,12 +21,31 @@ public class SimpleAPDU {
private static byte TESTECSUPPORTALL_FP[] = {(byte) 0xB0, (byte) 0x5E, (byte) 0x00, (byte) 0x00, (byte) 0x00};
private static byte TESTECSUPPORTALL_F2M[] = {(byte) 0xB0, (byte) 0x5F, (byte) 0x00, (byte) 0x00, (byte) 0x00};
- private static byte TESTECSUPPORTALL_FP_KEYGEN_INVALIDCURVEB[] = {(byte) 0xB0, (byte) 0x70, (byte) 0x10, (byte) 0x00, (byte) 0x00};
+ private static byte TESTECSUPPORTALL_LASTUSEDPARAMS[] = {(byte) 0xB0, (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x00};
+
+ private static byte TESTECSUPPORTALL_FP_KEYGEN_INVALIDCURVEB[] = {(byte) 0xB0, (byte) 0x70, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
static short getShort(byte[] array, int offset) {
return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF));
}
+ static void setShort(byte[] array, int offset, short value) {
+ array[offset + 1] = (byte) (value & 0xFF);
+ array[offset] = (byte) ((value >> 8) & 0xFF);
+ }
+ static void testFPkeyGen_setNumRepeats(byte[] apduArray, short numRepeats) {
+ // num repeats starts at index 5
+ setShort(apduArray, 5, numRepeats);
+ }
+ static void testFPkeyGen_rewindOnSuccess(byte[] apduArray, boolean bRewind) {
+ // rewind info at index 7
+ apduArray[7] = bRewind ? (byte) 1 : (byte) 0;
+ }
+ static void testFPkeyGen_setCorruptionType(byte[] apduArray, short corruptionType) {
+ // corruptionType starts at index 7
+ setShort(apduArray, 7, corruptionType);
+ }
+
public static void main(String[] args) {
try {
//
@@ -34,9 +54,18 @@ public class SimpleAPDU {
if (cardManager.ConnectToCard()) {
// Select our application on card
cardManager.sendAPDU(SELECT_ECTESTERAPPLET);
- // Test setting invalid curves
- ResponseAPDU resp_fp_keygen = cardManager.sendAPDU(TESTECSUPPORTALL_FP_KEYGEN_INVALIDCURVEB);
+
+ // Test setting invalid parameter B of curev
+ byte[] testAPDU = Arrays.clone(TESTECSUPPORTALL_FP_KEYGEN_INVALIDCURVEB);
+ //testFPkeyGen_setCorruptionType(testAPDU, SimpleECCApplet.CORRUPT_B_LASTBYTEINCREMENT);
+ testFPkeyGen_setCorruptionType(testAPDU, SimpleECCApplet.CORRUPT_B_ONEBYTERANDOM);
+ //testFPkeyGen_setCorruptionType(testAPDU, SimpleECCApplet.CORRUPT_B_FULLRANDOM);
+ testFPkeyGen_setNumRepeats(testAPDU, (short) 1000);
+ testFPkeyGen_rewindOnSuccess(testAPDU, false);
+ ResponseAPDU resp_fp_keygen = cardManager.sendAPDU(testAPDU);
+ ResponseAPDU resp_keygen_params = cardManager.sendAPDU(TESTECSUPPORTALL_LASTUSEDPARAMS);
PrintECKeyGenInvalidCurveB(resp_fp_keygen);
+ PrintECKeyGenInvalidCurveB_lastUserParams(resp_keygen_params);
// Test support for different types of curves
ResponseAPDU resp_fp = cardManager.sendAPDU(TESTECSUPPORTALL_FP);
@@ -44,7 +73,7 @@ public class SimpleAPDU {
PrintECSupport(resp_fp);
PrintECSupport(resp_f2m);
-
+
cardManager.DisconnectFromCard();
} else {
@@ -79,6 +108,12 @@ public class SimpleAPDU {
if (code == SimpleECCApplet.SW_SKIPPED) {
codeStr = "skipped";
}
+ if (code == SimpleECCApplet.SW_KEYPAIR_GENERATED_INVALID) {
+ codeStr = "SW_KEYPAIR_GENERATED_INVALID";
+ }
+ if (code == SimpleECCApplet.SW_INVALID_CORRUPTION_TYPE) {
+ codeStr = "SW_INVALID_CORRUPTION_TYPE";
+ }
return String.format("fail\t(%s,\t0x%4x)", codeStr, code);
}
}
@@ -89,26 +124,31 @@ public class SimpleAPDU {
MUST_FAIL
}
static int VerifyPrintResult(String message, byte expectedTag, byte[] buffer, int bufferOffset, ExpResult expRes) {
- if (buffer[bufferOffset] != expectedTag) {
- System.out.println("ERROR: mismatched tag");
- assert(buffer[bufferOffset] == expectedTag);
- }
- bufferOffset++;
- short resCode = getShort(buffer, bufferOffset);
- bufferOffset += 2;
-
- boolean bHiglight = false;
- if ((expRes == ExpResult.MUST_FAIL) && (resCode == ISO7816.SW_NO_ERROR)) {
- bHiglight = true;
- }
- if ((expRes == ExpResult.SHOULD_SUCCEDD) && (resCode != ISO7816.SW_NO_ERROR)) {
- bHiglight = true;
- }
- if (bHiglight) {
- System.out.println(String.format("!! %-50s%s", message, getPrintError(resCode)));
+ if (bufferOffset >= buffer.length) {
+ System.out.println("No more data returned");
}
else {
- System.out.println(String.format(" %-50s%s", message, getPrintError(resCode)));
+ if (buffer[bufferOffset] != expectedTag) {
+ System.out.println("ERROR: mismatched tag");
+ assert(buffer[bufferOffset] == expectedTag);
+ }
+ bufferOffset++;
+ short resCode = getShort(buffer, bufferOffset);
+ bufferOffset += 2;
+
+ boolean bHiglight = false;
+ if ((expRes == ExpResult.MUST_FAIL) && (resCode == ISO7816.SW_NO_ERROR)) {
+ bHiglight = true;
+ }
+ if ((expRes == ExpResult.SHOULD_SUCCEDD) && (resCode != ISO7816.SW_NO_ERROR)) {
+ bHiglight = true;
+ }
+ if (bHiglight) {
+ System.out.println(String.format("!! %-50s%s", message, getPrintError(resCode)));
+ }
+ else {
+ System.out.println(String.format(" %-50s%s", message, getPrintError(resCode)));
+ }
}
return bufferOffset;
}
@@ -139,7 +179,7 @@ public class SimpleAPDU {
bufferOffset = VerifyPrintResult("Generate key with valid curve:", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD);
bufferOffset = VerifyPrintResult("ECDH agreement with valid point:", SimpleECCApplet.ECTEST_ECDH_AGREEMENT_VALID_POINT, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD);
bufferOffset = VerifyPrintResult("ECDH agreement with invalid point (fail is good):", SimpleECCApplet.ECTEST_ECDH_AGREEMENT_INVALID_POINT, buffer, bufferOffset, ExpResult.MUST_FAIL);
- bufferOffset = VerifyPrintResult("Set invalid custom curve (my fail):", SimpleECCApplet.ECTEST_SET_INVALIDCURVE, buffer, bufferOffset, ExpResult.MAY_FAIL);
+ bufferOffset = VerifyPrintResult("Set invalid custom curve (may fail):", SimpleECCApplet.ECTEST_SET_INVALIDCURVE, buffer, bufferOffset, ExpResult.MAY_FAIL);
bufferOffset = VerifyPrintResult("Generate key with invalid curve (fail is good):", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE, buffer, bufferOffset, ExpResult.MUST_FAIL);
System.out.println();
@@ -167,6 +207,11 @@ public class SimpleAPDU {
System.out.println(String.format("%-53s%d bits", "EC key length (bits):", keyLen));
bufferOffset += 2;
+ short numRepeats = getShort(buffer, bufferOffset);
+ bufferOffset += 2;
+ System.out.println(String.format("Executed repeats before unexpected error: %d times", numRepeats));
+
+
bufferOffset = VerifyPrintResult("KeyPair object allocation:", SimpleECCApplet.ECTEST_ALLOCATE_KEYPAIR, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD);
while (bufferOffset < buffer.length) {
bufferOffset = VerifyPrintResult("Set invalid custom curve:", SimpleECCApplet.ECTEST_SET_INVALIDCURVE, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD);
@@ -178,4 +223,15 @@ public class SimpleAPDU {
System.out.println();
}
}
+
+ static void PrintECKeyGenInvalidCurveB_lastUserParams(ResponseAPDU resp) {
+ byte[] buffer = resp.getData();
+ short offset = 0;
+ System.out.print("Last used value of B: ");
+ while (offset < buffer.length) {
+ System.out.print(String.format("%x ", buffer[offset]));
+ offset++;
+ }
+
+ }
}