summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Fitzek <andreas.fitzek@iaik.tugraz.at>2014-11-18 11:50:40 (GMT)
committerAndreas Fitzek <andreas.fitzek@iaik.tugraz.at>2014-11-18 11:50:40 (GMT)
commitf6e55fe06d5512afeb1981b37df00a45f2d6d5d3 (patch)
tree62c362c6d780f7b04431834d41851454d9684b1e
parent42ce4de107f26807bd27dc295c0ad8ecf10bb5ac (diff)
downloadmocca-f6e55fe06d5512afeb1981b37df00a45f2d6d5d3.zip
mocca-f6e55fe06d5512afeb1981b37df00a45f2d6d5d3.tar.gz
mocca-f6e55fe06d5512afeb1981b37df00a45f2d6d5d3.tar.bz2
Gemalto ID .Net extension, latest certificate selection algorithm and key Identifiers 00 - 14 for direct addressing
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java17
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java288
2 files changed, 242 insertions, 63 deletions
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java
index 5469799..4a7a15b 100644
--- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java
@@ -57,7 +57,22 @@ public class CertificatesInfoboxImpl extends AbstractAssocArrayInfobox {
*/
public static final String[] CERTIFICATES_KEYS = new String[] {
"SecureSignatureKeypair",
- "CertifiedKeypair" };
+ "CertifiedKeypair",
+ "00",
+ "01",
+ "02",
+ "03",
+ "04",
+ "05",
+ "06",
+ "07",
+ "08",
+ "09",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14"};
@Override
public String getIdentifier() {
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java b/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java
index 6a9b039..d53f52a 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java
@@ -10,6 +10,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -30,28 +32,80 @@ import at.gv.egiz.smcc.util.MSCMService;
public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
PINMgmtSignatureCard {
+ private static final String KSC_PATTERN = "ksc(\\p{XDigit}\\p{XDigit})";
+ private static final String CERT_FILE = "mscp\\ksc";
+
+ private static final String CONTAINER_00 = "00";
+ private static final String CONTAINER_01 = "01";
+ private static final String CONTAINER_02 = "02";
+ private static final String CONTAINER_03 = "03";
+ private static final String CONTAINER_04 = "04";
+ private static final String CONTAINER_05 = "05";
+ private static final String CONTAINER_06 = "06";
+ private static final String CONTAINER_07 = "07";
+ private static final String CONTAINER_08 = "08";
+ private static final String CONTAINER_09 = "09";
+ private static final String CONTAINER_10 = "10";
+ private static final String CONTAINER_11 = "11";
+ private static final String CONTAINER_12 = "12";
+ private static final String CONTAINER_13 = "13";
+ private static final String CONTAINER_14 = "14";
+
+ private static final KeyboxName KEYBOX_CONTAINER_00 = KeyboxName
+ .getKeyboxName(CONTAINER_00);
+ private static final KeyboxName KEYBOX_CONTAINER_01 = KeyboxName
+ .getKeyboxName(CONTAINER_01);
+ private static final KeyboxName KEYBOX_CONTAINER_02 = KeyboxName
+ .getKeyboxName(CONTAINER_02);
+ private static final KeyboxName KEYBOX_CONTAINER_03 = KeyboxName
+ .getKeyboxName(CONTAINER_03);
+ private static final KeyboxName KEYBOX_CONTAINER_04 = KeyboxName
+ .getKeyboxName(CONTAINER_04);
+ private static final KeyboxName KEYBOX_CONTAINER_05 = KeyboxName
+ .getKeyboxName(CONTAINER_05);
+ private static final KeyboxName KEYBOX_CONTAINER_06 = KeyboxName
+ .getKeyboxName(CONTAINER_06);
+ private static final KeyboxName KEYBOX_CONTAINER_07 = KeyboxName
+ .getKeyboxName(CONTAINER_07);
+ private static final KeyboxName KEYBOX_CONTAINER_08 = KeyboxName
+ .getKeyboxName(CONTAINER_08);
+ private static final KeyboxName KEYBOX_CONTAINER_09 = KeyboxName
+ .getKeyboxName(CONTAINER_09);
+ private static final KeyboxName KEYBOX_CONTAINER_10 = KeyboxName
+ .getKeyboxName(CONTAINER_10);
+ private static final KeyboxName KEYBOX_CONTAINER_11 = KeyboxName
+ .getKeyboxName(CONTAINER_11);
+ private static final KeyboxName KEYBOX_CONTAINER_12 = KeyboxName
+ .getKeyboxName(CONTAINER_12);
+ private static final KeyboxName KEYBOX_CONTAINER_13 = KeyboxName
+ .getKeyboxName(CONTAINER_13);
+ private static final KeyboxName KEYBOX_CONTAINER_14 = KeyboxName
+ .getKeyboxName(CONTAINER_14);
+
private final Logger log = LoggerFactory
.getLogger(GemaltoNetV2_0Card.class);
PinInfo pinPinInfo;
PinInfo pukPinInfo;
-
+
+ Pattern pattern;
+
private final byte[] SHA1_PADDING = new byte[] {
- (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06,
- (byte) 0x05, (byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02,
- (byte) 0x1A, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 };
-
+ (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06,
+ (byte) 0x05, (byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02,
+ (byte) 0x1A, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 };
+
private final byte[] SHA256_PADDING = new byte[] {
- (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
- (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
- (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x01,
- (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x20 };
+ (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+ (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
+ (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x01,
+ (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x20 };
public void init(Card card, CardTerminal cardTerminal) {
super.init(card, cardTerminal);
-
+ pattern = Pattern.compile(KSC_PATTERN);
log.info("GemaltoNetV2 card found");
pinPinInfo = new PinInfo(4, 64, "[0-9]",
@@ -62,15 +116,89 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
"at/gv/egiz/smcc/GemaltoNetV2_0Card", "sig.puk", (byte) 2,
new byte[] {}, 3);
}
-
+
public static byte[] hexStringToByteArray(String s) {
- int len = s.length();
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
- + Character.digit(s.charAt(i+1), 16));
- }
- return data;
+ int len = s.length();
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
+ .digit(s.charAt(i + 1), 16));
+ }
+ return data;
+ }
+
+ private int findKeyIndex() throws IOException, CardException, MSCMException {
+ MSCMService service = new MSCMService(this.getCardChannel());
+ String[] files = service.getFiles("mscp");
+ int currentMax = -1;
+ for (int i = 0; i < files.length; i++) {
+ String fileName = files[i];
+ log.trace("Checking file: " + files[i]);
+ Matcher matcher = pattern.matcher(fileName);
+ if (matcher.find()) {
+ if (matcher.groupCount() == 1) {
+ String fidx = matcher.group(1);
+ log.trace("Found idx: " + fidx);
+ try {
+ int curr = Integer.parseInt(fidx, 16);
+ if (currentMax < curr) {
+ currentMax = curr;
+ }
+ } catch (NumberFormatException e) {
+ log.warn("Matched Regex but is no integer!", e);
+ }
+ }
+ }
+ }
+ return currentMax;
+ }
+
+ private String getCertificateFileFormIdx(int idx) {
+ return String.format("%s%02x", CERT_FILE, idx);
+ }
+
+ private int resolveKeyboxIdx(KeyboxName keyboxName) {
+ if (keyboxName.equals(KEYBOX_CONTAINER_00)) {
+ return 0;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_01)) {
+ return 1;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_02)) {
+ return 2;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_03)) {
+ return 3;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_04)) {
+ return 4;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_05)) {
+ return 5;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_06)) {
+ return 6;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_07)) {
+ return 7;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_08)) {
+ return 8;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_09)) {
+ return 9;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_10)) {
+ return 10;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_11)) {
+ return 11;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_12)) {
+ return 12;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_13)) {
+ return 13;
+ } else if (keyboxName.equals(KEYBOX_CONTAINER_14)) {
+ return 14;
+ }
+ return -1;
+ }
+
+ private String resolveKeybox(KeyboxName keyboxName) {
+ int idx = resolveKeyboxIdx(keyboxName);
+ if(idx < 0) {
+ return null;
+ }
+
+ return getCertificateFileFormIdx(idx);
}
@Override
@@ -79,7 +207,19 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
try {
CardChannel channel = this.getCardChannel();// this.getCard().getBasicChannel();
MSCMService service = new MSCMService(channel);
- byte[] filecnt = service.readFile("mscp\\ksc00");
+ String certFile = resolveKeybox(keyboxName);
+
+ if(certFile == null) {
+ int idx = findKeyIndex();
+ if(idx < 0) {
+ throw new SignatureCardException("There is no certificate available on this token!");
+ }
+ certFile = getCertificateFileFormIdx(idx);
+ }
+
+ log.info("Reading certificate: " + certFile);
+
+ byte[] filecnt = service.readFile(certFile);
Inflater inflater = new Inflater();
inflater.setInput(filecnt, 4, filecnt.length - 4);
@@ -111,8 +251,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
@Override
public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId)
throws SignatureCardException, InterruptedException {
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
+ return getCertificate(KeyboxName.getKeyboxName(infobox), pinGUI);
}
@Override
@@ -122,15 +261,31 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
boolean sha1 = false;
MessageDigest md;
+ int ctrIdx = -1;
try {
- if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
- && (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
- .equals(alg))) {
+
+ ctrIdx = resolveKeyboxIdx(keyboxName);
+
+ if(ctrIdx < 0) {
+ ctrIdx = findKeyIndex();
+ if(ctrIdx < 0) {
+ throw new SignatureCardException("There is no private key available on this token!");
+ }
+ }
+
+ if(ctrIdx > 14) {
+ log.error("Key Index is bigger the maximum container available");
+ throw new SignatureCardException("There is no private key available on this token!");
+ }
+
+ log.info("Signing with key: " + ctrIdx);
+
+ if (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
+ .equals(alg)) {
md = MessageDigest.getInstance("SHA-1");
sha1 = true;
- } else if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
- && ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
- .equals(alg))) {
+ } else if ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
+ .equals(alg)) {
md = MessageDigest.getInstance("SHA-256");
} else {
throw new SignatureCardException(
@@ -140,6 +295,12 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
} catch (CryptoException e) {
log.error("Failed to get MessageDigest.", e);
throw new SignatureCardException(e);
+ } catch (CardException e) {
+ log.error("Failed to get MessageDigest.", e);
+ throw new SignatureCardException(e);
+ } catch (MSCMException e) {
+ log.error("Failed to get MessageDigest.", e);
+ throw new SignatureCardException(e);
}
byte[] digest = new byte[md.getDigestLength()];
@@ -156,11 +317,10 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
MSCMService service = new MSCMService(channel);
verifyPINLoop(channel, pinPinInfo, pinGUI);
-
+
ByteArrayOutputStream fdata = new ByteArrayOutputStream();
-
-
- if(sha1) {
+
+ if (sha1) {
fdata.write(SHA1_PADDING);
} else {
fdata.write(SHA256_PADDING);
@@ -169,7 +329,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
fdata.close();
byte[] msg = fdata.toByteArray();
byte[] paded = padding.pad(msg);
- byte[] sign = service.privateKeyDecrypt((byte) 0, (byte) 2, paded);
+ byte[] sign = service.privateKeyDecrypt((byte) ctrIdx, (byte) 2, paded);
return sign;
} catch (Throwable e) {
log.warn("Failed to execute command.", e);
@@ -177,35 +337,37 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
}
}
- protected void unblockPINLoop(CardChannel channel,
- ModifyPINGUI provider, PinInfo pin) throws InterruptedException, CardException, SignatureCardException{
+ protected void unblockPINLoop(CardChannel channel, ModifyPINGUI provider,
+ PinInfo pin) throws InterruptedException, CardException,
+ SignatureCardException {
int retries = -1;
do {
retries = exec_unblockPIN(channel, provider, pin);
} while (retries > 0);
}
-
+
/*
* Unblock PIN with PUK code
*/
- protected int exec_unblockPIN(CardChannel channel, ModifyPINGUI changePINGUI, PinInfo pin)
+ protected int exec_unblockPIN(CardChannel channel,
+ ModifyPINGUI changePINGUI, PinInfo pin)
throws InterruptedException, CardException, SignatureCardException {
-
-
+
char[] oldPIN = changePINGUI.providePUK(pin, pukPinInfo,
pukPinInfo.retries);
char[] newPIN = changePINGUI.provideNewPIN(pin);
-
+
byte[] ascii_pin = encodePIN(newPIN);
MSCMService service = new MSCMService(channel);
-
+
try {
byte[] key = hexStringToByteArray(new String(oldPIN));
- if(key.length != 24) {
- throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!");
+ if (key.length != 24) {
+ throw new SignatureCardException(
+ "Invalid ADMIN PIN (not 24 bytes long)!");
}
byte[] challenge = service.getChallenge();
byte[] response = service.cryptoResponse(challenge, key);
@@ -235,7 +397,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
}
}
-
+
protected void verifyPINLoop(CardChannel channel, PinInfo spec,
PINGUI provider) throws InterruptedException, CardException,
SignatureCardException {
@@ -256,11 +418,12 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
char[] pin = provider.providePIN(pinInfo, pinInfo.retries);
byte[] ascii_pin = hexStringToByteArray(new String(pin));
-
- if(ascii_pin.length != 24) {
- throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!");
+
+ if (ascii_pin.length != 24) {
+ throw new SignatureCardException(
+ "Invalid ADMIN PIN (not 24 bytes long)!");
}
-
+
MSCMService service = new MSCMService(channel);
try {
@@ -283,7 +446,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
throw new SignatureCardException(e);
}
}
-
+
/*
* Verify PIN/PUK entry
*/
@@ -303,7 +466,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
} catch (MSCMException e) {
try {
int tries = service.getTriesRemaining(pinInfo.getKID());
- if(tries == 0) {
+ if (tries == 0) {
pinInfo.setBlocked();
throw new LockedException();
}
@@ -328,7 +491,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
int retries = -1;
do {
- if(pin.getKID() == 2) {
+ if (pin.getKID() == 2) {
retries = exec_changePUK(channel, provider, pin);
} else {
retries = exec_changePIN(channel, provider, pin);
@@ -372,11 +535,13 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
try {
byte[] key = hexStringToByteArray(new String(oldPIN));
byte[] keynew = hexStringToByteArray(new String(newPIN));
- if(key.length != 24) {
- throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!");
+ if (key.length != 24) {
+ throw new SignatureCardException(
+ "Invalid ADMIN PIN (not 24 bytes long)!");
}
- if(keynew.length != 24) {
- throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!");
+ if (keynew.length != 24) {
+ throw new SignatureCardException(
+ "Invalid ADMIN PIN (not 24 bytes long)!");
}
byte[] challenge = service.getChallenge();
byte[] response = service.cryptoResponse(challenge, key);
@@ -392,7 +557,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
log.info(e.getMessage());
try {
int tries = service.getTriesRemaining(pin.getKID());
- if(tries == 0) {
+ if (tries == 0) {
pin.setBlocked();
throw new LockedException();
}
@@ -412,7 +577,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
}
}
-
+
/*
* Unblock PIN with PUK code
*/
@@ -433,8 +598,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
try {
// service -> change pin
- service.changePIN((byte) 1, ascii_puk, ascii_pin,
- pin.maxRetries);
+ service.changePIN((byte) 1, ascii_puk, ascii_pin, pin.maxRetries);
pin.setActive(pin.maxRetries);
return -1;
} catch (IOException e) {
@@ -446,7 +610,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
log.info(e.getMessage());
try {
int tries = service.getTriesRemaining(pin.getKID());
- if(tries == 0) {
+ if (tries == 0) {
pin.setBlocked();
throw new LockedException();
}
@@ -480,10 +644,10 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
public void verifyPIN(PinInfo pinInfo, PINGUI pinGUI)
throws LockedException, NotActivatedException, CancelledException,
SignatureCardException, InterruptedException {
-
+
try {
CardChannel channel = this.getCardChannel();
- if(pinInfo.getKID() == 2) {
+ if (pinInfo.getKID() == 2) {
verifyPUK(channel, pinInfo, pinGUI, pinInfo.retries);
} else {
verifyPIN(channel, pinInfo, pinGUI, pinInfo.retries);
@@ -519,7 +683,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
public void unblockPIN(PinInfo pinInfo, ModifyPINGUI pukGUI)
throws CancelledException, SignatureCardException,
InterruptedException {
- if(pinInfo.getKID() == 2) {
+ if (pinInfo.getKID() == 2) {
throw new SignatureCardException("Unable to unblock PUK");
} else {
CardChannel channel = getCardChannel();