summaryrefslogtreecommitdiff
path: root/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java
diff options
context:
space:
mode:
Diffstat (limited to 'smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java')
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java513
1 files changed, 513 insertions, 0 deletions
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
new file mode 100644
index 00000000..3bea0753
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java
@@ -0,0 +1,513 @@
+package at.gv.egiz.smcc;
+
+import iaik.me.security.CryptoBag;
+import iaik.me.security.CryptoException;
+import iaik.me.security.MessageDigest;
+import iaik.me.security.cipher.TripleDES;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import javax.print.attribute.standard.Severity;
+import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import sun.security.rsa.RSAPadding;
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
+import at.gv.egiz.smcc.util.MSCMException;
+import at.gv.egiz.smcc.util.MSCMService;
+
+public class GemaltoNetV2_0Card extends AbstractSignatureCard implements
+ PINMgmtSignatureCard {
+
+ private final Logger log = LoggerFactory
+ .getLogger(GemaltoNetV2_0Card.class);
+
+ PinInfo pinPinInfo;
+ PinInfo pukPinInfo;
+
+ public void init(Card card, CardTerminal cardTerminal) {
+ super.init(card, cardTerminal);
+
+ log.info("GemaltoNetV2 card found");
+
+ pinPinInfo = new PinInfo(4, 64, "[0-9]",
+ "at/gv/egiz/smcc/GemaltoNetV2_0Card", "sig.pin", (byte) 1,
+ new byte[] {}, 5);
+
+ pukPinInfo = new PinInfo(48, 48, "[0-9A-F]",
+ "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;
+ }
+
+ @Override
+ public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI)
+ throws SignatureCardException, InterruptedException {
+ try {
+ CardChannel channel = this.getCardChannel();// this.getCard().getBasicChannel();
+ MSCMService service = new MSCMService(channel);
+ byte[] filecnt = service.readFile("mscp\\ksc00");
+
+ Inflater inflater = new Inflater();
+ inflater.setInput(filecnt, 4, filecnt.length - 4);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ while (!inflater.finished()) {
+ byte[] uncompressedData = new byte[1024];
+ int compressLength = inflater.inflate(uncompressedData, 0,
+ uncompressedData.length);
+ // System.out.println(compressedData);
+ out.write(uncompressedData, 0, compressLength);
+ }
+ byte[] uncompressed = out.toByteArray();
+ return uncompressed;
+ } catch (CardException e) {
+ log.info("Failed to get certificate.", e);
+ throw new SignatureCardException(e);
+ } catch (DataFormatException e) {
+ log.info("Failed to get certificate.", e);
+ throw new SignatureCardException(e);
+ } catch (IOException e) {
+ log.info("Failed to get certificate.", e);
+ throw new SignatureCardException(e);
+ } catch (MSCMException e) {
+ log.info("Failed to get certificate.", e);
+ throw new SignatureCardException(e);
+ }
+ }
+
+ @Override
+ public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId)
+ throws SignatureCardException, InterruptedException {
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
+ }
+
+ @Override
+ public byte[] createSignature(InputStream input, KeyboxName keyboxName,
+ PINGUI pinGUI, String alg) throws SignatureCardException,
+ InterruptedException, IOException {
+
+ MessageDigest md;
+ try {
+ if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
+ && (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
+ .equals(alg))) {
+ md = MessageDigest.getInstance("SHA-1");
+ } else if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)
+ && ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
+ .equals(alg))) {
+ md = MessageDigest.getInstance("SHA-256");
+ } else {
+ throw new SignatureCardException(
+ "Card does not support signature algorithm " + alg
+ + ".");
+ }
+ } catch (CryptoException e) {
+ log.error("Failed to get MessageDigest.", e);
+ throw new SignatureCardException(e);
+ }
+
+ byte[] digest = new byte[md.getDigestLength()];
+ for (int l; (l = input.read(digest)) != -1;) {
+ md.update(digest, 0, l);
+ }
+ digest = md.digest();
+
+ try {
+ RSAPadding padding = RSAPadding.getInstance(
+ RSAPadding.PAD_BLOCKTYPE_1, 256);
+
+ CardChannel channel = this.getCardChannel();
+ MSCMService service = new MSCMService(channel);
+
+ verifyPINLoop(channel, pinPinInfo, pinGUI);
+
+ byte[] paded = padding.pad(digest);
+ byte[] sign = service.privateKeyDecrypt((byte) 0, (byte) 2, paded);
+ return sign;
+ } catch (Throwable e) {
+ log.warn("Failed to execute command.", e);
+ throw new SignatureCardException("Failed to access card.", e);
+ }
+ }
+
+ 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)
+ 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)!");
+ }
+ byte[] challenge = service.getChallenge();
+ byte[] response = service.cryptoResponse(challenge, key);
+ service.unblockPIN((byte) 1, response, ascii_pin, pin.maxRetries);
+ pin.setActive(pin.maxRetries);
+ return -1;
+ } catch (IOException e) {
+ String msg = "SET PIN failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, e);
+ } catch (MSCMException e) {
+ log.info(e.getMessage());
+ try {
+ return service.getTriesRemaining((byte) 2);
+ } catch (IOException ec) {
+ String msg = "getTriesRemaining failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, ec);
+ } catch (MSCMException e1) {
+ String msg = "getTriesRemaining failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, e1);
+ }
+ }
+
+ }
+
+ protected void verifyPINLoop(CardChannel channel, PinInfo spec,
+ PINGUI provider) throws InterruptedException, CardException,
+ SignatureCardException {
+
+ int retries = -1;
+ do {
+ retries = verifyPIN(channel, spec, provider, retries);
+ } while (retries > 0);
+ }
+
+ /*
+ * Verify PIN/PUK entry
+ */
+ protected int verifyPUK(CardChannel channel, PinInfo pinInfo,
+ PINGUI provider, int retries) throws InterruptedException,
+ CardException, SignatureCardException {
+
+ 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)!");
+ }
+
+ MSCMService service = new MSCMService(channel);
+
+ try {
+ byte[] challenge = service.getChallenge();
+ byte[] response = service.cryptoResponse(challenge, ascii_pin);
+ service.doExternalAuthentication(response);
+ pinInfo.setActive(pinInfo.maxRetries);
+ return -1;
+ } catch (MSCMException e) {
+ try {
+ int tries = service.getTriesRemaining(pinInfo.getKID());
+ pinInfo.setActive(tries);
+ return tries;
+ } catch (Exception ex) {
+ log.error("Failed to get remaining tries");
+ throw new SignatureCardException(ex);
+ }
+ } catch (IOException e) {
+ log.error("Failed to verify PIN");
+ throw new SignatureCardException(e);
+ }
+ }
+
+ /*
+ * Verify PIN/PUK entry
+ */
+ protected int verifyPIN(CardChannel channel, PinInfo pinInfo,
+ PINGUI provider, int retries) throws InterruptedException,
+ CardException, SignatureCardException {
+
+ char[] pin = provider.providePIN(pinInfo, pinInfo.retries);
+
+ byte[] ascii_pin = encodePIN(pin);
+ MSCMService service = new MSCMService(channel);
+
+ try {
+ service.verifyPin(pinInfo.getKID(), ascii_pin);
+ pinInfo.setActive(pinInfo.maxRetries);
+ return -1;
+ } catch (MSCMException e) {
+ try {
+ int tries = service.getTriesRemaining(pinInfo.getKID());
+ if(tries == 0) {
+ pinInfo.setBlocked();
+ throw new LockedException();
+ }
+ pinInfo.setActive(tries);
+ return tries;
+ } catch (IOException ex) {
+ log.error("Failed to get remaining tries");
+ throw new SignatureCardException(ex);
+ } catch (MSCMException e1) {
+ log.error("Failed to get remaining tries");
+ throw new SignatureCardException(e1);
+ }
+ } catch (IOException e) {
+ log.error("Failed to verify PIN");
+ throw new SignatureCardException(e);
+ }
+ }
+
+ protected void changePINLoop(CardChannel channel, ModifyPINGUI provider,
+ PinInfo pin) throws InterruptedException, CardException,
+ SignatureCardException {
+
+ int retries = -1;
+ do {
+ if(pin.getKID() == 2) {
+ retries = exec_changePUK(channel, provider, pin);
+ } else {
+ retries = exec_changePIN(channel, provider, pin);
+ }
+ } while (retries > 0);
+ }
+
+ protected byte[] cryptoChallenge(byte[] challenge, byte[] pass) {
+ try {
+ byte[] iv = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00 };
+ TripleDES cip = new TripleDES();
+ cip.init(TripleDES.ENCRYPT_MODE, CryptoBag.makeSecretKey(pass),
+ CryptoBag.makeIV(iv), null);
+ log.info("Crypto IV: "
+ + MSCMService.bytArrayToHex(cip.getIV().getEncoded()));
+ byte[] result = cip.doFinal(challenge);
+ log.info("Crypto result: " + MSCMService.bytArrayToHex(result));
+ return result;
+ } catch (CryptoException e) {
+ log.error("Failed to get crypto stuff", e);
+ return null;
+ }
+ }
+
+ /*
+ * Unblock PIN with PUK code
+ */
+ protected int exec_changePUK(CardChannel channel,
+ ModifyPINGUI changePINGUI, PinInfo pin)
+ throws InterruptedException, CardException, SignatureCardException {
+
+ char[] oldPIN = changePINGUI.providePUK(pin, pukPinInfo,
+ pukPinInfo.retries);
+
+ char[] newPIN = changePINGUI.provideNewPIN(pin);
+
+ MSCMService service = new MSCMService(channel);
+
+ 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(keynew.length != 24) {
+ throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!");
+ }
+ byte[] challenge = service.getChallenge();
+ byte[] response = service.cryptoResponse(challenge, key);
+ service.changePIN((byte) 2, response, keynew, pin.maxRetries);
+ pin.setActive(pin.maxRetries);
+ return -1;
+ } catch (IOException e) {
+ String msg = "SET PIN failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, e);
+ } catch (MSCMException e) {
+ log.info(e.getMessage());
+ try {
+ int tries = service.getTriesRemaining(pin.getKID());
+ if(tries == 0) {
+ pin.setBlocked();
+ throw new LockedException();
+ }
+ pin.setActive(tries);
+ return tries;
+ } catch (IOException ec) {
+ String msg = "getTriesRemaining failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, ec);
+ } catch (MSCMException e1) {
+ String msg = "getTriesRemaining failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, e1);
+ }
+ }
+
+ }
+
+ /*
+ * Unblock PIN with PUK code
+ */
+ protected int exec_changePIN(CardChannel channel,
+ ModifyPINGUI changePINGUI, PinInfo pin)
+ throws InterruptedException, CardException, SignatureCardException {
+
+ char[] oldPIN = changePINGUI.providePUK(pin, pinPinInfo,
+ pinPinInfo.retries);
+
+ char[] newPIN = changePINGUI.provideNewPIN(pin);
+
+ byte[] ascii_puk = encodePIN(oldPIN);
+
+ byte[] ascii_pin = encodePIN(newPIN);
+
+ MSCMService service = new MSCMService(channel);
+
+ try {
+ // service -> change pin
+ service.changePIN((byte) 1, ascii_puk, ascii_pin,
+ pin.maxRetries);
+ pin.setActive(pin.maxRetries);
+ return -1;
+ } catch (IOException e) {
+ String msg = "SET PIN failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, e);
+ } catch (MSCMException e) {
+ log.info(e.getMessage());
+ try {
+ int tries = service.getTriesRemaining(pin.getKID());
+ if(tries == 0) {
+ pin.setBlocked();
+ throw new LockedException();
+ }
+ pin.setActive(tries);
+ return tries;
+ } catch (IOException ec) {
+ String msg = "getTriesRemaining failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, ec);
+ } catch (MSCMException e1) {
+ String msg = "getTriesRemaining failed.";
+ log.info(msg);
+ pin.setUnknown();
+ throw new SignatureCardException(msg, e1);
+ }
+ }
+
+ }
+
+ private byte[] encodePIN(char[] pin) {
+ return Charset.forName("ASCII").encode(CharBuffer.wrap(pin)).array();
+ }
+
+ // @Override
+ public PinInfo[] getPinInfos() throws SignatureCardException {
+ return new PinInfo[] { pinPinInfo, pukPinInfo };
+ }
+
+ // @Override
+ public void verifyPIN(PinInfo pinInfo, PINGUI pinGUI)
+ throws LockedException, NotActivatedException, CancelledException,
+ SignatureCardException, InterruptedException {
+
+ try {
+ CardChannel channel = this.getCardChannel();
+ if(pinInfo.getKID() == 2) {
+ verifyPUK(channel, pinInfo, pinGUI, pinInfo.retries);
+ } else {
+ verifyPIN(channel, pinInfo, pinGUI, pinInfo.retries);
+ }
+ } catch (CardException e) {
+ log.error("Failed to verify PIN");
+ throw new SignatureCardException(e);
+ }
+ }
+
+ // @Override
+ public void changePIN(PinInfo pinInfo, ModifyPINGUI changePINGUI)
+ throws LockedException, NotActivatedException, CancelledException,
+ PINFormatException, SignatureCardException, InterruptedException {
+ try {
+ changePINLoop(getCardChannel(), changePINGUI, pinInfo);
+ } catch (CardException e) {
+ log.error("Failed to change PIN");
+ throw new SignatureCardException(e);
+ }
+ }
+
+ // @Override
+ public void activatePIN(PinInfo pinInfo, ModifyPINGUI activatePINGUI)
+ throws CancelledException, SignatureCardException,
+ InterruptedException {
+ log.error("ACTIVATE PIN not supported by Cypriotic EID");
+ throw new SignatureCardException(
+ "PIN activation not supported by this card.");
+ }
+
+ // @Override
+ public void unblockPIN(PinInfo pinInfo, ModifyPINGUI pukGUI)
+ throws CancelledException, SignatureCardException,
+ InterruptedException {
+ if(pinInfo.getKID() == 2) {
+ throw new SignatureCardException("Unable to unblock PUK");
+ } else {
+ CardChannel channel = getCardChannel();
+
+ try {
+ unblockPINLoop(channel, pukGUI, pinInfo);
+ } catch (CardException e) {
+ log.info("Failed to unblock PIN.", e);
+ throw new SignatureCardException("Failed to unblock PIN.", e);
+ }
+ }
+ }
+}