Skip to content

Commit b91626e

Browse files
author
Your Name
committed
Support jcardsim and J3H081
jcardsim's PersistentSimulatorRuntime cannot persist Signature objects, so make those temporary and not part of the class object. Additionally, allow skipping checks for RSA4096 and for RSA PSS, as even just testing them can prevent applet installation on certain cards (J3H081).
1 parent b22f0ee commit b91626e

File tree

4 files changed

+90
-50
lines changed

4 files changed

+90
-50
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
ant-javacard.jar
21
doc
32
*.swp
43
*.orig
54
*.un~
65
*.cap
6+
*.jar

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,31 @@ After cloning the IsoApplet repository, all you have to do is:
3737
# Installation
3838
Install the CAP-file (IsoApplet.cap) to your Java Card smart card (e.g. with [GlobalPlatformPro](https://github.com/martinpaljak/GlobalPlatformPro)).
3939

40+
# Using with jcardsim
41+
Make sure to install the appropriate vsmartcard package. On Debian/Ubuntu, this is called vsmartcard-vpcd. You may need to restart pcscd after installing it. Note: This is only appropriate for development machines; it creates an open listening socket with no authentication that pcscd exposes as the first reader so it is trivial to MitM for an attacker.
42+
43+
Setup a jcardsim.cfg file like so:
44+
```
45+
com.licel.jcardsim.card.applet.0.AID=F276A288BCFBA69D34F31001
46+
com.licel.jcardsim.card.applet.0.Class=xyz.wendland.javacard.pki.isoapplet.IsoApplet
47+
com.licel.jcardsim.terminal.type=2
48+
com.licel.jcardsim.vsmartcard.host=127.0.0.1
49+
com.licel.jcardsim.vsmartcard.port=35963
50+
```
51+
52+
Run jcardsim with the IsoApplet.jar file on the path:
53+
```java -cp IsoApplet.jar:jcardsim-3.0.5-SNAPSHOT.jar com.licel.jcardsim.remote.VSmartCard jcardsim.cfg```
54+
55+
Instantiate the applet in jcardsim (this example uses gpshell):
56+
```
57+
echo 'establish_context
58+
card_connect
59+
send_apdu -sc 0 -APDU 80b800000d0cF276A288BCFBA69D34F31001
60+
card_disconnect
61+
release_context' | gpshell
62+
```
63+
64+
Now you should be able to use pkcs15-init and friends.
65+
4066
**Have a look at the wiki for more information:** https://github.com/philipWendland/IsoApplet/wiki
4167

build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<target name="dist" description="generate the distribution">
99
<tstamp/>
1010
<javacard jckit="ext/sdks/jc310r20210706_kit">
11-
<cap targetsdk="ext/sdks/jc304_kit" aid="f2:76:a2:88:bc:fb:a6:9d:34:f3:10" output="IsoApplet.cap" sources="src" version="1.0">
11+
<cap targetsdk="ext/sdks/jc304_kit" aid="f2:76:a2:88:bc:fb:a6:9d:34:f3:10" output="IsoApplet.cap" sources="src" version="1.0" jar="IsoApplet.jar">
1212
<applet class="xyz.wendland.javacard.pki.isoapplet.IsoApplet" aid="f2:76:a2:88:bc:fb:a6:9d:34:f3:10:01"/>
1313
</cap>
1414
</javacard>

src/xyz/wendland/javacard/pki/isoapplet/IsoApplet.java

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import javacard.framework.ISO7816;
2424
import javacard.framework.ISOException;
2525
import javacard.framework.APDU;
26+
import javacard.framework.SystemException;
27+
import javacard.framework.TransactionException;
2628
import javacard.framework.JCSystem;
2729
import javacard.framework.Util;
2830
import javacard.framework.OwnerPIN;
@@ -61,6 +63,11 @@ public class IsoApplet extends Applet implements ExtendedLength {
6163
/* Card-specific configuration */
6264
public static final boolean DEF_PRIVATE_KEY_IMPORT_ALLOWED = false;
6365

66+
/* Certain cards (J3H081) break in unexpected ways testing these at
67+
* runtime. Allow them to be forced off so no test is run. */
68+
public static final boolean DEF_TEST_RSA_4096 = true;
69+
public static final boolean DEF_TEST_RSA_PSS = true;
70+
6471
/* ISO constants not in the "ISO7816" interface */
6572
// File system related INS:
6673
public static final byte INS_CREATE_FILE = (byte) 0xE0;
@@ -138,12 +145,6 @@ public class IsoApplet extends Applet implements ExtendedLength {
138145
private Key[] keys = null;
139146
private byte[] ram_buf = null;
140147
private Cipher rsaPkcs1Cipher = null;
141-
private Signature ecdsaSignature = null;
142-
private Signature rsaSha1PssSignature = null;
143-
private Signature rsaSha224PssSignature = null;
144-
private Signature rsaSha256PssSignature = null;
145-
private Signature rsaSha384PssSignature = null;
146-
private Signature rsaSha512PssSignature = null;
147148
private RandomData randomData = null;
148149
private byte api_features;
149150

@@ -179,54 +180,60 @@ protected IsoApplet() {
179180

180181
// API features: probe card support for ECDSA
181182
try {
182-
ecdsaSignature = Signature.getInstance(MessageDigest.ALG_NULL, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL, false);
183+
Signature.getInstance(MessageDigest.ALG_NULL, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL, false);
183184
api_features |= API_FEATURE_ECC;
184185
} catch (CryptoException e) {
185186
if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
186187
/* Few Java Cards do not support ECDSA at all.
187188
* We should not throw an exception in this cases
188189
* as this would prevent installation. */
189-
ecdsaSignature = null;
190190
api_features &= ~API_FEATURE_ECC;
191191
} else {
192192
throw e;
193193
}
194194
}
195195

196196
// API features: probe card support for 4096 bit RSA keys
197-
try {
198-
RSAPrivateCrtKey testKey = (RSAPrivateCrtKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, KeyBuilder.LENGTH_RSA_4096, false);
199-
api_features |= API_FEATURE_RSA_4096;
200-
} catch (CryptoException e) {
201-
if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
202-
api_features &= ~API_FEATURE_RSA_4096;
203-
} else {
204-
throw e;
197+
if (DEF_TEST_RSA_4096) {
198+
try {
199+
RSAPrivateCrtKey testKey = (RSAPrivateCrtKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, KeyBuilder.LENGTH_RSA_4096, false);
200+
api_features |= API_FEATURE_RSA_4096;
201+
} catch (CryptoException e) {
202+
if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
203+
api_features &= ~API_FEATURE_RSA_4096;
204+
} else {
205+
throw e;
206+
}
207+
} catch (TransactionException e) {
208+
// J3H081 from javacardsdk.com (FUTAKO) raises this exception instead.
209+
if(e.getReason() == TransactionException.INTERNAL_FAILURE) {
210+
api_features &= ~API_FEATURE_RSA_4096;
211+
} else {
212+
throw e;
213+
}
205214
}
206215
}
207216

217+
208218
/* API features: probe card support for RSA and PSS padding with SHA-1 and all SHA-2 algorithms
209219
* to be used with Signature.signPreComputedHash() */
210-
try {
211-
rsaSha1PssSignature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1_PSS, false);
212-
rsaSha224PssSignature = Signature.getInstance(Signature.ALG_RSA_SHA_224_PKCS1_PSS, false);
213-
rsaSha256PssSignature = Signature.getInstance(Signature.ALG_RSA_SHA_256_PKCS1_PSS, false);
214-
rsaSha384PssSignature = Signature.getInstance(Signature.ALG_RSA_SHA_384_PKCS1_PSS, false);
215-
rsaSha512PssSignature = Signature.getInstance(Signature.ALG_RSA_SHA_512_PKCS1_PSS, false);
216-
api_features |= API_FEATURE_RSA_PSS;
217-
} catch (CryptoException e) {
218-
if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
219-
/* Certain Java Cards do not support this algorithm.
220-
* We should not throw an exception in this cases
221-
* as this would prevent installation. */
222-
rsaSha1PssSignature = null;
223-
rsaSha224PssSignature = null;
224-
rsaSha384PssSignature = null;
225-
rsaSha256PssSignature = null;
226-
rsaSha512PssSignature = null;
227-
api_features &= ~API_FEATURE_RSA_PSS;
228-
} else {
229-
throw e;
220+
if (DEF_TEST_RSA_PSS) {
221+
try {
222+
Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1_PSS, false);
223+
Signature.getInstance(Signature.ALG_RSA_SHA_224_PKCS1_PSS, false);
224+
Signature.getInstance(Signature.ALG_RSA_SHA_256_PKCS1_PSS, false);
225+
Signature.getInstance(Signature.ALG_RSA_SHA_384_PKCS1_PSS, false);
226+
Signature.getInstance(Signature.ALG_RSA_SHA_512_PKCS1_PSS, false);
227+
api_features |= API_FEATURE_RSA_PSS;
228+
} catch (CryptoException e) {
229+
if(e.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
230+
/* Certain Java Cards do not support this algorithm.
231+
* We should not throw an exception in this cases
232+
* as this would prevent installation. */
233+
api_features &= ~API_FEATURE_RSA_PSS;
234+
} else {
235+
throw e;
236+
}
230237
}
231238
}
232239

@@ -1101,7 +1108,7 @@ public void processManageSecurityEnvironment(APDU apdu) throws ISOException {
11011108
if(privKeyRef < 0) {
11021109
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
11031110
}
1104-
if(algRef == ALG_GEN_EC && ecdsaSignature == null) {
1111+
if(algRef == ALG_GEN_EC && (api_features & API_FEATURE_ECC) == 0) {
11051112
// There are cards that do not support ECDSA at all.
11061113
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
11071114
}
@@ -1129,7 +1136,7 @@ public void processManageSecurityEnvironment(APDU apdu) throws ISOException {
11291136
if(keys[privKeyRef].getType() != KeyBuilder.TYPE_EC_FP_PRIVATE) {
11301137
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
11311138
}
1132-
if(ecdsaSignature == null) {
1139+
if((api_features & API_FEATURE_ECC) == 0) {
11331140
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
11341141
}
11351142

@@ -1297,24 +1304,27 @@ private void computeDigitalSignature(APDU apdu) throws ISOException {
12971304
} else if (currentAlgorithmRef[0] == ALG_RSA_PAD_PSS) {
12981305
// ALG_RSA_PAD_PSS with pre-computed hash.
12991306
// Determine Signature object by hash length.
1307+
Signature obj = null;
13001308
if(lc == (short) 20) {
1301-
rsaSha1PssSignature.init(rsaKey, Signature.MODE_SIGN);
1302-
sigLen = rsaSha1PssSignature.signPreComputedHash(ram_buf, (short)0, lc, ram_buf, lc);
1309+
obj = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1_PSS, false);
13031310
} else if (lc == (short) 28) {
1304-
rsaSha224PssSignature.init(rsaKey, Signature.MODE_SIGN);
1305-
sigLen = rsaSha224PssSignature.signPreComputedHash(ram_buf, (short)0, lc, ram_buf, lc);
1311+
obj = Signature.getInstance(Signature.ALG_RSA_SHA_224_PKCS1_PSS, false);
13061312
} else if (lc == (short) 32) {
1307-
rsaSha256PssSignature.init(rsaKey, Signature.MODE_SIGN);
1308-
sigLen = rsaSha256PssSignature.signPreComputedHash(ram_buf, (short)0, lc, ram_buf, lc);
1313+
obj = Signature.getInstance(Signature.ALG_RSA_SHA_256_PKCS1_PSS, false);
13091314
} else if (lc == (short) 48) {
1310-
rsaSha384PssSignature.init(rsaKey, Signature.MODE_SIGN);
1311-
sigLen = rsaSha384PssSignature.signPreComputedHash(ram_buf, (short)0, lc, ram_buf, lc);
1315+
obj = Signature.getInstance(Signature.ALG_RSA_SHA_384_PKCS1_PSS, false);
13121316
} else if (lc == (short) 64) {
1313-
rsaSha512PssSignature.init(rsaKey, Signature.MODE_SIGN);
1314-
sigLen = rsaSha512PssSignature.signPreComputedHash(ram_buf, (short)0, lc, ram_buf, lc);
1317+
obj = Signature.getInstance(Signature.ALG_RSA_SHA_512_PKCS1_PSS, false);
13151318
} else {
13161319
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
13171320
}
1321+
1322+
obj.init(rsaKey, Signature.MODE_SIGN);
1323+
sigLen = obj.signPreComputedHash(ram_buf, (short)0, lc, ram_buf, lc);
1324+
1325+
if(JCSystem.isObjectDeletionSupported()) {
1326+
JCSystem.requestObjectDeletion();
1327+
}
13181328
} else {
13191329
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
13201330
}
@@ -1331,8 +1341,12 @@ private void computeDigitalSignature(APDU apdu) throws ISOException {
13311341
// Get the key - it must be a EC private key,
13321342
// checks have been done in MANAGE SECURITY ENVIRONMENT.
13331343
ECPrivateKey ecKey = (ECPrivateKey) keys[currentPrivateKeyRef[0]];
1344+
Signature ecdsaSignature = Signature.getInstance(MessageDigest.ALG_NULL, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL, false);
13341345
ecdsaSignature.init(ecKey, Signature.MODE_SIGN);
13351346
sigLen = ecdsaSignature.sign(ram_buf, (short)0, lc, apdu.getBuffer(), (short)0);
1347+
if(JCSystem.isObjectDeletionSupported()) {
1348+
JCSystem.requestObjectDeletion();
1349+
}
13361350
apdu.setOutgoingAndSend((short) 0, sigLen);
13371351
break;
13381352

0 commit comments

Comments
 (0)