summaryrefslogtreecommitdiff
path: root/smcc/src/main
diff options
context:
space:
mode:
authormcentner <mcentner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>2009-07-01 13:03:41 +0000
committermcentner <mcentner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>2009-07-01 13:03:41 +0000
commit6cb4a071eab9a3b8cf78b8ec7e407aa148f2d038 (patch)
tree762855c70893eaac8b0f944cdabebc115849aae2 /smcc/src/main
parente7641b2b5861897e1e1abab3b7411bb77361d5cb (diff)
downloadmocca-6cb4a071eab9a3b8cf78b8ec7e407aa148f2d038.tar.gz
mocca-6cb4a071eab9a3b8cf78b8ec7e407aa148f2d038.tar.bz2
mocca-6cb4a071eab9a3b8cf78b8ec7e407aa148f2d038.zip
Major refactoring of SMCC
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@381 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
Diffstat (limited to 'smcc/src/main')
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java30
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java1089
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java541
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/CardNotSupportedException.java44
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java33
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java95
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java110
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java28
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java129
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java60
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java2
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java2
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java41
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java2
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java44
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java34
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java1110
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SWCard.java61
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java69
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java45
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java49
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java200
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java28
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java357
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/conf/SMCCConfiguration.java2
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java359
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java194
27 files changed, 2810 insertions, 1948 deletions
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java
deleted file mode 100644
index 9fca6ab9..00000000
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2008 Federal Chancellery Austria and
- * Graz University of Technology
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package at.gv.egiz.smcc;
-
-/**
- *
- * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
- */
-public class ACOS04Card extends ACOSCard {
-
- public ACOS04Card() {
- pinSpecs.remove(PINSPEC_INF);
- }
-
-}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
index d064b821..9825978c 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
@@ -1,48 +1,47 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
package at.gv.egiz.smcc;
-import at.gv.egiz.smcc.ccid.CCID;
-import at.gv.egiz.smcc.util.SMCCHelper;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-public class ACOSCard extends AbstractSignatureCard {
+import at.gv.egiz.smcc.util.ISO7816Utils;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import at.gv.egiz.smcc.util.TransparentFileInputStream;
+
+public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureCard {
private static Log log = LogFactory.getLog(ACOSCard.class);
@@ -69,6 +68,8 @@ public class ACOSCard extends AbstractSignatureCard {
(byte) 0x01 };
public static final byte[] EF_INFOBOX = new byte[] { (byte) 0xc0, (byte) 0x02 };
+
+ public static final byte[] EF_INFO = new byte[] { (byte) 0xd0, (byte) 0x02 };
public static final int EF_INFOBOX_MAX_SIZE = 1500;
@@ -90,7 +91,7 @@ public class ACOSCard extends AbstractSignatureCard {
(byte) 0x14 // ECDSA
};
- public static final byte[] DST_DEC = new byte[] { (byte) 0x84, (byte) 0x01, // tag
+ public static final byte[] AT_DEC = new byte[] { (byte) 0x84, (byte) 0x01, // tag
// ,
// length
// (
@@ -102,123 +103,278 @@ public class ACOSCard extends AbstractSignatureCard {
(byte) 0x01 // RSA // TODO: Not verified yet
};
- protected static final int PINSPEC_INF = 0;
- protected static final int PINSPEC_DEC = 1;
- protected static final int PINSPEC_SIG = 2;
+ private static final PINSpec DEC_PIN_SPEC = new PINSpec(0, 8, "[0-9]",
+ "at/gv/egiz/smcc/ACOSCard", "dec.pin.name", KID_PIN_DEC, AID_DEC);
+
+ private static final PINSpec SIG_PIN_SPEC = new PINSpec(0, 8, "[0-9]",
+ "at/gv/egiz/smcc/ACOSCard", "sig.pin.name", KID_PIN_SIG, AID_SIG);
+
+ private static final PINSpec INF_PIN_SPEC = new PINSpec(0, 8, "[0-9]",
+ "at/gv/egiz/smcc/ACOSCard", "inf.pin.name", KID_PIN_INF, AID_DEC);
+
+ /**
+ * The version of the card's digital signature application.
+ */
+ protected int appVersion = -1;
public ACOSCard() {
super("at/gv/egiz/smcc/ACOSCard");
- pinSpecs.add(PINSPEC_INF,
- new PINSpec(0, 8, "[0-9]", getResourceBundle().getString("inf.pin.name"), KID_PIN_INF, AID_DEC));
- pinSpecs.add(PINSPEC_DEC,
- new PINSpec(0, 8, "[0-9]", getResourceBundle().getString("dec.pin.name"), KID_PIN_DEC, AID_DEC));
- pinSpecs.add(PINSPEC_SIG,
- new PINSpec(0, 8, "[0-9]", getResourceBundle().getString("sig.pin.name"), KID_PIN_SIG, AID_SIG));
}
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.SignatureCard#getCertificate(at.gv.egiz.smcc.SignatureCard.KeyboxName)
- */
@Override
+ public void init(Card card, CardTerminal cardTerminal) {
+ super.init(card, cardTerminal);
+
+ // determine application version
+ try {
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, AID_SIG);
+ // SELECT file
+ execSELECT_FID(channel, EF_INFO);
+ // READ BINARY
+ TransparentFileInputStream is = ISO7816Utils.openTransparentFileInputStream(channel, 8);
+ appVersion = is.read();
+ log.info("a-sign premium application version = " + appVersion);
+ } catch (FileNotFoundException e) {
+ appVersion = 1;
+ log.info("a-sign premium application version = " + appVersion);
+ } catch (SignatureCardException e) {
+ log.warn(e);
+ appVersion = 0;
+ } catch (IOException e) {
+ log.warn(e);
+ appVersion = 0;
+ } catch (CardException e) {
+ log.warn(e);
+ appVersion = 0;
+ }
+
+ pinSpecs.add(DEC_PIN_SPEC);
+ pinSpecs.add(SIG_PIN_SPEC);
+ if (appVersion < 2) {
+ pinSpecs.add(INF_PIN_SPEC);
+ }
+
+ }
+
+ @Override
+ @Exclusive
public byte[] getCertificate(KeyboxName keyboxName)
throws SignatureCardException, InterruptedException {
-
- try {
-
+
+ byte[] aid;
+ byte[] fid;
if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
-
- try {
- getCard().beginExclusive();
- byte[] certificate = readTLVFile(AID_SIG, EF_C_CH_DS, EF_C_CH_DS_MAX_SIZE);
- if (certificate == null) {
- throw new NotActivatedException();
- }
- return certificate;
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
- } finally {
- getCard().endExclusive();
- }
-
+ aid = AID_SIG;
+ fid = EF_C_CH_DS;
} else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
-
- try {
- getCard().beginExclusive();
- byte[] certificate = readTLVFile(AID_DEC, EF_C_CH_EKEY, EF_C_CH_EKEY_MAX_SIZE);
- if (certificate == null) {
- throw new NotActivatedException();
- }
- return certificate;
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
- } finally {
- getCard().endExclusive();
- }
-
+ aid = AID_DEC;
+ fid = EF_C_CH_EKEY;
} else {
throw new IllegalArgumentException("Keybox " + keyboxName
+ " not supported.");
}
- } catch (CardException e) {
- log.warn(e);
- throw new SignatureCardException("Failed to access card.", e);
- }
-
+ try {
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, aid);
+ // SELECT file
+ byte[] fcx = execSELECT_FID(channel, fid);
+ int maxSize = -1;
+ if (getAppVersion() < 2) {
+ maxSize = ISO7816Utils.getLengthFromFCx(fcx);
+ log.debug("Size of selected file = " + maxSize);
+ }
+ // READ BINARY
+ byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, maxSize, (byte) 0x30);
+ if (certificate == null) {
+ throw new NotActivatedException();
+ }
+ return certificate;
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
+ } catch (CardException e) {
+ log.info("Failed to get certificate.", e);
+ throw new SignatureCardException(e);
+ }
+
+
}
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.SignatureCard#getInfobox(java.lang.String, at.gv.egiz.smcc.PINProvider, java.lang.String)
- */
@Override
+ @Exclusive
public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
throws SignatureCardException, InterruptedException {
+
+ if ("IdentityLink".equals(infobox)) {
+ if (getAppVersion() < 2) {
+ return getIdentityLinkV1(provider, domainId);
+ } else {
+ return getIdentityLinkV2(provider, domainId);
+ }
+ } else {
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
+ }
+
+ }
+
+ protected byte[] getIdentityLinkV1(PINProvider provider, String domainId)
+ throws SignatureCardException, InterruptedException {
+
+ try {
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, AID_DEC);
+ // SELECT file
+ byte[] fcx = execSELECT_FID(channel, EF_INFOBOX);
+ int maxSize = ISO7816Utils.getLengthFromFCx(fcx);
+ log.debug("Size of selected file = " + maxSize);
+ // READ BINARY
+ while(true) {
+ try {
+ return ISO7816Utils.readTransparentFileTLV(channel, maxSize, (byte) 0x30);
+ } catch (SecurityStatusNotSatisfiedException e) {
+ verifyPINLoop(channel, INF_PIN_SPEC, provider);
+ }
+ }
+
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
+ } catch (CardException e) {
+ log.info("Faild to get infobox.", e);
+ throw new SignatureCardException(e);
+ }
+
+ }
+ protected byte[] getIdentityLinkV2(PINProvider provider, String domainId)
+ throws SignatureCardException, InterruptedException {
+
try {
- if ("IdentityLink".equals(infobox)) {
-
- PINSpec spec = pinSpecs.get(PINSPEC_INF);
- //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"));
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, AID_DEC);
+ // SELECT file
+ execSELECT_FID(channel, EF_INFOBOX);
+
+ // READ BINARY
+ TransparentFileInputStream is = ISO7816Utils.openTransparentFileInputStream(channel, -1);
+
+ int b = is.read();
+ if (b == 0x00) {
+ return null;
+ }
+ if (b != 0x41 || is.read() != 0x49 || is.read() != 0x4b) {
+ String msg = "Infobox structure invalid.";
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
- int retries = -1;
- boolean pinRequired = false;
+ b = is.read();
+ if (b != 0x01) {
+ String msg = "Infobox structure v" + b + " not supported.";
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
+
+ while ((b = is.read()) != 0x01 && b != 00) {
+ is.read(); // modifiers
+ is.skip(is.read() + (is.read() << 8)); // length
+ }
+
+ if (b != 0x01) {
+ return null;
+ }
+
+ int modifiers = is.read();
+ int length = is.read() + (is.read() << 8);
- do {
- try {
- getCard().beginExclusive();
- if (pinRequired) {
- char[] pin = provider.providePIN(spec, retries);
- return readTLVFile(AID_DEC, EF_INFOBOX, pin, spec.getKID(), EF_INFOBOX_MAX_SIZE);
- } else {
- return readTLVFile(AID_DEC, EF_INFOBOX, EF_INFOBOX_MAX_SIZE);
- }
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
- } catch (SecurityStatusNotSatisfiedException e) {
- pinRequired = true;
- } catch (VerificationFailedException e) {
- pinRequired = true;
- retries = e.getRetries();
- } finally {
- getCard().endExclusive();
- }
- } while (retries != 0);
+ byte[] bytes;
+ byte[] key = null;
+
+ switch (modifiers) {
+ case 0x00:
+ bytes = new byte[length];
+ break;
+ case 0x01:
+ key = new byte[is.read() + (is.read() << 8)];
+ is.read(key);
+ bytes = new byte[length - key.length - 2];
+ break;
+ default:
+ String msg = "Compressed infobox structure not yet supported.";
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
+
+ is.read(bytes);
+
+ if (key == null) {
+ return bytes;
+ }
- throw new LockedException();
+ execMSE(channel, 0x41, 0xb8, new byte[] {
+ (byte) 0x84, (byte) 0x01, (byte) 0x88, (byte) 0x80, (byte) 0x01,
+ (byte) 0x02 });
- } else {
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
- }
+ byte[] plainKey = null;
+
+ while (true) {
+ try {
+ plainKey = execPSO_DECIPHER(channel, key);
+ break;
+ } catch(SecurityStatusNotSatisfiedException e) {
+ verifyPINLoop(channel, DEC_PIN_SPEC, provider);
+ }
+ }
+
+ try {
+ Cipher cipher = Cipher
+ .getInstance("DESede/CBC/PKCS5Padding");
+ byte[] iv = new byte[8];
+ Arrays.fill(iv, (byte) 0x00);
+ IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
+ AlgorithmParameters parameters = AlgorithmParameters
+ .getInstance("DESede");
+ parameters.init(ivParameterSpec);
+
+ DESedeKeySpec keySpec = new DESedeKeySpec(plainKey);
+ SecretKeyFactory keyFactory = SecretKeyFactory
+ .getInstance("DESede");
+ SecretKey secretKey = keyFactory.generateSecret(keySpec);
+
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, parameters);
+
+ return cipher.doFinal(bytes);
+
+ } catch (GeneralSecurityException e) {
+ String msg = "Failed to decrypt infobox.";
+ log.info(msg, e);
+ throw new SignatureCardException(msg, e);
+ }
+
+
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
} catch (CardException e) {
- log.warn(e);
- throw new SignatureCardException("Failed to access card.", e);
+ log.info("Faild to get infobox.", e);
+ throw new SignatureCardException(e);
+ } catch (IOException e) {
+ if (e.getCause() instanceof SignatureCardException) {
+ throw (SignatureCardException) e.getCause();
+ } else {
+ throw new SignatureCardException(e);
+ }
}
-
+
}
-
+
@Override
+ @Exclusive
public byte[] createSignature(byte[] hash, KeyboxName keyboxName,
PINProvider provider) throws SignatureCardException, InterruptedException {
@@ -228,87 +384,40 @@ public class ACOSCard extends AbstractSignatureCard {
try {
- if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
-
- PINSpec spec = pinSpecs.get(PINSPEC_SIG);
- //new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));
-
- int retries = -1;
- char[] pin = null;
-
- do {
- pin = provider.providePIN(spec, retries);
- try {
- getCard().beginExclusive();
-
- // SELECT DF
- selectFileFID(DF_SIG);
- // VERIFY
- retries = verifyPIN(KID_PIN_SIG, pin);
- if (retries != -1) {
- throw new VerificationFailedException(retries);
- }
- // MSE: SET DST
- mseSetDST(0x81, 0xb6, DST_SIG);
- // PSO: HASH
- psoHash(hash);
- // PSO: COMPUTE DIGITAL SIGNATURE
- return psoComputDigitalSiganture();
+ CardChannel channel = getCardChannel();
- } catch (SecurityStatusNotSatisfiedException e) {
- retries = verifyPIN(KID_PIN_SIG);
- } catch (VerificationFailedException e) {
- retries = e.getRetries();
- } finally {
- getCard().endExclusive();
- }
- } while (retries != 0);
+ if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
- throw new LockedException();
+ PINSpec spec = SIG_PIN_SPEC;
+ // SELECT application
+ execSELECT_AID(channel, AID_SIG);
+ // MANAGE SECURITY ENVIRONMENT : SET DST
+ execMSE(channel, 0x41, 0xb6, DST_SIG);
+ // VERIFY
+ verifyPINLoop(channel, spec, provider);
+ // PERFORM SECURITY OPERATION : HASH
+ execPSO_HASH(channel, hash);
+ // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATRE
+ return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel);
} else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
- PINSpec spec = pinSpecs.get(PINSPEC_DEC);
- //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name"));
-
- int retries = -1;
- char[] pin = null;
- boolean pinRequired = false;
+ PINSpec spec = DEC_PIN_SPEC;
- do {
- if (pinRequired) {
- pin = provider.providePIN(spec, retries);
- }
+ // SELECT application
+ execSELECT_AID(channel, AID_DEC);
+ // MANAGE SECURITY ENVIRONMENT : SET AT
+ execMSE(channel, 0x41, 0xa4, AT_DEC);
+
+ while (true) {
try {
- getCard().beginExclusive();
-
- // SELECT DF
- selectFileFID(DF_DEC);
- // VERIFY
- retries = verifyPIN(KID_PIN_DEC, pin);
- if (retries != -1) {
- throw new VerificationFailedException(retries);
- }
- // MSE: SET DST
- mseSetDST(0x41, 0xa4, DST_DEC);
// INTERNAL AUTHENTICATE
- return internalAuthenticate(hash);
-
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
+ return execINTERNAL_AUTHENTICATE(channel, hash);
} catch (SecurityStatusNotSatisfiedException e) {
- pinRequired = true;
- retries = verifyPIN(KID_PIN_DEC);
- } catch (VerificationFailedException e) {
- pinRequired = true;
- retries = e.getRetries();
- } finally {
- getCard().endExclusive();
+ verifyPINLoop(channel, spec, provider);
}
- } while (retries != 0);
-
- throw new LockedException();
+ }
} else {
throw new IllegalArgumentException("KeyboxName '" + keyboxName
@@ -321,377 +430,311 @@ public class ACOSCard extends AbstractSignatureCard {
}
}
+
+ public int getAppVersion() {
+ return appVersion;
+ }
- ////////////////////////////////////////////////////////////////////////
- // PROTECTED METHODS (assume exclusive card access)
- ////////////////////////////////////////////////////////////////////////
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider)
+ */
+ @Override
+ public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException,
+ TimeoutException, SignatureCardException, InterruptedException {
- protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
- return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,
- 0x00, fid, 256));
+
+ try {
+ // SELECT application
+ execSELECT_AID(channel, pinSpec.getContextAID());
+ // VERIFY
+ verifyPIN(channel, pinSpec, pinProvider, -1);
+ } catch (CardException e) {
+ log.info("Failed to verify PIN.", e);
+ throw new SignatureCardException("Failed to verify PIN.", e);
+ }
+
}
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.ChangePINProvider)
+ */
+ @Override
+ public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException,
+ TimeoutException, SignatureCardException, InterruptedException {
- private void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, p1,
- p2, dst));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("MSE:SET DST failed: SW="
- + Integer.toHexString(resp.getSW()));
+
+ try {
+ // SELECT application
+ execSELECT_AID(channel, pinSpec.getContextAID());
+ // CHANGE REFERENCE DATA
+ changePIN(channel, pinSpec, pinProvider, -1);
+ } catch (CardException e) {
+ log.info("Failed to change PIN.", e);
+ throw new SignatureCardException("Failed to change PIN.", e);
}
+
}
- private void psoHash(byte[] hash) throws CardException, SignatureCardException {
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x90,
- 0x81, hash));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("PSO:HASH failed: SW="
- + Integer.toHexString(resp.getSW()));
- }
+ @Override
+ public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws CancelledException, SignatureCardException, CancelledException,
+ TimeoutException, InterruptedException {
+ log.error("ACTIVATE PIN not supported by ACOS");
+ throw new SignatureCardException("PIN activation not supported by this card.");
}
- private byte[] psoComputDigitalSiganture() throws CardException,
- SignatureCardException {
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x9E,
- 0x9A, 256));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException(
- "PSO: COMPUTE DIGITAL SIGNATRE failed: SW="
- + Integer.toHexString(resp.getSW()));
- } else {
- return resp.getData();
- }
+ @Override
+ public void unblockPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws CancelledException, SignatureCardException, InterruptedException {
+ throw new SignatureCardException("Unblock PIN not supported.");
}
- private byte[] internalAuthenticate(byte[] hash) throws CardException, SignatureCardException {
- byte[] digestInfo = 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[] data = new byte[digestInfo.length + hash.length + 1];
-
- System.arraycopy(digestInfo, 0, data, 0, digestInfo.length);
- data[digestInfo.length] = (byte) hash.length;
- System.arraycopy(hash, 0, data, digestInfo.length + 1, hash.length);
-
- CardChannel channel = getCardChannel();
-
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x88, 0x10, 0x00, data, 256));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("INTERNAL AUTHENTICATE failed: SW=" + Integer.toHexString(resp.getSW()));
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPINSpecs()
+ */
+ @Override
+ public List<PINSpec> getPINSpecs() {
+ if (getAppVersion() < 2) {
+ return Arrays.asList(new PINSpec[] {DEC_PIN_SPEC, SIG_PIN_SPEC, INF_PIN_SPEC});
} else {
- return resp.getData();
+ return Arrays.asList(new PINSpec[] {DEC_PIN_SPEC, SIG_PIN_SPEC});
}
}
- /**
- *
- * @param kid
- * @return -1
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPINStatus(at.gv.egiz.smcc.PINSpec)
*/
@Override
- protected int verifyPIN(byte kid) {
- log.debug("VERIFY PIN without PIN BLOCK not supported by ACOS");
- return -1;
+ public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException {
+ return PIN_STATE.UNKNOWN;
}
@Override
- protected int verifyPIN(byte kid, char[] pin)
- throws LockedException, NotActivatedException, CancelledException, TimeoutException, PINFormatException, PINOperationAbortedException, SignatureCardException {
- try {
- byte[] sw;
- if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) {
- log.debug("verify pin on cardreader");
- sw = reader.verifyPinDirect(getPINVerifyStructure(kid));
-// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
- } else if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_START)) {
- log.debug("verify pin on cardreader");
- sw = reader.verifyPin(getPINVerifyStructure(kid));
- } else {
- byte[] pinBlock = encodePINBlock(pin);
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false);
- sw = new byte[2];
- sw[0] = (byte) resp.getSW1();
- sw[1] = (byte) resp.getSW2();
- }
+ public String toString() {
+ return "a-sign premium";
+ }
- //6A 00 (falshe P1/P2) nicht in contextAID
- //69 85 (nutzungsbedingungen nicht erfüllt) in DF_Sig und nicht sigpin
-
- if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
- return -1;
- } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
- throw new LockedException("[63:c0]");
- } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
- return sw[1] & 0x0f;
- } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
- //Authentisierungsmethode gesperrt
- throw new NotActivatedException("[69:83]");
-// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
-// //referenzierte Daten sind reversibel gesperrt (invalidated)
-// throw new NotActivatedException("[69:84]");
-// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
-// //Benutzungsbedingungen nicht erfüllt
-// throw new NotActivatedException("[69:85]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
- throw new TimeoutException("[64:00]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
- throw new CancelledException("[64:01]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) {
- throw new PINFormatException("[64:03]");
- }
- log.error("Failed to verify pin: SW="
- + SMCCHelper.toString(sw));
- throw new SignatureCardException(SMCCHelper.toString(sw));
+ ////////////////////////////////////////////////////////////////////////
+ // PROTECTED METHODS (assume exclusive card access)
+ ////////////////////////////////////////////////////////////////////////
- } catch (CardException ex) {
- log.error("smart card communication failed: " + ex.getMessage());
- throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
- }
+ protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINProvider provider)
+ throws InterruptedException, LockedException, NotActivatedException,
+ TimeoutException, PINFormatException, PINOperationAbortedException,
+ SignatureCardException, CardException {
+
+ int retries = -1;
+ do {
+ retries = verifyPIN(channel, spec, provider, retries);
+ } while (retries > 0);
+
}
- /**
- * SCARD_E_NOT_TRANSACTED inf/dec PIN not active (pcsc crash)
- * @param kid
- * @param oldPin
- * @param newPin
- * @return
- * @throws at.gv.egiz.smcc.LockedException
- * @throws at.gv.egiz.smcc.NotActivatedException
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
- @Override
- protected int changePIN(byte kid, char[] oldPin, char[] newPin)
- throws LockedException, NotActivatedException, CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException {
- try {
- byte[] sw;
- if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) {
- log.debug("modify pin on cardreader");
- sw = reader.modifyPinDirect(getPINModifyStructure(kid));
- } else if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_START)) {
- log.debug("modify pin on cardreader");
- sw = reader.modifyPin(getPINModifyStructure(kid));
- } else {
- byte[] cmd = new byte[16];
- System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8);
- System.arraycopy(encodePINBlock(newPin), 0, cmd, 8, 8);
-
- CardChannel channel = getCardChannel();
+ protected int verifyPIN(CardChannel channel, PINSpec pinSpec,
+ PINProvider provider, int retries) throws InterruptedException, CardException, SignatureCardException {
+
+ VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, pinSpec.getKID(), (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 },
+ 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
+
+ ResponseAPDU resp = reader.verify(channel, apduSpec, pinSpec, provider, retries);
+
+ if (resp.getSW() == 0x9000) {
+ return -1;
+ }
+ if (resp.getSW() >> 4 == 0x63c) {
+ return 0x0f & resp.getSW();
+ }
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0x24, 0x00, kid, cmd), false);
+ switch (resp.getSW()) {
+ case 0x6983:
+ // authentication method blocked
+ throw new LockedException();
+
+ default:
+ String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW());
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
- sw = new byte[2];
- sw[0] = (byte) resp.getSW1();
- sw[1] = (byte) resp.getSW2();
- }
+ }
- // activates pin (newPIN) if not active
- if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
- return -1;
- } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
- throw new LockedException("[63:c0]");
- } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
- return sw[1] & 0x0f;
- } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
- //Authentisierungsmethode gesperrt
- // sig-pin only (card not transacted for inf/dec pin)
- throw new NotActivatedException("[69:83]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
- throw new TimeoutException("[64:00]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
- throw new CancelledException("[64:01]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x02) {
- throw new PINConfirmationException("[64:02]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) {
- throw new PINFormatException("[64:03]");
- } else if (sw[0] == (byte) 0x6a && sw[1] == (byte) 0x80) {
- log.info("invalid parameter, assume wrong pin size");
- throw new PINFormatException("[6a:80]");
- }
- log.error("Failed to change pin: SW="
- + SMCCHelper.toString(sw));
- throw new SignatureCardException(SMCCHelper.toString(sw));
+ protected int changePIN(CardChannel channel, PINSpec pinSpec,
+ ChangePINProvider pinProvider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException {
+
+ ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.getKID(), (byte) 0x10,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ },
+ 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
+
+
+
+ ResponseAPDU resp = reader.modify(channel, apduSpec, pinSpec, pinProvider, retries);
+
+ if (resp.getSW() == 0x9000) {
+ return -1;
+ }
+ if (resp.getSW() >> 4 == 0x63c) {
+ return 0x0f & resp.getSW();
+ }
+
+ switch (resp.getSW()) {
+ case 0x6983:
+ // authentication method blocked
+ throw new LockedException();
+
+ default:
+ String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW());
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
+
+ }
- } catch (CardException ex) {
- log.error("smart card communication failed: " + ex.getMessage());
- throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
+ protected byte[] execSELECT_AID(CardChannel channel, byte[] aid)
+ throws SignatureCardException, CardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0xA4, 0x04, 0x00, aid, 256));
+
+ if (resp.getSW() == 0x6A82) {
+ String msg = "File or application not found AID="
+ + SMCCHelper.toString(aid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.info(msg);
+ throw new FileNotFoundException(msg);
+ } else if (resp.getSW() != 0x9000) {
+ String msg = "Failed to select application AID="
+ + SMCCHelper.toString(aid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ } else {
+ return resp.getBytes();
}
+
}
+
+ protected byte[] execSELECT_FID(CardChannel channel, byte[] fid)
+ throws SignatureCardException, CardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0xA4, 0x00, 0x00, fid, 256));
+
+ if (resp.getSW() == 0x6A82) {
+ String msg = "File or application not found FID="
+ + SMCCHelper.toString(fid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.info(msg);
+ throw new FileNotFoundException(msg);
+ } else if (resp.getSW() != 0x9000) {
+ String msg = "Failed to select application FID="
+ + SMCCHelper.toString(fid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.error(msg);
+ throw new SignatureCardException(msg);
+ } else {
+ return resp.getBytes();
+ }
- /**
- * throws SignatureCardException (PIN activation not supported by ACOS)
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
- @Override
- public void activatePIN(byte kid, char[] pin)
- throws SignatureCardException {
- log.error("ACTIVATE PIN not supported by ACOS");
- throw new SignatureCardException("PIN activation not supported by this card");
+
}
+
+ protected void execMSE(CardChannel channel, int p1,
+ int p2, byte[] data) throws SignatureCardException, CardException {
- /**
- * ASCII encoded pin, padded with 0x00
- * @param pin
- * @return a 8 byte pin block
- */
- @Override
- protected byte[] encodePINBlock(char[] pin) {
-// byte[] asciiPIN = new String(pin).getBytes(Charset.forName("ASCII"));
- CharBuffer chars = CharBuffer.wrap(pin);
- ByteBuffer bytes = Charset.forName("ASCII").encode(chars);
- byte[] asciiPIN = bytes.array();
- byte[] encodedPIN = new byte[8];
- System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length,
- encodedPIN.length));
-// System.out.println("ASCII encoded PIN block: " + SMCCHelper.toString(encodedPIN));
- return encodedPIN;
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x22, p1, p2, data));
+
+ if (resp.getSW() != 0x9000) {
+ String msg = "MSE failed: SW="
+ + Integer.toHexString(resp.getSW());
+ log.error(msg);
+ throw new SignatureCardException(msg);
+ }
+
}
- private byte[] getPINVerifyStructure(byte kid) {
-
- byte bTimeOut = reader.getbTimeOut();
- byte bTimeOut2 = reader.getbTimeOut2();
- byte bmFormatString = (byte) 0x82; // 1 0000 0 10
- // ^------------ System unit = byte
- // ^^^^------- PIN position in the frame = 1 byte
- // ^----- PIN justification left
- // ^^-- ASCII format
- byte bmPINBlockString = (byte) 0x08; // 0000 1000
- // ^^^^--------- PIN length size: 0 bits
- // ^^^^---- Length PIN = 8 bytes
- byte bmPINLengthFormat = (byte) 0x00; // 000 0 0000
- // ^-------- System bit units is bit
- // ^^^^--- no PIN length
- byte wPINMaxExtraDigitL = //TODO compare ints, not bytes
- (reader.getwPINMaxExtraDigitL() < (byte) 0x08) ?
- reader.getwPINMaxExtraDigitL() : (byte) 0x08;
- byte wPINMaxExtraDigitH =
- (reader.getwPINMaxExtraDigitH() > (byte) 0x00) ?
- reader.getwPINMaxExtraDigitH() : (byte) 0x00;
- byte bEntryValidationCondition =
- reader.getbEntryValidationCondition();
- byte bNumberMessage = (byte) 0x00; // No message
- byte wLangIdL = (byte) 0x0C;
- byte wLangIdH = (byte) 0x04;
- byte bMsgIndex = (byte) 0x00;
-
- byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
- };
-
- int offset = 0;
- byte[] pinVerifyStructure = new byte[offset + 19 + apdu.length];
- pinVerifyStructure[offset++] = bTimeOut;
- pinVerifyStructure[offset++] = bTimeOut2;
- pinVerifyStructure[offset++] = bmFormatString;
- pinVerifyStructure[offset++] = bmPINBlockString;
- pinVerifyStructure[offset++] = bmPINLengthFormat;
- pinVerifyStructure[offset++] = wPINMaxExtraDigitL;
- pinVerifyStructure[offset++] = wPINMaxExtraDigitH;
- pinVerifyStructure[offset++] = bEntryValidationCondition;
- pinVerifyStructure[offset++] = bNumberMessage;
- pinVerifyStructure[offset++] = wLangIdL;
- pinVerifyStructure[offset++] = wLangIdH;
- pinVerifyStructure[offset++] = bMsgIndex;
-
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
-
- pinVerifyStructure[offset++] = (byte) apdu.length;
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
- System.arraycopy(apdu, 0, pinVerifyStructure, offset, apdu.length);
-
- return pinVerifyStructure;
+ protected byte[] execPSO_DECIPHER(CardChannel channel, byte [] cipher) throws CardException, SignatureCardException {
+
+ byte[] data = new byte[cipher.length + 1];
+ data[0] = 0x00;
+ System.arraycopy(cipher, 0, data, 1, cipher.length);
+ ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x2A, 0x80, 0x86, data, 256));
+ if (resp.getSW() == 0x6982) {
+ throw new SecurityStatusNotSatisfiedException();
+ } else if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException(
+ "PSO - DECIPHER failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ }
+
+ return resp.getData();
+
}
- public byte[] getPINModifyStructure(byte kid) {
-
- byte bTimeOut = reader.getbTimeOut();
- byte bTimeOut2 = reader.getbTimeOut2();
- byte bmFormatString = (byte) 0x82; // 1 0000 0 10
- // ^------------ System unit = byte
- // ^^^^------- PIN position in the frame = 1 byte
- // ^----- PIN justification left
- // ^^-- ASCII format
- byte bmPINBlockString = (byte) 0x08; // 0000 1000
- // ^^^^--------- PIN length size: 0 bits
- // ^^^^---- Length PIN = 8 bytes
- byte bmPINLengthFormat = (byte) 0x00; // 000 0 0000
- // ^-------- System bit units is bit
- // ^^^^--- no PIN length
- byte bInsertionOffsetOld = (byte) 0x00; // insertion position offset in bytes
- byte bInsertionOffsetNew = (byte) 0x08;
- byte wPINMaxExtraDigitL =
- (reader.getwPINMaxExtraDigitL() < (byte) 0x08) ?
- reader.getwPINMaxExtraDigitL() : (byte) 0x08;
- byte wPINMaxExtraDigitH =
- (reader.getwPINMaxExtraDigitH() > (byte) 0x00) ?
- reader.getwPINMaxExtraDigitH() : (byte) 0x00;
- byte bConfirmPIN = (byte) 0x03;
- byte bEntryValidationCondition =
- reader.getbEntryValidationCondition();
- byte bNumberMessage = (byte) 0x03;
- byte wLangIdL = (byte) 0x0C;
- byte wLangIdH = (byte) 0x04;
- byte bMsgIndex1 = (byte) 0x00;
- byte bMsgIndex2 = (byte) 0x01;
- byte bMsgIndex3 = (byte) 0x02;
-
- byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
- };
-
- int offset = 0;
- byte[] pinModifyStructure = new byte[offset + 24 + apdu.length];
- pinModifyStructure[offset++] = bTimeOut;
- pinModifyStructure[offset++] = bTimeOut2;
- pinModifyStructure[offset++] = bmFormatString;
- pinModifyStructure[offset++] = bmPINBlockString;
- pinModifyStructure[offset++] = bmPINLengthFormat;
- pinModifyStructure[offset++] = bInsertionOffsetOld;
- pinModifyStructure[offset++] = bInsertionOffsetNew;
- pinModifyStructure[offset++] = wPINMaxExtraDigitL;
- pinModifyStructure[offset++] = wPINMaxExtraDigitH;
- pinModifyStructure[offset++] = bConfirmPIN;
- pinModifyStructure[offset++] = bEntryValidationCondition;
- pinModifyStructure[offset++] = bNumberMessage;
- pinModifyStructure[offset++] = wLangIdL;
- pinModifyStructure[offset++] = wLangIdH;
- pinModifyStructure[offset++] = bMsgIndex1;
- pinModifyStructure[offset++] = bMsgIndex2;
- pinModifyStructure[offset++] = bMsgIndex3;
-
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
-
- pinModifyStructure[offset++] = (byte) apdu.length;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- System.arraycopy(apdu, 0, pinModifyStructure, offset, apdu.length);
-
- return pinModifyStructure;
+ protected void execPSO_HASH(CardChannel channel, byte[] hash) throws CardException, SignatureCardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x2A, 0x90, 0x81, hash));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("PSO - HASH failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ }
+
}
+
+ protected byte[] execPSO_COMPUTE_DIGITAL_SIGNATURE(CardChannel channel) throws CardException,
+ SignatureCardException {
- @Override
- public String toString() {
- return "a-sign premium";
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x2A, 0x9E, 0x9A, 256));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException(
+ "PSO - COMPUTE DIGITAL SIGNATRE failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ } else {
+ return resp.getData();
+ }
+
+ }
+
+ protected byte[] execINTERNAL_AUTHENTICATE(CardChannel channel, byte[] hash) throws CardException,
+ SignatureCardException {
+
+ byte[] digestInfo = 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[] data = new byte[digestInfo.length + hash.length + 1];
+
+ System.arraycopy(digestInfo, 0, data, 0, digestInfo.length);
+ data[digestInfo.length] = (byte) hash.length;
+ System.arraycopy(hash, 0, data, digestInfo.length + 1, hash.length);
+
+ ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x88, 0x10, 0x00, data, 256));
+ if (resp.getSW() == 0x6982) {
+ throw new SecurityStatusNotSatisfiedException();
+ } else if (resp.getSW() == 0x6983) {
+ throw new LockedException();
+ } else if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("INTERNAL AUTHENTICATE failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ } else {
+ return resp.getData();
+ }
}
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
index f0f8b8c8..54b4c7fe 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
@@ -1,55 +1,37 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
package at.gv.egiz.smcc;
-import at.gv.egiz.smcc.ccid.CCID;
-import at.gv.egiz.smcc.ccid.ReaderFactory;
-import at.gv.egiz.smcc.util.SMCCHelper;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
-import javax.smartcardio.ATR;
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import at.gv.egiz.smcc.ccid.CCID;
+import at.gv.egiz.smcc.ccid.ReaderFactory;
+
public abstract class AbstractSignatureCard implements SignatureCard {
private static Log log = LogFactory.getLog(AbstractSignatureCard.class);
@@ -61,14 +43,8 @@ public abstract class AbstractSignatureCard implements SignatureCard {
private Locale locale = Locale.getDefault();
- int ifs_ = 254;
-
private Card card_;
- /**
- * The card terminal that connects the {@link #card_}.
- */
-// private CardTerminal cardTerminal;
protected CCID reader;
protected AbstractSignatureCard(String resourceBundleName) {
@@ -89,379 +65,10 @@ public abstract class AbstractSignatureCard implements SignatureCard {
return sb.toString();
}
- /**
- * Select an application using AID as DF name according to ISO/IEC 7816-4
- * section 8.2.2.2.
- *
- * @param dfName
- * AID of the application to be selected
- *
- * @return the response data of the response APDU if SW=0x9000
- *
- * @throws CardException
- * if card communication fails
- *
- * @throws SignatureCardException
- * if application selection fails (e.g. an application with the
- * given AID is not present on the card)
- */
- protected byte[] selectFileAID(byte[] dfName) throws CardException, SignatureCardException {
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0xA4, 0x04, 0x00, dfName, 256));
-// new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, dfName));
- if (resp.getSW() != 0x9000) {
- String msg = "Failed to select application AID=" + SMCCHelper.toString(dfName) +
- ": SW=" + Integer.toHexString(resp.getSW());
- log.error(msg);
- throw new SignatureCardException(msg);
- } else {
- return resp.getBytes();
- }
- }
-
- protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException,
- SignatureCardException;
-
- /**
- * VERIFY APDU without PIN BLOCK
- * Not supported by ACOS cards (and GemPC Pinpad?)
- * @param kid
- * @return the number of possible tries until card is blocked or -1 if unknown
- * (ACOS does not support this VERIFY APDU type)
- * @throws at.gv.egiz.smcc.LockedException
- * @throws at.gv.egiz.smcc.NotActivatedException
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
- protected abstract int verifyPIN(byte kid)
- throws LockedException, NotActivatedException, SignatureCardException;
-
- /**
- * VERIFY APDU with PIN BLOCK
- * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty.
- * @param kid
- * @param pin to be encoded in the PIN BLOCK
- * @return -1 if VERIFY PIN was successful, or the number of possible retries
- * @throws at.gv.egiz.smcc.LockedException
- * @throws at.gv.egiz.smcc.NotActivatedException
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
- protected abstract int verifyPIN(byte kid, char[] pin)
- throws LockedException, NotActivatedException, CancelledException, PINFormatException, TimeoutException, PINOperationAbortedException, SignatureCardException;
-
- /**
- * CHANGE(?) APDU
- * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty.
- * @param kid
- * @param pin
- * @throws at.gv.egiz.smcc.SignatureCardException if activation fails
- */
- protected abstract void activatePIN(byte kid, char[] pin)
- throws CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException;
-
- /**
- * CHANGE(?) APDU
- * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty.
- * @param kid
- * @param pin
- * @return -1 if CHANGE PIN was successful, or the number of possible retries
- * @throws at.gv.egiz.smcc.SignatureCardException if change fails
- */
- protected abstract int changePIN(byte kid, char[] oldPin, char[] newPin)
- throws LockedException, NotActivatedException, CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException;
-
- /**
- * encode the pin as needed in VERIFY/CHANGE APDUs
- * @param pin
- * @return
- * @throws at.gv.egiz.smcc.SignatureCardException if the provided pin does
- * not meet the restrictions imposed by the encoding (not the pinSpec!),
- * such as maximum Length
- */
- protected abstract byte[] encodePINBlock(char[] pin) throws SignatureCardException;
-
- protected byte[] readRecord(int recordNumber) throws SignatureCardException, CardException {
- return readRecord(getCardChannel(), recordNumber);
- }
-
- protected byte[] readRecord(CardChannel channel, int recordNumber) throws SignatureCardException, CardException {
-
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB2,
- recordNumber, 0x04, 256));
- if (resp.getSW() == 0x9000) {
- return resp.getData();
- } else {
- throw new SignatureCardException("Failed to read records. SW=" + Integer.toHexString(resp.getSW()));
- }
-
- }
-
- protected byte[] readBinary(CardChannel channel, int offset, int len)
- throws CardException, SignatureCardException {
-
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB0,
- 0x7F & (offset >> 8), offset & 0xFF, len));
- if (resp.getSW() == 0x9000) {
- return resp.getData();
- } else if (resp.getSW() == 0x6982) {
- throw new SecurityStatusNotSatisfiedException();
- } else {
- throw new SignatureCardException("Failed to read bytes (" + offset + "+"
- + len + "): SW=" + Integer.toHexString(resp.getSW()));
- }
-
- }
-
- protected int readBinary(int offset, int len, byte[] b) throws CardException,
- SignatureCardException {
-
- if (b.length < len) {
- throw new IllegalArgumentException(
- "Length of b must not be less than len.");
- }
-
- CardChannel channel = getCardChannel();
-
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB0,
- 0x7F & (offset >> 8), offset & 0xFF, len));
- if (resp.getSW() == 0x9000) {
- System.arraycopy(resp.getData(), 0, b, 0, len);
- }
-
- return resp.getSW();
-
- }
-
- protected byte[] readBinaryTLV(int maxSize, byte expectedType) throws CardException,
- SignatureCardException {
-
- CardChannel channel = getCardChannel();
-
- // read first chunk
- int len = Math.min(maxSize, ifs_);
- byte[] chunk = readBinary(channel, 0, len);
- if (chunk.length > 0 && chunk[0] != expectedType) {
- return null;
- }
- int offset = chunk.length;
- int actualSize = maxSize;
- if (chunk.length > 3) {
- if ((chunk[1] & 0x80) > 0) {
- int octets = (0x0F & chunk[1]);
- actualSize = 2 + octets;
- for (int i = 1; i <= octets; i++) {
- actualSize += (0xFF & chunk[i + 1]) << ((octets - i) * 8);
- }
- } else {
- actualSize = 2 + chunk[1];
- }
- }
- ByteBuffer buffer = ByteBuffer.allocate(actualSize);
- buffer.put(chunk, 0, Math.min(actualSize, chunk.length));
- while (offset < actualSize) {
- len = Math.min(ifs_, actualSize - offset);
- chunk = readBinary(channel, offset, len);
- buffer.put(chunk);
- offset += chunk.length;
- }
- return buffer.array();
-
- }
-
- protected byte[] readRecords(byte[] aid, byte[] ef, int start, int end) throws SignatureCardException, InterruptedException {
-
- try {
-
- // SELECT FILE (AID)
- byte[] rb = selectFileAID(aid);
- if (rb[rb.length - 2] != (byte) 0x90 || rb[rb.length - 1] != (byte) 0x00) {
-
- throw new SignatureCardException("SELECT FILE with "
- + "AID="
- + toString(aid)
- + " failed ("
- + "SW="
- + Integer.toHexString((0xFF & (int) rb[rb.length - 1])
- | (0xFF & (int) rb[rb.length - 2]) << 8) + ").");
-
- }
-
- // SELECT FILE (EF)
- ResponseAPDU resp = selectFileFID(ef);
- if (resp.getSW() == 0x6a82) {
-
- // EF not found
- throw new FileNotFoundException("EF " + toString(ef) + " not found.");
-
- } else if (resp.getSW() != 0x9000) {
-
- throw new SignatureCardException("SELECT FILE with "
- + "FID="
- + toString(ef)
- + " failed ("
- + "SW="
- + Integer.toHexString(resp.getSW()) + ").");
-
- }
-
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-
- for (int i = start; i <= end; i++) {
- bytes.write(readRecord(i));
- }
-
- return bytes.toByteArray();
-
- } catch (CardException e) {
- throw new SignatureCardException("Failed to acces card.", e);
- } catch (IOException e) {
- throw new SignatureCardException("Failed to read records.", e);
- }
-
- }
-
- /**
- * Read the content of a TLV file.
- *
- * @param aid the application ID (AID)
- * @param ef the elementary file (EF)
- * @param maxLength the maximum length of the file
- *
- * @return the content of the file
- *
- * @throws SignatureCardException
- * @throws CardException
- */
- protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength)
- throws SignatureCardException, InterruptedException, CardException {
- // SELECT FILE (AID)
- selectFileAID(aid);
-
- // SELECT FILE (EF)
- ResponseAPDU resp = selectFileFID(ef);
- if (resp.getSW() == 0x6a82) {
- // EF not found
- throw new FileNotFoundException("EF " + toString(ef) + " not found.");
- } else if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("SELECT FILE with "
- + "FID="
- + toString(ef)
- + " failed ("
- + "SW="
- + Integer.toHexString(resp.getSW()) + ").");
- }
-
- return readBinaryTLV(maxLength, (byte) 0x30);
-// return readTLVFile(aid, ef, null, (byte) 0, maxLength);
- }
-
- /**
- * Read the content of a TLV file wich requires a PIN.
- *
- * @param aid the application ID (AID)
- * @param ef the elementary file (EF)
- * @param kid the key ID (KID) of the corresponding PIN
- * @param pin the pin or null if VERIFY on pinpad
- * @param spec the PINSpec
- * @param maxLength the maximum length of the file
- *
- * @return the content of the file
- *
- * @throws SignatureCardException
- * @throws CardException
- */
- protected byte[] readTLVFile(byte[] aid, byte[] ef, char[] pin, byte kid, int maxLength)
- throws SignatureCardException, InterruptedException, CardException {
-
-
- // SELECT FILE (AID)
- selectFileAID(aid);
-
- // SELECT FILE (EF)
- ResponseAPDU resp = selectFileFID(ef);
- if (resp.getSW() == 0x6a82) {
- // EF not found
- throw new FileNotFoundException("EF " + toString(ef) + " not found.");
- } else if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("SELECT FILE with "
- + "FID="
- + toString(ef)
- + " failed ("
- + "SW="
- + Integer.toHexString(resp.getSW()) + ").");
- }
-
- // VERIFY
- int retries = verifyPIN(kid, pin);
- if (retries != -1) {
- throw new VerificationFailedException(retries);
- }
-
- return readBinaryTLV(maxLength, (byte) 0x30);
-
-
- }
-
- /**
- * Transmit the given command APDU using the given card channel.
- *
- * @param channel
- * the card channel
- * @param commandAPDU
- * the command APDU
- * @param logData
- * <code>true</code> if command APDU data may be logged, or
- * <code>false</code> otherwise
- *
- * @return the corresponding response APDU
- *
- * @throws CardException
- * if smart card communication fails
- */
- protected ResponseAPDU transmit(CardChannel channel, CommandAPDU commandAPDU, boolean logData)
- throws CardException {
-
- if (log.isTraceEnabled()) {
- log.trace(commandAPDU
- + (logData ? "\n" + toString(commandAPDU.getBytes()) : ""));
- long t0 = System.currentTimeMillis();
- ResponseAPDU responseAPDU = channel.transmit(commandAPDU);
- long t1 = System.currentTimeMillis();
- log.trace(responseAPDU + "\n[" + (t1 - t0) + "ms] "
- + (logData ? "\n" + toString(responseAPDU.getBytes()) : ""));
- return responseAPDU;
- } else {
- return channel.transmit(commandAPDU);
- }
-
- }
-
- /**
- * Transmit the given command APDU using the given card channel.
- *
- * @param channel the card channel
- * @param commandAPDU the command APDU
- *
- * @return the corresponding response APDU
- *
- * @throws CardException if smart card communication fails
- */
- protected ResponseAPDU transmit(CardChannel channel, CommandAPDU commandAPDU)
- throws CardException {
- return transmit(channel, commandAPDU, true);
- }
-
-
@Override
public void init(Card card, CardTerminal cardTerminal) {
this.card_ = card;
this.reader = ReaderFactory.getInstance().getReader(card, cardTerminal);
- ATR atr = card.getATR();
- byte[] atrBytes = atr.getBytes();
- if (atrBytes.length >= 6) {
- ifs_ = 0xFF & atr.getBytes()[6];
- log.trace("Setting IFS (information field size) to " + ifs_);
- }
}
@Override
@@ -470,7 +77,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
protected CardChannel getCardChannel() {
- return card_.getBasicChannel();
+ return new LogCardChannel(card_.getBasicChannel());
}
@Override
@@ -517,112 +124,4 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
}
- @Override
- public List<PINSpec> getPINSpecs() {
- return pinSpecs;
- }
-
- @Override
- public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
- throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException {
- try {
- getCard().beginExclusive();
-
- if (pinSpec.getContextAID() != null) {
- selectFileAID(pinSpec.getContextAID());
- }
-
- // -1 if ok or unknown
- int retries = verifyPIN(pinSpec.getKID());
- do {
- char[] pin = pinProvider.providePIN(pinSpec, retries);
- retries = verifyPIN(pinSpec.getKID(), pin);
- } while (retries > 0);
- //return on -1, 0 never reached: verifyPIN throws LockedEx
-
- } catch (CardException ex) {
- log.error("failed to verify " + pinSpec.getLocalizedName() +
- ": " + ex.getMessage(), ex);
- throw new SignatureCardException(ex);
- } finally {
- try {
- getCard().endExclusive();
- } catch (CardException ex) {
- log.trace("failed to end exclusive card access: " + ex.getMessage());
- }
- }
- }
-
- @Override
- public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
- throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException {
- try {
- getCard().beginExclusive();
-
- if (pinSpec.getContextAID() != null) {
- selectFileAID(pinSpec.getContextAID());
- }
- char[] pin = pinProvider.providePIN(pinSpec, -1);
- activatePIN(pinSpec.getKID(), pin);
-
- } catch (CardException ex) {
- log.error("Failed to activate " + pinSpec.getLocalizedName() +
- ": " + ex.getMessage());
- throw new SignatureCardException(ex.getMessage(), ex);
- } finally {
- try {
- getCard().endExclusive();
- } catch (CardException ex) {
- log.trace("failed to end exclusive card access: " + ex.getMessage());
- }
- }
- }
-
- /**
- * activates pin (newPIN) if not active
- * @param pinSpec
- * @param oldPIN
- * @param newPIN
- * @throws at.gv.egiz.smcc.LockedException
- * @throws at.gv.egiz.smcc.VerificationFailedException
- * @throws at.gv.egiz.smcc.NotActivatedException
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
- @Override
- public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
- throws LockedException, NotActivatedException, CancelledException,
- TimeoutException, SignatureCardException, InterruptedException {
- try {
- getCard().beginExclusive();
-
- if (pinSpec.getContextAID() != null) {
- selectFileAID(pinSpec.getContextAID());
- }
-
- int retries = verifyPIN(pinSpec.getKID());
- do {
- char[] newPin = pinProvider.providePIN(pinSpec, retries);
- char[] oldPin = pinProvider.provideOldPIN(pinSpec, retries);
- retries = changePIN(pinSpec.getKID(), oldPin, newPin);
- } while (retries > 0);
- //return on -1, 0 never reached: verifyPIN throws LockedEx
-
- } catch (CardException ex) {
- log.error("Failed to change " + pinSpec.getLocalizedName() +
- ": " + ex.getMessage());
- throw new SignatureCardException(ex.getMessage(), ex);
- } finally {
- try {
- getCard().endExclusive();
- } catch (CardException ex) {
- log.trace("failed to end exclusive card access: " + ex.getMessage());
- }
- }
- }
-
- @Override
- public void unblockPIN(PINSpec pinSpec, PINProvider pinProvider)
- throws CancelledException, SignatureCardException, InterruptedException {
- throw new SignatureCardException("Unblock not supported yet");
- }
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/CardNotSupportedException.java b/smcc/src/main/java/at/gv/egiz/smcc/CardNotSupportedException.java
index e2a5fe16..1cde093d 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/CardNotSupportedException.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/CardNotSupportedException.java
@@ -1,31 +1,19 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
package at.gv.egiz.smcc;
public class CardNotSupportedException extends Exception {
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
index d0622aa4..41010551 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
@@ -1,24 +1,21 @@
/*
- * Copyright 2008 Federal Chancellery Austria and
- * Graz University of Technology
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
package at.gv.egiz.smcc;
-import at.gv.egiz.smcc.*;
-
/**
*
* @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java
new file mode 100644
index 00000000..0b10d88f
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java
@@ -0,0 +1,95 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc;
+
+public class ChangeReferenceDataAPDUSpec extends VerifyAPDUSpec {
+
+ /**
+ * The offset for the insertion of the old PIN. (Default: 0)
+ */
+ protected int pinInsertionOffsetOld = 0;
+
+ /**
+ * The offset for the insertion of the new PIN. (Default:
+ * {@link VerifyAPDUSpec#pinLength} + 1})
+ */
+ protected int pinInsertionOffsetNew = pinLength;
+
+ public ChangeReferenceDataAPDUSpec(byte[] apdu, int pinPosition, int pinFormat, int pinLength) {
+ super(apdu, pinPosition, pinFormat, pinLength);
+ }
+
+ /**
+ * @param apdu
+ * @param pinPosition
+ * @param pinFormat
+ * @param pinLength
+ * @param pinLengthSize
+ * @param pinLengthPos
+ */
+ public ChangeReferenceDataAPDUSpec(byte[] apdu, int pinPosition,
+ int pinFormat, int pinLength, int pinLengthSize, int pinLengthPos) {
+ super(apdu, pinPosition, pinFormat, pinLength, pinLengthSize, pinLengthPos);
+ }
+
+ /**
+ * @param apdu
+ * @param pinPosition
+ * @param pinFormat
+ * @param pinLength
+ * @param pinLengthSize
+ * @param pinLengthPos
+ * @param pinInsertionOffsetNew
+ */
+ public ChangeReferenceDataAPDUSpec(byte[] apdu, int pinPosition,
+ int pinFormat, int pinLength, int pinLengthSize, int pinLengthPos,
+ int pinInsertionOffsetNew) {
+ super(apdu, pinPosition, pinFormat, pinLength, pinLengthSize, pinLengthPos);
+ this.pinInsertionOffsetNew = pinInsertionOffsetNew;
+ }
+
+ /**
+ * @return the pinInsertionOffsetOld
+ */
+ public int getPinInsertionOffsetOld() {
+ return pinInsertionOffsetOld;
+ }
+
+ /**
+ * @param pinInsertionOffsetOld the pinInsertionOffsetOld to set
+ */
+ public void setPinInsertionOffsetOld(int pinInsertionOffsetOld) {
+ this.pinInsertionOffsetOld = pinInsertionOffsetOld;
+ }
+
+ /**
+ * @return the pinInsertionOffsetNew
+ */
+ public int getPinInsertionOffsetNew() {
+ return pinInsertionOffsetNew;
+ }
+
+ /**
+ * @param pinInsertionOffsetNew the pinInsertionOffsetNew to set
+ */
+ public void setPinInsertionOffsetNew(int pinInsertionOffsetNew) {
+ this.pinInsertionOffsetNew = pinInsertionOffsetNew;
+ }
+
+
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java b/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java
new file mode 100644
index 00000000..bfbd0063
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class ExclSignatureCardProxy implements InvocationHandler {
+
+ private static Log log = LogFactory.getLog(ExclSignatureCardProxy.class);
+
+ private static final Method init;
+
+ static {
+ try {
+ init = SignatureCard.class.getMethod("init", new Class<?>[] { Card.class,
+ CardTerminal.class });
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private SignatureCard signatureCard;
+
+ public ExclSignatureCardProxy(SignatureCard signatureCard) {
+ this.signatureCard = signatureCard;
+ }
+
+ public static SignatureCard newInstance(SignatureCard signatureCard) {
+ ArrayList<Class<?>> proxyInterfaces = new ArrayList<Class<?>>();
+ proxyInterfaces.add(SignatureCard.class);
+ if (PINMgmtSignatureCard.class.isAssignableFrom(signatureCard.getClass())) {
+ proxyInterfaces.add(PINMgmtSignatureCard.class);
+ }
+ ClassLoader loader = signatureCard.getClass().getClassLoader();
+ return (SignatureCard) Proxy.newProxyInstance(loader, proxyInterfaces
+ .toArray(new Class[proxyInterfaces.size()]),
+ new ExclSignatureCardProxy(signatureCard));
+ }
+
+ public static PINMgmtSignatureCard newInstance(PINMgmtSignatureCard signatureCard) {
+ return null;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+
+ Card card = null;
+
+ Method target = signatureCard.getClass().getMethod(method.getName(),
+ method.getParameterTypes());
+
+ if (target.isAnnotationPresent(Exclusive.class)) {
+ card = (Card) ((method.equals(init))
+ ? args[0]
+ : signatureCard.getCard());
+ }
+
+ if (card != null) {
+ try {
+ log.trace("Invoking method " + method.getName() + "() with exclusive access.");
+ card.beginExclusive();
+ } catch (CardException e) {
+ log.info("Failed to get exclusive access to signature card "
+ + signatureCard.toString() + ".");
+ throw new SignatureCardException(e);
+ }
+ }
+
+ try {
+ return method.invoke(signatureCard, args);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ } finally {
+ if (card != null) {
+ card.endExclusive();
+ }
+ }
+
+
+ }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java b/smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java
new file mode 100644
index 00000000..b796b045
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java
@@ -0,0 +1,28 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Exclusive {
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java
new file mode 100644
index 00000000..3fc80fa1
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java
@@ -0,0 +1,129 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc;
+
+import java.nio.ByteBuffer;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class LogCardChannel extends CardChannel {
+
+ protected static Log log = LogFactory.getLog(LogCardChannel.class);
+
+ private CardChannel channel;
+
+ public LogCardChannel(CardChannel channel) {
+ if (channel == null) {
+ throw new NullPointerException();
+ }
+ this.channel = channel;
+ }
+
+ @Override
+ public void close() throws CardException {
+ channel.close();
+ }
+
+ @Override
+ public Card getCard() {
+ return channel.getCard();
+ }
+
+ @Override
+ public int getChannelNumber() {
+ return channel.getChannelNumber();
+ }
+
+ @Override
+ public ResponseAPDU transmit(CommandAPDU command) throws CardException {
+ if (log.isTraceEnabled()) {
+ switch (command.getINS()) {
+ case 0x20: // VERIFY
+ case 0x21: // VERIFY
+ case 0x24: { // CHANGE REFERENCE DATA
+ // Don't log possibly sensitive command data
+ StringBuilder sb = new StringBuilder();
+ sb.append(command);
+ sb.append('\n');
+ byte[] c = new byte[4];
+ c[0] = (byte) command.getCLA();
+ c[1] = (byte) command.getINS();
+ c[2] = (byte) command.getP1();
+ c[3] = (byte) command.getP2();
+ sb.append(toString(c));
+ if (command.getNc() > 0) {
+ sb.append(':');
+ sb.append(toString(new byte[] {(byte) command.getNc()}));
+ for (int i = 0; i < command.getNc(); i++) {
+ sb.append(":XX");
+ }
+ }
+ if (command.getNe() > 0) {
+ sb.append(':');
+ sb.append(toString(new byte[] {(byte) command.getNe()}));
+ }
+ log.trace(sb.toString());
+ }; break;
+
+ default:
+ log.trace(command + "\n" + toString(command.getBytes()));
+ }
+ long t0 = System.currentTimeMillis();
+ ResponseAPDU response = channel.transmit(command);
+ long t1 = System.currentTimeMillis();
+ log.trace(response + " [" + (t1 - t0) + "ms]\n" + toString(response.getBytes()));
+ return response;
+ } else {
+ return channel.transmit(command);
+ }
+ }
+
+ @Override
+ public int transmit(ByteBuffer command, ByteBuffer response) throws CardException {
+ if (log.isTraceEnabled()) {
+ long t0 = System.currentTimeMillis();
+ int l = channel.transmit(command, response);
+ long t1 = System.currentTimeMillis();
+ log.trace("[" + (t1 - t0) + "ms]");
+ return l;
+ } else {
+ return channel.transmit(command, response);
+ }
+ }
+
+ private String toString(byte[] b) {
+ StringBuffer sb = new StringBuffer();
+ if (b != null && b.length > 0) {
+ sb.append(Integer.toHexString((b[0] & 240) >> 4));
+ sb.append(Integer.toHexString(b[0] & 15));
+ }
+ for (int i = 1; i < b.length; i++) {
+ sb.append(':');
+ sb.append(Integer.toHexString((b[i] & 240) >> 4));
+ sb.append(Integer.toHexString(b[i] & 15));
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java
new file mode 100644
index 00000000..2eadaf26
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java
@@ -0,0 +1,60 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc;
+
+public class NewReferenceDataAPDUSpec extends VerifyAPDUSpec {
+
+ /**
+ * The offset for the insertion of the new PIN. (Default:
+ * {@link VerifyAPDUSpec#pinLength} + 1})
+ */
+ protected int pinInsertionOffsetNew = 0;
+
+ public NewReferenceDataAPDUSpec(byte[] apdu, int pinPosition, int pinFormat, int pinLength) {
+ super(apdu, pinPosition, pinFormat, pinLength);
+ }
+
+ /**
+ * @param apdu
+ * @param pinPosition
+ * @param pinFormat
+ * @param pinLength
+ * @param pinLengthSize
+ * @param pinLengthPos
+ */
+ public NewReferenceDataAPDUSpec(byte[] apdu, int pinPosition,
+ int pinFormat, int pinLength, int pinLengthSize, int pinLengthPos) {
+ super(apdu, pinPosition, pinFormat, pinLength, pinLengthSize, pinLengthPos);
+ }
+
+ /**
+ * @return the pinInsertionOffsetNew
+ */
+ public int getPinInsertionOffsetNew() {
+ return pinInsertionOffsetNew;
+ }
+
+ /**
+ * @param pinInsertionOffsetNew the pinInsertionOffsetNew to set
+ */
+ public void setPinInsertionOffsetNew(int pinInsertionOffsetNew) {
+ this.pinInsertionOffsetNew = pinInsertionOffsetNew;
+ }
+
+
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java
index 115e6d5f..eaf38435 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java
@@ -24,6 +24,8 @@ package at.gv.egiz.smcc;
*/
public class PINConfirmationException extends SignatureCardException {
+ private static final long serialVersionUID = 1L;
+
public PINConfirmationException() {
super();
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java
index 28a13fdb..774fcdf5 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java
@@ -24,6 +24,8 @@ package at.gv.egiz.smcc;
*/
public class PINFormatException extends SignatureCardException {
+ private static final long serialVersionUID = 1L;
+
public PINFormatException() {
super();
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java
new file mode 100644
index 00000000..53738612
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java
@@ -0,0 +1,41 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc;
+
+import java.util.List;
+
+public interface PINMgmtSignatureCard extends SignatureCard {
+
+ public enum PIN_STATE {UNKNOWN, ACTIV, NOT_ACTIV, BLOCKED};
+
+ public List<PINSpec> getPINSpecs();
+
+ public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException;
+
+ public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException;
+
+ public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException;
+
+ public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws CancelledException, SignatureCardException, InterruptedException;
+
+ public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
+ throws CancelledException, SignatureCardException, InterruptedException;
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java
index 7337f59e..51e4904e 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java
@@ -24,6 +24,8 @@ package at.gv.egiz.smcc;
*/
public class PINOperationAbortedException extends SignatureCardException {
+ private static final long serialVersionUID = 1L;
+
public PINOperationAbortedException() {
super();
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
index 8fa80dcb..5c294b5b 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
@@ -1,31 +1,19 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
package at.gv.egiz.smcc;
/**
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java
index d180ddf0..b8ffafab 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package at.gv.egiz.smcc;
+import java.util.Locale;
import java.util.ResourceBundle;
/**
@@ -31,7 +31,7 @@ public class PINSpec {
String rexepPattern_;
- ResourceBundle resourceBundle_;
+ String resourceBundleName_;
String name_;
@@ -49,17 +49,17 @@ public class PINSpec {
* @param kid the keyId for this pin
*/
public PINSpec(int minLenght, int maxLength, String rexepPattern,
- ResourceBundle resourceBundle, String name, byte kid, byte[] contextAID) {
+ String resourceBundleName, String name, byte kid, byte[] contextAID) {
minLength_ = minLenght;
maxLength_ = maxLength;
rexepPattern_ = rexepPattern;
- resourceBundle_ = resourceBundle;
+ resourceBundleName_ = resourceBundleName;
name_ = name;
kid_ = kid;
context_aid_ = contextAID;
}
-
+
public PINSpec(int minLenght, int maxLength, String rexepPattern,
String name, byte kid, byte[] contextAID) {
@@ -71,14 +71,26 @@ public class PINSpec {
context_aid_ = contextAID;
}
-
-
public String getLocalizedName() {
+
+ if (resourceBundleName_ != null) {
+ ResourceBundle resourceBundle = ResourceBundle.getBundle(resourceBundleName_);
+ return resourceBundle.getString(name_);
+ } else {
+ return name_;
+ }
- return (resourceBundle_ != null)
- ? resourceBundle_.getString(name_)
- : name_;
-
+ }
+
+ public String getLocalizedName(Locale locale) {
+
+ if (resourceBundleName_ != null) {
+ ResourceBundle resourceBundle = ResourceBundle.getBundle(resourceBundleName_, locale);
+ return resourceBundle.getString(name_);
+ } else {
+ return name_;
+ }
+
}
public int getMaxLength() {
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
index e622f65a..83c0197a 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
@@ -1,36 +1,27 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
package at.gv.egiz.smcc;
-import at.gv.egiz.smcc.ccid.CCID;
-import at.gv.egiz.smcc.util.SMCCHelper;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.util.Arrays;
+import java.util.List;
+
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
@@ -39,7 +30,10 @@ import javax.smartcardio.ResponseAPDU;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-public class STARCOSCard extends AbstractSignatureCard {
+import at.gv.egiz.smcc.util.ISO7816Utils;
+import at.gv.egiz.smcc.util.SMCCHelper;
+
+public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatureCard {
/**
* Logging facility.
@@ -154,133 +148,131 @@ public class STARCOSCard extends AbstractSignatureCard {
public static final byte KID_PIN_CARD = (byte) 0x01;
- public static final int PINSPEC_CARD = 0;
- public static final int PINSPEC_SS = 1;
+ private static final PINSpec CARD_PIN_SPEC =
+ new PINSpec(4, 12, "[0-9]",
+ "at/gv/egiz/smcc/STARCOSCard", "card.pin.name", KID_PIN_CARD, null);
+
+ private static final PINSpec SS_PIN_SPEC =
+ new PINSpec(6, 12, "[0-9]",
+ "at/gv/egiz/smcc/STARCOSCard", "sig.pin.name", KID_PIN_SS, AID_DF_SS);
/**
* Creates an new instance.
*/
public STARCOSCard() {
super("at/gv/egiz/smcc/STARCOSCard");
- pinSpecs.add(PINSPEC_CARD,
- new PINSpec(4, 12, "[0-9]",
- getResourceBundle().getString("card.pin.name"),
- KID_PIN_CARD, null));
- pinSpecs.add(PINSPEC_SS,
- new PINSpec(6, 12, "[0-9]",
- getResourceBundle().getString("sig.pin.name"),
- KID_PIN_SS, AID_DF_SS));
+ pinSpecs.add(CARD_PIN_SPEC);
+ pinSpecs.add(SS_PIN_SPEC);
}
@Override
+ @Exclusive
public byte[] getCertificate(KeyboxName keyboxName)
throws SignatureCardException, InterruptedException {
- try {
-
- if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
-
- try {
- getCard().beginExclusive();
- return readTLVFile(AID_DF_SS, EF_C_X509_CH_DS, 2000);
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
- } finally {
- getCard().endExclusive();
- }
-
- } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
-
- try {
- getCard().beginExclusive();
- return readTLVFile(AID_DF_GS, EF_C_X509_CH_AUT, 2000);
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
- } finally {
- getCard().endExclusive();
- }
+ byte[] aid;
+ byte[] fid;
+ if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
+ aid = AID_DF_SS;
+ fid = EF_C_X509_CH_DS;
+ } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
+ aid = AID_DF_GS;
+ fid = EF_C_X509_CH_AUT;
+ } else {
+ throw new IllegalArgumentException("Keybox " + keyboxName
+ + " not supported.");
+ }
- } else {
- throw new IllegalArgumentException("Keybox " + keyboxName
- + " not supported.");
+ try {
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, aid);
+ // SELECT file
+ execSELECT_FID(channel, fid);
+ // READ BINARY
+ byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30);
+ if (certificate == null) {
+ throw new NotActivatedException();
}
-
+ return certificate;
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
} catch (CardException e) {
- log.warn(e);
- throw new SignatureCardException("Failed to access card.", e);
+ log.info("Failed to get certificate.", e);
+ throw new SignatureCardException(e);
}
}
@Override
+ @Exclusive
public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
throws SignatureCardException, InterruptedException {
try {
if ("IdentityLink".equals(infobox)) {
- PINSpec spec = pinSpecs.get(PINSPEC_CARD);
- //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
-
- int retries = -1;
- boolean pinRequired = false;
+ PINSpec spec = CARD_PIN_SPEC;
+
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, AID_INFOBOX);
+ // SELECT file
+ execSELECT_FID(channel, EF_INFOBOX);
- do {
+ while (true) {
try {
- getCard().beginExclusive();
- if (pinRequired) {
- char[] pin = provider.providePIN(spec, retries);
- return readTLVFile(AID_INFOBOX, EF_INFOBOX, pin, spec.getKID(), 2000);
- } else {
- return readTLVFile(AID_INFOBOX, EF_INFOBOX, 2000);
- }
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
+ return ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30);
} catch (SecurityStatusNotSatisfiedException e) {
- pinRequired = true;
- retries = verifyPIN(KID_PIN_CARD);
- } catch (VerificationFailedException e) {
- pinRequired = true;
- retries = e.getRetries();
- } finally {
- getCard().endExclusive();
+ verifyPINLoop(channel, spec, provider);
}
- } while (retries != 0);
-
- throw new LockedException();
-
- } else if ("EHIC".equals(infobox)) {
- try {
- getCard().beginExclusive();
- return readTLVFile(AID_SV_PERSONENDATEN, FID_EHIC, 126);
- } finally {
- getCard().endExclusive();
- }
- } else if ("Grunddaten".equals(infobox)) {
- try {
- getCard().beginExclusive();
- return readTLVFile(AID_SV_PERSONENDATEN, FID_GRUNDDATEN, 550);
- } finally {
- getCard().endExclusive();
- }
- } else if ("SV-Personenbindung".equals(infobox)) {
- try {
- getCard().beginExclusive();
- return readTLVFile(AID_SV_PERSONENDATEN, FID_SV_PERSONENBINDUNG, 500);
- } finally {
- getCard().endExclusive();
}
+
} else if ("Status".equals(infobox)) {
+
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, AID_SV_PERSONENDATEN);
+ // SELECT file
+ execSELECT_FID(channel, FID_STATUS);
+ // READ RECORDS
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try {
- getCard().beginExclusive();
- return readRecords(AID_SV_PERSONENDATEN, FID_STATUS, 1, 5);
- } finally {
- getCard().endExclusive();
+ for (int record = 1; record <= 5; record++) {
+ byte[] rb = ISO7816Utils.readRecord(channel, record);
+ bytes.write(rb);
+ }
+ } catch (IOException e) {
+ throw new SignatureCardException("Failed to read infobox '" + infobox
+ + "'.", e);
}
+ return bytes.toByteArray();
+
} else {
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
+
+ byte[] fid;
+
+ if ("EHIC".equals(infobox)) {
+ fid = FID_EHIC;
+ } else if ("Grunddaten".equals(infobox)) {
+ fid = FID_GRUNDDATEN;
+ } else if ("SV-Personenbindung".equals(infobox)) {
+ fid = FID_SV_PERSONENBINDUNG;
+ } else {
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
+ }
+
+ CardChannel channel = getCardChannel();
+ // SELECT application
+ execSELECT_AID(channel, AID_SV_PERSONENDATEN);
+ // SELECT file
+ execSELECT_FID(channel, fid);
+ // READ BINARY
+ return ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30);
+
}
+
} catch (CardException e) {
log.warn(e);
throw new SignatureCardException("Failed to access card.", e);
@@ -288,6 +280,7 @@ public class STARCOSCard extends AbstractSignatureCard {
}
@Override
+ @Exclusive
public byte[] createSignature(byte[] hash, KeyboxName keyboxName,
PINProvider provider) throws SignatureCardException, InterruptedException {
@@ -297,68 +290,44 @@ public class STARCOSCard extends AbstractSignatureCard {
try {
+ CardChannel channel = getCardChannel();
+
if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
- PINSpec spec = pinSpecs.get(PINSPEC_SS);
- //new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));
+ PINSpec spec = SS_PIN_SPEC;
+
+ // SELECT MF
+ execSELECT_MF(channel);
+ // SELECT application
+ execSELECT_AID(channel, AID_DF_SS);
+ // VERIFY
+ verifyPINLoop(channel, spec, provider);
+ // MANAGE SECURITY ENVIRONMENT : SET DST
+ execMSE(channel, 0x41, 0xb6, DST_SS);
+ // PERFORM SECURITY OPERATION : HASH
+ execPSO_HASH(channel, hash);
+ // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE
+ return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel);
- int retries = -1;
- char[] pin = null;
-
- do {
- try {
- getCard().beginExclusive();
- selectFileAID(AID_DF_SS);
- retries = verifyPIN(KID_PIN_SS); //, null);
- } finally {
- getCard().endExclusive();
- }
- pin = provider.providePIN(spec, retries);
- try {
- getCard().beginExclusive();
- return createSignature(hash, AID_DF_SS, pin, KID_PIN_SS, DST_SS);
- } catch (VerificationFailedException e) {
- retries = e.getRetries();
- } catch (PINFormatException e) {
- log.debug("wrong pin size entered, retry");
- } finally {
- getCard().endExclusive();
- }
- } while (retries != 0);
-
- throw new LockedException();
-
-
} else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
- PINSpec spec = pinSpecs.get(PINSPEC_CARD);
- //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
-
- int retries = -1;
- char[] pin = null;
- boolean pinRequiered = false;
-
- do {
- if (pinRequiered) {
- pin = provider.providePIN(spec, retries);
- }
+ PINSpec spec = CARD_PIN_SPEC;
+
+ // SELECT application
+ execSELECT_AID(channel, AID_DF_GS);
+ // MANAGE SECURITY ENVIRONMENT : SET DST
+ execMSE(channel, 0x41, 0xb6, DST_GS);
+ // PERFORM SECURITY OPERATION : HASH
+ execPSO_HASH(channel, hash);
+
+ while (true) {
try {
- getCard().beginExclusive();
- return createSignature(hash, AID_DF_GS, pin, KID_PIN_CARD, DST_GS);
- } catch (FileNotFoundException e) {
- throw new NotActivatedException();
+ // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE
+ return execPSO_COMPUTE_DIGITAL_SIGNATURE(channel);
} catch (SecurityStatusNotSatisfiedException e) {
- pinRequiered = true;
- retries = verifyPIN(KID_PIN_CARD);
- } catch (VerificationFailedException e) {
- pinRequiered = true;
- retries = e.getRetries();
- } finally {
- getCard().endExclusive();
+ verifyPINLoop(channel, spec, provider);
}
- } while (retries != 0);
-
- throw new LockedException();
+ }
} else {
throw new IllegalArgumentException("KeyboxName '" + keyboxName
@@ -372,529 +341,366 @@ public class STARCOSCard extends AbstractSignatureCard {
}
-
- ////////////////////////////////////////////////////////////////////////
- // PROTECTED METHODS (assume exclusive card access)
- ////////////////////////////////////////////////////////////////////////
-
- protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
- CardChannel channel = getCardChannel();
- return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02,
- 0x04, fid, 256));
- }
-
- private byte[] createSignature(byte[] hash, byte[] aid, char[] pin, byte kid,
- byte[] dst) throws CardException, SignatureCardException {
-
- // SELECT MF
- selectMF();
- // SELECT DF
- selectFileAID(aid);
- // VERIFY
- int retries = verifyPIN(kid, pin);
- if (retries != -1) {
- throw new VerificationFailedException(retries);
- }
- // MSE: SET DST
- mseSetDST(dst);
- // PSO: HASH
- psoHash(hash);
- // PSO: COMPUTE DIGITAL SIGNATURE
- return psoComputDigitalSiganture();
-
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider)
+ */
+ @Override
+ @Exclusive
+ public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException,
+ TimeoutException, SignatureCardException, InterruptedException {
- }
-
- private void selectMF() throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,
- 0x0C));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("Failed to select MF: SW="
- + Integer.toHexString(resp.getSW()) + ".");
+
+ try {
+ if (pinSpec.getContextAID() != null) {
+ // SELECT application
+ execSELECT_AID(channel, pinSpec.getContextAID());
+ }
+ int retries = verifyPIN(channel, pinSpec, null, 0);
+ verifyPIN(channel, pinSpec, pinProvider, retries);
+ } catch (CardException e) {
+ log.info("Failed to verify PIN.", e);
+ throw new SignatureCardException("Failed to verify PIN.", e);
}
+
}
-
- private void mseSetDST(byte[] dst) throws CardException, SignatureCardException {
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.ChangePINProvider)
+ */
+ @Override
+ @Exclusive
+ public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+ throws LockedException, NotActivatedException, CancelledException,
+ TimeoutException, SignatureCardException, InterruptedException {
+
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, 0x41,
- 0xB6, dst));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("MSE:SET DST failed: SW="
- + Integer.toHexString(resp.getSW()));
+
+ try {
+ if (pinSpec.getContextAID() != null) {
+ // SELECT application
+ execSELECT_AID(channel, pinSpec.getContextAID());
+ }
+ int retries = verifyPIN(channel, pinSpec, null, 0);
+ changePIN(channel, pinSpec, pinProvider, retries);
+ } catch (CardException e) {
+ log.info("Failed to change PIN.", e);
+ throw new SignatureCardException("Failed to change PIN.", e);
}
+
}
- private void psoHash(byte[] hash) throws CardException, SignatureCardException {
- byte[] data = new byte[hash.length + 2];
- data[0] = (byte) 0x90; // tag
- data[1] = (byte) (hash.length); // length
- System.arraycopy(hash, 0, data, 2, hash.length);
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.AbstractSignatureCard#activatePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider)
+ */
+ @Override
+ @Exclusive
+ public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+ throws CancelledException, SignatureCardException, CancelledException,
+ TimeoutException, InterruptedException {
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x90,
- 0xA0, data));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("PSO:HASH failed: SW="
- + Integer.toHexString(resp.getSW()));
- }
- }
- private byte[] psoComputDigitalSiganture() throws CardException,
- SignatureCardException {
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x9E,
- 0x9A, 256));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException(
- "PSO: COMPUTE DIGITAL SIGNATRE failed: SW="
- + Integer.toHexString(resp.getSW()));
- } else {
- return resp.getData();
+ try {
+ if (pinSpec.getContextAID() != null) {
+ // SELECT application
+ execSELECT_AID(channel, pinSpec.getContextAID());
+ }
+ activatePIN(channel, pinSpec, pinProvider);
+ } catch (CardException e) {
+ log.info("Failed to activate PIN.", e);
+ throw new SignatureCardException("Failed to activate PIN.", e);
}
+
}
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.PINMgmtSignatureCard#unblockPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider)
+ */
@Override
- protected int verifyPIN(byte kid, char[] pin)
- throws LockedException, NotActivatedException, TimeoutException, CancelledException, PINFormatException, PINOperationAbortedException, SignatureCardException {
- try {
- byte[] sw;
- if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) {
- log.debug("verify pin on cardreader");
- sw = reader.verifyPinDirect(getPINVerifyStructure(kid));
-// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
- } else if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_START)) {
- log.debug("verify pin on cardreader");
- sw = reader.verifyPin(getPINVerifyStructure(kid));
- } else {
- byte[] pinBlock = encodePINBlock(pin);
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false);
- sw = new byte[2];
- sw[0] = (byte) resp.getSW1();
- sw[1] = (byte) resp.getSW2();
- }
-
- if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
- return -1;
- } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
- throw new LockedException("[63:c0]");
- } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
- return sw[1] & 0x0f;
- } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
- //Authentisierungsmethode gesperrt
- throw new LockedException("[69:83]");
- } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
- //referenzierte Daten sind reversibel gesperrt (invalidated)
- throw new NotActivatedException("[69:84]");
- } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
- //Benutzungsbedingungen nicht erfüllt
- throw new NotActivatedException("[69:85]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
- throw new TimeoutException("[64:00]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
- throw new CancelledException("[64:01]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) {
- throw new PINFormatException("[64:03]");
- }
- log.error("Failed to verify pin: SW="
- + SMCCHelper.toString(sw));
- throw new SignatureCardException(SMCCHelper.toString(sw));
-
- } catch (CardException ex) {
- log.error("smart card communication failed: " + ex.getMessage());
- throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
- }
+ public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
+ throws CancelledException, SignatureCardException, InterruptedException {
+ throw new SignatureCardException("Unblock PIN is not supported.");
}
@Override
- protected int verifyPIN(byte kid)
- throws LockedException, NotActivatedException, SignatureCardException {
+ public void reset() throws SignatureCardException {
try {
+ super.reset();
+ log.debug("select MF (e-card workaround)");
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0x20, 0x00, kid), false);
-
- if (resp.getSW() == 0x9000) {
- return -1;
- } else if (resp.getSW() == 0x63c0) {
- throw new LockedException("[63:c0]");
- } else if (resp.getSW1() == 0x63 && (resp.getSW2() & 0xf0) >> 4 == 0xc) {
- return resp.getSW2() & 0x0f;
- } else if (resp.getSW() == 0x6983) {
- //Authentisierungsmethode gesperrt
- throw new LockedException("[69:83]");
- } else if (resp.getSW() == 0x6984) {
- //referenzierte Daten sind reversibel gesperrt (invalidated)
- throw new NotActivatedException("[69:84]");
- } else if (resp.getSW() == 0x6985) {
- //Benutzungsbedingungen nicht erfüllt
- throw new NotActivatedException("[69:85]");
+ ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x00, 0x0C));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("Failed to select MF after RESET: SW=" + Integer.toHexString(resp.getSW()) + ".");
}
- log.error("Failed to verify pin: SW="
- + Integer.toHexString(resp.getSW()));
- throw new SignatureCardException("[" + Integer.toHexString(resp.getSW()) + "]");
-
} catch (CardException ex) {
- log.error("smart card communication failed: " + ex.getMessage());
- throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
+ log.error("Failed to select MF after RESET: " + ex.getMessage(), ex);
+ throw new SignatureCardException("Failed to select MF after RESET");
}
}
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPINSpecs()
+ */
@Override
- protected int changePIN(byte kid, char[] oldPin, char[] newPin)
- throws LockedException, CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException {
- try {
- byte[] sw;
- if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) {
- log.debug("modify pin on cardreader");
- sw = reader.modifyPinDirect(getPINModifyStructure(kid));
- } else if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_START)) {
- log.debug("modify pin on cardreader");
- sw = reader.modifyPin(getPINModifyStructure(kid));
- } else {
- byte[] cmd = new byte[16];
- System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8);
- System.arraycopy(encodePINBlock(newPin), 0, cmd, 8, 8);
-
- CardChannel channel = getCardChannel();
-
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0x24, 0x00, kid, cmd), false);
-
- sw = new byte[2];
- sw[0] = (byte) resp.getSW1();
- sw[1] = (byte) resp.getSW2();
- }
-
- // activates pin (newPIN) if not active
- if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
- return -1;
- } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) {
- throw new LockedException("[63:c0]");
- } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) {
- return sw[1] & 0x0f;
- } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
- //Authentisierungsmethode gesperrt
- throw new LockedException("[69:83]");
-// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
-// //referenzierte Daten sind reversibel gesperrt (invalidated)
-// throw new NotActivatedException("[69:84]");
-// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
-// //Benutzungsbedingungen nicht erfüllt
-// throw new NotActivatedException("[69:85]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
- throw new TimeoutException("[64:00]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
- throw new CancelledException("[64:01]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x02) {
- throw new PINConfirmationException("[64:02]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) {
- throw new PINFormatException("[64:03]");
- } else if (sw[0] == (byte) 0x6a && sw[1] == (byte) 0x80) {
- log.info("invalid parameter, assume wrong pin size");
- throw new PINFormatException("[6a:80]");
- }
- log.error("Failed to change pin: SW="
- + SMCCHelper.toString(sw));
- throw new SignatureCardException(SMCCHelper.toString(sw));
- } catch (CardException ex) {
- log.error("smart card communication failed: " + ex.getMessage());
- throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
- }
+ public List<PINSpec> getPINSpecs() {
+ return Arrays.asList(new PINSpec[] {CARD_PIN_SPEC, SS_PIN_SPEC});
}
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.PINMgmtSignatureCard#getPINStatus(at.gv.egiz.smcc.PINSpec)
+ */
@Override
- protected void activatePIN(byte kid, char[] pin)
- throws CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException {
+ public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException {
+
+ CardChannel channel = getCardChannel();
+
try {
- byte[] sw;
- if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) {
- log.debug("activate pin on cardreader");
- sw = reader.modifyPinDirect(getActivatePINModifyStructure(kid));
- } else if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_START)) {
- log.debug("activate pin on cardreader");
- sw = reader.modifyPin(getActivatePINModifyStructure(kid));
- } else {
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0x24, 0x01, kid, encodePINBlock(pin)), false);
-
- sw = new byte[2];
- sw[0] = (byte) resp.getSW1();
- sw[1] = (byte) resp.getSW2();
- log.trace("activate pin returned SW=" + Integer.toHexString(resp.getSW()));
- }
-
- if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
- return;
- } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
- //Authentisierungsmethode gesperrt
- throw new LockedException("[69:83]");
-// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
-// //referenzierte Daten sind reversibel gesperrt (invalidated)
-// throw new NotActivatedException("[69:84]");
-// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
-// //Benutzungsbedingungen nicht erfüllt
-// throw new NotActivatedException("[69:85]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
- throw new TimeoutException("[64:00]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
- throw new CancelledException("[64:01]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x02) {
- throw new PINConfirmationException("[64:02]");
- } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) {
- throw new PINFormatException("[64:03]");
+ if (pinSpec.getContextAID() != null) {
+ // SELECT AID
+ execSELECT_AID(channel, pinSpec.getContextAID());
}
- log.error("Failed to activate pin: SW="
- + SMCCHelper.toString(sw));
- throw new SignatureCardException(SMCCHelper.toString(sw));
-
- } catch (CardException ex) {
- log.error("smart card communication failed: " + ex.getMessage());
- throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);
+ verifyPIN(channel, pinSpec, null, 0);
+ return PIN_STATE.ACTIV;
+ } catch (InterruptedException e) {
+ return PIN_STATE.UNKNOWN;
+ } catch (LockedException e) {
+ return PIN_STATE.BLOCKED;
+ } catch (NotActivatedException e) {
+ return PIN_STATE.NOT_ACTIV;
+ } catch (CardException e) {
+ log.error("Failed to get PIN status.", e);
+ throw new SignatureCardException("Failed to get PIN status.", e);
}
+
}
- /**
- * BCD encodes the pin, pads with 0xFF and prepends the pins length
- * @param pin
- * @return a 8 byte pin block consisting of length byte (0x2X),
- * the BCD encoded pin and a 0xFF padding
- */
- @Override
- protected byte[] encodePINBlock(char[] pin) throws SignatureCardException {
- if (pin == null || pin.length > 12) {
- throw new SignatureCardException("invalid pin: " + pin);
+ public String toString() {
+ return "e-card";
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // PROTECTED METHODS (assume exclusive card access)
+ ////////////////////////////////////////////////////////////////////////
+
+ protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINProvider provider)
+ throws LockedException, NotActivatedException, SignatureCardException,
+ InterruptedException, CardException {
+
+ int retries = verifyPIN(channel, spec, null, -1);
+ do {
+ retries = verifyPIN(channel, spec, provider, retries);
+ } while (retries > 0);
+
+ }
+
+ protected int verifyPIN(CardChannel channel, PINSpec pinSpec,
+ PINProvider provider, int retries) throws SignatureCardException,
+ LockedException, NotActivatedException, InterruptedException,
+ CardException {
+
+ VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, pinSpec.getKID(), (byte) 0x08,
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff },
+ 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4);
+
+ ResponseAPDU resp;
+ if (provider != null) {
+ resp = reader.verify(channel, apduSpec, pinSpec, provider, retries);
+ } else {
+ resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00, pinSpec.getKID()));
+ }
+
+ if (resp.getSW() == 0x9000) {
+ return -1;
+ }
+ if (resp.getSW() >> 4 == 0x63c) {
+ return 0x0f & resp.getSW();
+ }
+
+ switch (resp.getSW()) {
+ case 0x6983:
+ // authentication method blocked
+ throw new LockedException();
+ case 0x6984:
+ // reference data not usable
+ throw new NotActivatedException();
+ case 0x6985:
+ // conditions of use not satisfied
+ throw new NotActivatedException();
+
+ default:
+ String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW());
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
+
+ }
+
+ protected int changePIN(CardChannel channel, PINSpec pinSpec,
+ ChangePINProvider pinProvider, int retries) throws CancelledException,
+ InterruptedException, CardException, SignatureCardException {
+
+ ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.getKID(), (byte) 0x10,
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff },
+ 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4, 8);
+
+ ResponseAPDU resp = reader.modify(channel, apduSpec, pinSpec, pinProvider, retries);
+
+ if (resp.getSW() == 0x9000) {
+ return -1;
}
- int numDigits = pin.length;
- int numBytes = (int) Math.ceil(numDigits/2.0);
+ if (resp.getSW() >> 4 == 0x63c) {
+ return 0x0f & resp.getSW();
+ }
+
+ switch (resp.getSW()) {
+ case 0x6983:
+ // authentication method blocked
+ throw new LockedException();
+
+ default:
+ String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW());
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
+
+
+ }
- byte[] pinBlock = new byte[8];
- pinBlock[0] = (byte) (0x20 | numDigits);
+ protected int activatePIN(CardChannel channel, PINSpec pinSpec,
+ PINProvider provider) throws SignatureCardException,
+ InterruptedException, CardException {
+
+ NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x01, pinSpec.getKID(), (byte) 0x08,
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff },
+ 1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4);
+
+ ResponseAPDU resp = reader.activate(channel, apduSpec, pinSpec, provider);
+
+ switch (resp.getSW()) {
+
+ case 0x9000:
+ return -1;
- for (int i = 0; i < numBytes; i++) {
- int p1 = 16*Character.digit(pin[i*2], 16);
- int p2 = (i*2+1 < numDigits) ? Character.digit(pin[i*2+1], 16) : 0xf;
- pinBlock[i+1] = (byte) (p1 + p2);
- }
- Arrays.fill(pinBlock, numBytes + 1, pinBlock.length, (byte) 0xff);
-// log.trace("BCD encoded PIN block: " + SMCCHelper.toString(pinBlock));
+ case 0x6983:
+ // authentication method blocked
+ throw new LockedException();
- return pinBlock;
+ default:
+ String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW());
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ }
+
}
- private byte[] getPINVerifyStructure(byte kid) {
- byte bTimeOut = reader.getbTimeOut();
- byte bTimeOut2 = reader.getbTimeOut2(); // time out after first entry
- byte bmFormatString = (byte) 0x89; // 1 0001 0 01
- // ^------------ System unit = byte
- // ^^^^------- PIN position in the frame = 1 byte
- // ^----- PIN justification left
- // ^^-- BCD format
- byte bmPINBlockString = (byte) 0x47; // 0100 0111
- // ^^^^--------- PIN length size: 4 bits
- // ^^^^---- Length PIN = 7 bytes
- byte bmPINLengthFormat = (byte) 0x04; // 000 0 0100
- // ^-------- System bit units is bit
- // ^^^^--- PIN length is at the 4th position bit
- //TODO compare ints, not bytes
- byte wPINMaxExtraDigitL = // Max=12 digits
- (reader.getwPINMaxExtraDigitL() < (byte) 0x0c) ?
- reader.getwPINMaxExtraDigitL() : (byte) 0x0c;
- byte wPINMaxExtraDigitH = // Min=4/6 digits TODO card/ss pin (min: 4/6)
- (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
- reader.getwPINMaxExtraDigitH() : (byte) 0x04;
- byte bEntryValidationCondition =
- reader.getbEntryValidationCondition();
- byte bNumberMessage = (byte) 0x00; // No message
- byte wLangIdL = (byte) 0x0C; // - English?
- byte wLangIdH = (byte) 0x04; // \
- byte bMsgIndex = (byte) 0x00; // Default Msg
-
- byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08, // CLA INS P1 P2 LC
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff // ...
- };
-
- int offset = 0;
- byte[] pinVerifyStructure = new byte[offset + 19 + apdu.length];
- pinVerifyStructure[offset++] = bTimeOut;
- pinVerifyStructure[offset++] = bTimeOut2;
- pinVerifyStructure[offset++] = bmFormatString;
- pinVerifyStructure[offset++] = bmPINBlockString;
- pinVerifyStructure[offset++] = bmPINLengthFormat;
- pinVerifyStructure[offset++] = wPINMaxExtraDigitL;
- pinVerifyStructure[offset++] = wPINMaxExtraDigitH;
- pinVerifyStructure[offset++] = bEntryValidationCondition;
- pinVerifyStructure[offset++] = bNumberMessage;
- pinVerifyStructure[offset++] = wLangIdL;
- pinVerifyStructure[offset++] = wLangIdH;
- pinVerifyStructure[offset++] = bMsgIndex;
-
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
-
- pinVerifyStructure[offset++] = (byte) apdu.length;
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
- pinVerifyStructure[offset++] = 0x00;
- System.arraycopy(apdu, 0, pinVerifyStructure, offset, apdu.length);
-
- return pinVerifyStructure;
+ protected void execSELECT_MF(CardChannel channel) throws CardException, SignatureCardException {
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0xA4, 0x00, 0x0C));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("Failed to select MF: SW="
+ + Integer.toHexString(resp.getSW()) + ".");
+ }
}
- private byte[] getPINModifyStructure(byte kid) {
-
- byte bTimeOut = reader.getbTimeOut(); // s.o.
- byte bTimeOut2 = reader.getbTimeOut2(); // s.o.
- byte bmFormatString = (byte) 0x89; // s.o.
- byte bmPINBlockString = (byte) 0x47; // s.o.
- byte bmPINLengthFormat = (byte) 0x04; // s.o.
- byte bInsertionOffsetOld = (byte) 0x00; // insertion position offset in bytes
- byte bInsertionOffsetNew = (byte) 0x08; // (add 1 from bmFormatString b3)
- byte wPINMaxExtraDigitL =
- (reader.getwPINMaxExtraDigitL() < (byte) 0x0c) ?
- reader.getwPINMaxExtraDigitL() : (byte) 0x0c;
- byte wPINMaxExtraDigitH = // Min=4/6 digits TODO card/ss pin (min: 4/6)
- (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
- reader.getwPINMaxExtraDigitH() : (byte) 0x04;
- byte bConfirmPIN = (byte) 0x03; // current pin entry + confirmation
- byte bEntryValidationCondition =
- reader.getbEntryValidationCondition();
- byte bNumberMessage = (byte) 0x03; // 3 messages
- byte wLangIdL = (byte) 0x0C;
- byte wLangIdH = (byte) 0x04;
- byte bMsgIndex1 = (byte) 0x00; // insertion
- byte bMsgIndex2 = (byte) 0x01; // modification
- byte bMsgIndex3 = (byte) 0x02; // confirmation
-
- byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10,
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
- };
-
- int offset = 0;
- byte[] pinModifyStructure = new byte[offset + 24 + apdu.length];
- pinModifyStructure[offset++] = bTimeOut;
- pinModifyStructure[offset++] = bTimeOut2;
- pinModifyStructure[offset++] = bmFormatString;
- pinModifyStructure[offset++] = bmPINBlockString;
- pinModifyStructure[offset++] = bmPINLengthFormat;
- pinModifyStructure[offset++] = bInsertionOffsetOld;
- pinModifyStructure[offset++] = bInsertionOffsetNew;
- pinModifyStructure[offset++] = wPINMaxExtraDigitL;
- pinModifyStructure[offset++] = wPINMaxExtraDigitH;
- pinModifyStructure[offset++] = bConfirmPIN;
- pinModifyStructure[offset++] = bEntryValidationCondition;
- pinModifyStructure[offset++] = bNumberMessage;
- pinModifyStructure[offset++] = wLangIdL;
- pinModifyStructure[offset++] = wLangIdH;
- pinModifyStructure[offset++] = bMsgIndex1;
- pinModifyStructure[offset++] = bMsgIndex2;
- pinModifyStructure[offset++] = bMsgIndex3;
-
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
-
- pinModifyStructure[offset++] = (byte) apdu.length;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- System.arraycopy(apdu, 0, pinModifyStructure, offset, apdu.length);
-
-// log.debug("PIN MODIFY " + SMCCHelper.toString(pinModifyStructure));
- return pinModifyStructure;
+ protected byte[] execSELECT_AID(CardChannel channel, byte[] aid)
+ throws SignatureCardException, CardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0xA4, 0x04, 0x00, aid, 256));
+
+ if (resp.getSW() == 0x6A82) {
+ String msg = "File or application not found AID="
+ + SMCCHelper.toString(aid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.info(msg);
+ throw new FileNotFoundException(msg);
+ } else if (resp.getSW() != 0x9000) {
+ String msg = "Failed to select application AID="
+ + SMCCHelper.toString(aid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.info(msg);
+ throw new SignatureCardException(msg);
+ } else {
+ return resp.getBytes();
+ }
+
}
- private byte[] getActivatePINModifyStructure(byte kid) {
-
- byte bTimeOut = reader.getbTimeOut();
- byte bTimeOut2 = reader.getbTimeOut2();
- byte bmFormatString = (byte) 0x89;
- byte bmPINBlockString = (byte) 0x47;
- byte bmPINLengthFormat = (byte) 0x04;
- byte bInsertionOffsetOld = (byte) 0x00; // ignored
- byte bInsertionOffsetNew = (byte) 0x00;
- byte wPINMaxExtraDigitL =
- (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?
- reader.getwPINMaxExtraDigitL() : (byte) 0x12;
- byte wPINMaxExtraDigitH = // Min=4/6 digits TODO card/ss pin (min: 4/6)
- (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
- reader.getwPINMaxExtraDigitH() : (byte) 0x04;
- byte bConfirmPIN = (byte) 0x01; // confirm, no current pin entry
- byte bEntryValidationCondition =
- reader.getbEntryValidationCondition();
- byte bNumberMessage = (byte) 0x02; // 2 messages
- byte wLangIdL = (byte) 0x0c;
- byte wLangIdH = (byte) 0x04;
- byte bMsgIndex1 = (byte) 0x01; // modification prompt
- byte bMsgIndex2 = (byte) 0x02; // confirmation prompt
- byte bMsgIndex3 = (byte) 0x00;
-
- byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x24, (byte) 0x01, kid, (byte) 0x08,
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
- };
-
- int offset = 0;
- byte[] pinModifyStructure = new byte[offset + 24 + apdu.length];
- pinModifyStructure[offset++] = bTimeOut;
- pinModifyStructure[offset++] = bTimeOut2;
- pinModifyStructure[offset++] = bmFormatString;
- pinModifyStructure[offset++] = bmPINBlockString;
- pinModifyStructure[offset++] = bmPINLengthFormat;
- pinModifyStructure[offset++] = bInsertionOffsetOld;
- pinModifyStructure[offset++] = bInsertionOffsetNew;
- pinModifyStructure[offset++] = wPINMaxExtraDigitL;
- pinModifyStructure[offset++] = wPINMaxExtraDigitH;
- pinModifyStructure[offset++] = bConfirmPIN;
- pinModifyStructure[offset++] = bEntryValidationCondition;
- pinModifyStructure[offset++] = bNumberMessage;
- pinModifyStructure[offset++] = wLangIdL;
- pinModifyStructure[offset++] = wLangIdH;
- pinModifyStructure[offset++] = bMsgIndex1;
- pinModifyStructure[offset++] = bMsgIndex2;
- pinModifyStructure[offset++] = bMsgIndex3;
-
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
-
- pinModifyStructure[offset++] = (byte) apdu.length;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- pinModifyStructure[offset++] = 0x00;
- System.arraycopy(apdu, 0, pinModifyStructure, offset, apdu.length);
-
-// log.debug("PIN MODIFY " + SMCCHelper.toString(pinModifyStructure));
- return pinModifyStructure;
+
+ protected byte[] execSELECT_FID(CardChannel channel, byte[] fid)
+ throws SignatureCardException, CardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0xA4, 0x02, 0x04, fid, 256));
+
+ if (resp.getSW() == 0x6A82) {
+ String msg = "File or application not found FID="
+ + SMCCHelper.toString(fid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.info(msg);
+ throw new FileNotFoundException(msg);
+ } else if (resp.getSW() != 0x9000) {
+ String msg = "Failed to select application FID="
+ + SMCCHelper.toString(fid) + " SW="
+ + Integer.toHexString(resp.getSW()) + ".";
+ log.error(msg);
+ throw new SignatureCardException(msg);
+ } else {
+ return resp.getBytes();
+ }
+
}
+
+ protected void execMSE(CardChannel channel, int p1, int p2, byte[] data)
+ throws CardException, SignatureCardException {
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x22, p1, p2, data));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("MSE:SET DST failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ }
+ }
+
+ protected void execPSO_HASH(CardChannel channel, byte[] hash) throws CardException, SignatureCardException {
+ byte[] data = new byte[hash.length + 2];
+ data[0] = (byte) 0x90; // tag
+ data[1] = (byte) (hash.length); // length
+ System.arraycopy(hash, 0, data, 2, hash.length);
- @Override
- public void reset() throws SignatureCardException {
- try {
- super.reset();
- log.debug("select MF (e-card workaround)");
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, 0x0C));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("Failed to select MF after RESET: SW=" + Integer.toHexString(resp.getSW()) + ".");
- }
- } catch (CardException ex) {
- log.error("Failed to select MF after RESET: " + ex.getMessage(), ex);
- throw new SignatureCardException("Failed to select MF after RESET");
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x2A, 0x90, 0xA0, data));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("PSO:HASH failed: SW="
+ + Integer.toHexString(resp.getSW()));
}
}
- public String toString() {
- return "e-card";
+ protected byte[] execPSO_COMPUTE_DIGITAL_SIGNATURE(CardChannel channel)
+ throws CardException, SignatureCardException {
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0x2A, 0x9E, 0x9A, 256));
+ if (resp.getSW() == 0x6982) {
+ throw new SecurityStatusNotSatisfiedException();
+ } else if (resp.getSW() == 0x6983) {
+ throw new LockedException();
+ } else if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException(
+ "PSO: COMPUTE DIGITAL SIGNATRE failed: SW="
+ + Integer.toHexString(resp.getSW()));
+ } else {
+ return resp.getData();
+ }
}
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
index da084e0d..279362c0 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
@@ -14,10 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package at.gv.egiz.smcc;
-import at.gv.egiz.smcc.ccid.CCID;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -37,20 +35,20 @@ import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
-import java.util.ArrayList;
import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
import java.util.Locale;
-import java.util.Map;
import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
+import javax.smartcardio.ResponseAPDU;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import at.gv.egiz.smcc.ccid.CCID;
+
/**
*
* @author mcentner
@@ -396,31 +394,6 @@ public class SWCard implements SignatureCard {
}
@Override
- public List<PINSpec> getPINSpecs() {
- return new ArrayList<PINSpec>();
- }
-
- @Override
- public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
- throws LockedException, NotActivatedException, SignatureCardException {
- }
-
- @Override
- public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) throws SignatureCardException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider) throws CancelledException, SignatureCardException, InterruptedException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
public CCID getReader() {
return new CCID() {
@@ -488,6 +461,32 @@ public class SWCard implements SignatureCard {
public void setDisablePinpad(boolean disable) {
throw new UnsupportedOperationException("Not supported yet.");
}
+
+ @Override
+ public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec,
+ PINSpec pinSpec, PINProvider provider, int retries)
+ throws CancelledException, InterruptedException, CardException,
+ SignatureCardException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public ResponseAPDU activate(CardChannel channel,
+ NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec,
+ PINProvider provider) throws CancelledException,
+ InterruptedException, CardException, SignatureCardException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ResponseAPDU modify(CardChannel channel,
+ ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec,
+ ChangePINProvider provider, int retries) throws CancelledException,
+ InterruptedException, CardException, SignatureCardException {
+ // TODO Auto-generated method stub
+ return null;
+ }
};
}
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
index c06074f2..1a163783 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
@@ -1,35 +1,23 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
package at.gv.egiz.smcc;
import at.gv.egiz.smcc.ccid.CCID;
-import java.util.List;
import java.util.Locale;
import javax.smartcardio.Card;
@@ -76,6 +64,11 @@ public interface SignatureCard {
return keyboxName_;
}
+ @Override
+ public String toString() {
+ return keyboxName_;
+ }
+
}
public void init(Card card, CardTerminal cardTerminal);
@@ -118,24 +111,6 @@ public interface SignatureCard {
public byte[] createSignature(byte[] hash, KeyboxName keyboxName,
PINProvider provider) throws SignatureCardException, InterruptedException;
- /**
- * Get the KIDs for all available PINs and the corresponding PINSpecs
- * @return array of KIDs
- */
- public List<PINSpec> getPINSpecs();
-
- public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
- throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException;
-
- public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
- throws LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException;
-
- public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
- throws CancelledException, SignatureCardException, InterruptedException;
-
- public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
- throws CancelledException, SignatureCardException, InterruptedException;
-
public CCID getReader();
/**
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java
index f296f3a2..48b4646a 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java
@@ -1,31 +1,20 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
package at.gv.egiz.smcc;
public class SignatureCardException extends Exception {
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java
index 5146c275..f46f8657 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java
@@ -1,31 +1,20 @@
-//Copyright (C) 2002 IAIK
-//http://jce.iaik.at
-//
-//Copyright (C) 2003 Stiftung Secure Information and
-// Communication Technologies SIC
-//http://www.sic.st
-//
-//All rights reserved.
-//
-//This source is provided for inspection purposes and recompilation only,
-//unless specified differently in a contract with IAIK. This source has to
-//be kept in strict confidence and must not be disclosed to any third party
-//under any circumstances. Redistribution in source and binary forms, with
-//or without modification, are <not> permitted in any case!
-//
-//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-//SUCH DAMAGE.
-//
-//
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
package at.gv.egiz.smcc;
import java.util.ArrayList;
@@ -233,7 +222,11 @@ public class SignatureCardFactory {
try {
Class<?> scClass = cl.loadClass(supportedCard.getImplementationClassName());
sc = (SignatureCard) scClass.newInstance();
+
+ sc = ExclSignatureCardProxy.newInstance(sc);
+
sc.init(card, cardTerminal);
+
return sc;
} catch (ClassNotFoundException e) {
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java
new file mode 100644
index 00000000..23c1f0fd
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java
@@ -0,0 +1,200 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc;
+
+public class VerifyAPDUSpec {
+
+ public static final int PIN_JUSTIFICATION_LEFT = 0;
+
+ public static final int PIN_JUSTIFICATION_RIGHT = 1;
+
+ public static final int PIN_FORMAT_BINARY = 0;
+
+ public static final int PIN_FORMAT_BCD = 1;
+
+ public static final int PIN_FORMAT_ASCII = 2;
+
+ /**
+ * The APDU template.
+ */
+ protected byte[] apdu;
+
+ /**
+ * The PIN position in bytes.
+ */
+ protected int pinPosition;
+
+ /**
+ * The PIN justification (either {@link #PIN_JUSTIFICATION_LEFT} or
+ * {@link #PIN_JUSTIFICATION_RIGHT}).
+ */
+ protected int pinJustification = PIN_JUSTIFICATION_LEFT;
+
+ /**
+ * The PIN encoding format (one of {@value #PIN_FORMAT_BCD},
+ * {@link #PIN_FORMAT_ASCII}).
+ */
+ protected int pinFormat;
+
+ /**
+ * The size of the PIN length in bits or 0 for no PIN length. (Default: 0)
+ */
+ protected int pinLengthSize = 0;
+
+ /**
+ * The PIN length in the template in bytes.
+ */
+ protected int pinLength;
+
+ /**
+ * The PIN length position in the template in bits or 0 for no PIN length.
+ * (Default: 0)
+ */
+ protected int pinLengthPos = 0;
+
+ /**
+ * @param apdu
+ * @param pinPosition
+ * @param pinFormat
+ * @param pinLength TODO
+ */
+ public VerifyAPDUSpec(byte[] apdu, int pinPosition, int pinFormat, int pinLength) {
+ super();
+ this.apdu = apdu;
+ this.pinPosition = pinPosition;
+ this.pinFormat = pinFormat;
+ this.pinLength = pinLength;
+ }
+
+ /**
+ * @param apdu
+ * @param pinPosition
+ * @param pinFormat
+ * @param pinLength
+ * @param pinLengthSize
+ * @param pinLengthPos
+ */
+ public VerifyAPDUSpec(byte[] apdu, int pinPosition, int pinFormat,
+ int pinLength, int pinLengthSize, int pinLengthPos) {
+ super();
+ this.apdu = apdu;
+ this.pinPosition = pinPosition;
+ this.pinFormat = pinFormat;
+ this.pinLength = pinLength;
+ this.pinLengthSize = pinLengthSize;
+ this.pinLengthPos = pinLengthPos;
+ }
+
+ /**
+ * @return the apdu
+ */
+ public byte[] getApdu() {
+ return apdu;
+ }
+
+ /**
+ * @param apdu the apdu to set
+ */
+ public void setApdu(byte[] apdu) {
+ this.apdu = apdu;
+ }
+
+ /**
+ * @return the pinPosition
+ */
+ public int getPinPosition() {
+ return pinPosition;
+ }
+
+ /**
+ * @param pinPosition the pinPosition to set
+ */
+ public void setPinPosition(int pinPosition) {
+ this.pinPosition = pinPosition;
+ }
+
+ /**
+ * @return the pinJustification
+ */
+ public int getPinJustification() {
+ return pinJustification;
+ }
+
+ /**
+ * @param pinJustification the pinJustification to set
+ */
+ public void setPinJustification(int pinJustification) {
+ this.pinJustification = pinJustification;
+ }
+
+ /**
+ * @return the pinFormat
+ */
+ public int getPinFormat() {
+ return pinFormat;
+ }
+
+ /**
+ * @param pinFormat the pinFormat to set
+ */
+ public void setPinFormat(int pinFormat) {
+ this.pinFormat = pinFormat;
+ }
+
+ /**
+ * @return the pinLengthSize
+ */
+ public int getPinLengthSize() {
+ return pinLengthSize;
+ }
+
+ /**
+ * @param pinLengthSize the pinLengthSize to set
+ */
+ public void setPinLengthSize(int pinLengthSize) {
+ this.pinLengthSize = pinLengthSize;
+ }
+
+ /**
+ * @return the pinLength
+ */
+ public int getPinLength() {
+ return pinLength;
+ }
+
+ /**
+ * @param pinLength the pinLength to set
+ */
+ public void setPinLength(int pinLength) {
+ this.pinLength = pinLength;
+ }
+
+ /**
+ * @return the pinLengthPos
+ */
+ public int getPinLengthPos() {
+ return pinLengthPos;
+ }
+
+ /**
+ * @param pinLengthPos the pinLengthPos to set
+ */
+ public void setPinLengthPos(int pinLengthPos) {
+ this.pinLengthPos = pinLengthPos;
+ }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
index 2972f3b8..d73ff0e9 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
@@ -16,9 +16,20 @@
*/
package at.gv.egiz.smcc.ccid;
-import at.gv.egiz.smcc.*;
import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.ChangePINProvider;
+import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.NewReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.PINOperationAbortedException;
+import at.gv.egiz.smcc.PINProvider;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.VerifyAPDUSpec;
/**
*
@@ -66,6 +77,16 @@ public interface CCID {
boolean hasFeature(Byte feature);
+ ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec,
+ PINSpec pinSpec, PINProvider provider, int retries)
+ throws CancelledException, InterruptedException, CardException,
+ SignatureCardException;
+
+ ResponseAPDU modify(CardChannel channel,
+ ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec,
+ ChangePINProvider provider, int retries) throws CancelledException,
+ InterruptedException, CardException, SignatureCardException;
+
/**
* not supported by OMNIKEY CardMan 3621 with ACOS card
* @param PIN_VERIFY
@@ -107,4 +128,9 @@ public interface CCID {
byte getwPINMaxExtraDigitL();
byte getwPINMaxExtraDigitH();
byte getbEntryValidationCondition();
+
+ ResponseAPDU activate(CardChannel channel, NewReferenceDataAPDUSpec apduSpec,
+ PINSpec pinSpec, PINProvider provider)
+ throws CancelledException, InterruptedException, CardException,
+ SignatureCardException;
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
index 580b9379..682390e3 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
@@ -16,16 +16,34 @@
*/
package at.gv.egiz.smcc.ccid;
-import at.gv.egiz.smcc.*;
-import at.gv.egiz.smcc.util.SMCCHelper;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+
import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
+import javax.smartcardio.ResponseAPDU;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.ChangePINProvider;
+import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.NewReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.PINFormatException;
+import at.gv.egiz.smcc.PINOperationAbortedException;
+import at.gv.egiz.smcc.PINProvider;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.TimeoutException;
+import at.gv.egiz.smcc.VerifyAPDUSpec;
+import at.gv.egiz.smcc.util.ISO7816Utils;
+import at.gv.egiz.smcc.util.SMCCHelper;
+
/**
*
* @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
@@ -415,4 +433,339 @@ public class DefaultReader implements CCID {
}
return resp;
}
+
+
+
+ protected byte[] createPINModifyStructure(NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) {
+
+ ByteArrayOutputStream s = new ByteArrayOutputStream();
+ // bTimeOut
+ s.write(getbTimeOut());
+ // bTimeOut2
+ s.write(getbTimeOut2());
+ // bmFormatString
+ s.write(1 << 7 // system unit = byte
+ | (0xF & apduSpec.getPinPosition()) << 3
+ | (0x1 & apduSpec.getPinJustification() << 2)
+ | (0x3 & apduSpec.getPinFormat()));
+ // bmPINBlockString
+ s.write((0xF & apduSpec.getPinLengthSize()) << 4
+ | (0xF & apduSpec.getPinLength()));
+ // bmPINLengthFormat
+ s.write(// system unit = bit
+ (0xF & apduSpec.getPinLengthPos()));
+ // bInsertionOffsetOld
+ s.write(0x00);
+ // bInsertionOffsetNew
+ s.write(apduSpec.getPinInsertionOffsetNew());
+ // wPINMaxExtraDigit
+ s.write(Math.min(pinSpec.getMaxLength(), getwPINMaxExtraDigitL()));
+ s.write(Math.max(pinSpec.getMinLength(), getwPINMaxExtraDigitH()));
+ // bConfirmPIN
+ s.write(0x01);
+ // bEntryValidationCondition
+ s.write(getbEntryValidationCondition());
+ // bNumberMessage
+ s.write(0x02);
+ // wLangId
+ s.write(0x0C);
+ s.write(0x04);
+ // bMsgIndex1
+ s.write(0x01);
+ // bMsgIndex2
+ s.write(0x02);
+ // bMsgIndex3
+ s.write(0x00);
+
+ // bTeoPrologue
+ s.write(0x00);
+ s.write(0x00);
+ s.write(0x00);
+ // ulDataLength
+ s.write(apduSpec.getApdu().length);
+ s.write(0x00);
+ s.write(0x00);
+ s.write(0x00);
+ // abData
+ try {
+ s.write(apduSpec.getApdu());
+ } catch (IOException e) {
+ // As we are dealing with ByteArrayOutputStreams no exception is to be
+ // expected.
+ throw new RuntimeException(e);
+ }
+
+ return s.toByteArray();
+
+ }
+
+ protected byte[] createPINModifyStructure(ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) {
+
+ ByteArrayOutputStream s = new ByteArrayOutputStream();
+ // bTimeOut
+ s.write(getbTimeOut());
+ // bTimeOut2
+ s.write(getbTimeOut2());
+ // bmFormatString
+ s.write(1 << 7 // system unit = byte
+ | (0xF & apduSpec.getPinPosition()) << 3
+ | (0x1 & apduSpec.getPinJustification() << 2)
+ | (0x3 & apduSpec.getPinFormat()));
+ // bmPINBlockString
+ s.write((0xF & apduSpec.getPinLengthSize()) << 4
+ | (0xF & apduSpec.getPinLength()));
+ // bmPINLengthFormat
+ s.write(// system unit = bit
+ (0xF & apduSpec.getPinLengthPos()));
+ // bInsertionOffsetOld
+ s.write(apduSpec.getPinInsertionOffsetOld());
+ // bInsertionOffsetNew
+ s.write(apduSpec.getPinInsertionOffsetNew());
+ // wPINMaxExtraDigit
+ s.write(Math.min(pinSpec.getMaxLength(), getwPINMaxExtraDigitL()));
+ s.write(Math.max(pinSpec.getMinLength(), getwPINMaxExtraDigitH()));
+ // bConfirmPIN
+ s.write(0x03);
+ // bEntryValidationCondition
+ s.write(getbEntryValidationCondition());
+ // bNumberMessage
+ s.write(0x03);
+ // wLangId
+ s.write(0x0C);
+ s.write(0x04);
+ // bMsgIndex1
+ s.write(0x00);
+ // bMsgIndex2
+ s.write(0x01);
+ // bMsgIndex3
+ s.write(0x02);
+
+ // bTeoPrologue
+ s.write(0x00);
+ s.write(0x00);
+ s.write(0x00);
+ // ulDataLength
+ s.write(apduSpec.getApdu().length);
+ s.write(0x00);
+ s.write(0x00);
+ s.write(0x00);
+ // abData
+ try {
+ s.write(apduSpec.getApdu());
+ } catch (IOException e) {
+ // As we are dealing with ByteArrayOutputStreams no exception is to be
+ // expected.
+ throw new RuntimeException(e);
+ }
+
+ return s.toByteArray();
+
+ }
+
+ protected byte[] createPINVerifyStructure(VerifyAPDUSpec apduSpec, PINSpec pinSpec) {
+
+ ByteArrayOutputStream s = new ByteArrayOutputStream();
+ // bTimeOut
+ s.write(getbTimeOut());
+ // bTimeOut2
+ s.write(getbTimeOut2());
+ // bmFormatString
+ s.write(1 << 7 // system unit = byte
+ | (0xF & apduSpec.getPinPosition()) << 3
+ | (0x1 & apduSpec.getPinJustification() << 2)
+ | (0x3 & apduSpec.getPinFormat()));
+ // bmPINBlockString
+ s.write((0xF & apduSpec.getPinLengthSize()) << 4
+ | (0xF & apduSpec.getPinLength()));
+ // bmPINLengthFormat
+ s.write(// system unit = bit
+ (0xF & apduSpec.getPinLengthPos()));
+ // wPINMaxExtraDigit
+ s.write(Math.min(pinSpec.getMaxLength(), getwPINMaxExtraDigitL())); // max PIN length
+ s.write(Math.max(pinSpec.getMinLength(), getwPINMaxExtraDigitH())); // min PIN length
+ // bEntryValidationCondition
+ s.write(getbEntryValidationCondition());
+ // bNumberMessage
+ s.write(0xFF);
+ // wLangId
+ s.write(0x0C);
+ s.write(0x04);
+ // bMsgIndex
+ s.write(0x00);
+ // bTeoPrologue
+ s.write(0x00);
+ s.write(0x00);
+ s.write(0x00);
+ // ulDataLength
+ s.write(apduSpec.getApdu().length);
+ s.write(0x00);
+ s.write(0x00);
+ s.write(0x00);
+ // abData
+ try {
+ s.write(apduSpec.getApdu());
+ } catch (IOException e) {
+ // As we are dealing with ByteArrayOutputStreams no exception is to be
+ // expected.
+ throw new RuntimeException(e);
+ }
+
+ return s.toByteArray();
+
+ }
+
+ @Override
+ public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec,
+ PINSpec pinSpec, PINProvider provider, int retries)
+ throws CancelledException, InterruptedException, CardException,
+ SignatureCardException {
+
+ char[] pin = provider.providePIN(pinSpec, retries);
+
+ ResponseAPDU resp = null;
+ if (!disablePinpad && hasFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+ log.debug("VERIFY using " + FEATURES[FEATURE_VERIFY_PIN_DIRECT] + ".");
+ byte[] s = createPINVerifyStructure(apduSpec, pinSpec);
+ resp = new ResponseAPDU(verifyPinDirect(s));
+ } else if (!disablePinpad && hasFeature(FEATURE_VERIFY_PIN_START)) {
+ log.debug("VERIFY using " + FEATURES[FEATURE_MODIFY_PIN_START] + ".");
+ byte[] s = createPINVerifyStructure(apduSpec, pinSpec);
+ resp = new ResponseAPDU(verifyPin(s));
+ }
+
+ if (resp != null) {
+
+ switch (resp.getSW()) {
+
+ case 0x6400:
+ log.debug("SPE operation timed out.");
+ throw new TimeoutException();
+ case 0x6401:
+ log.debug("SPE operation was cancelled by the 'Cancel' button.");
+ throw new CancelledException();
+ case 0x6103:
+ log.debug("User entered too short or too long PIN "
+ + "regarding MIN/MAX PIN length.");
+ throw new PINFormatException();
+ case 0x6480:
+ log.debug("SPE operation was aborted by the 'Cancel' operation "
+ + "at the host system.");
+ case 0x6b80:
+ log.info("Invalid parameter in passed structure.");
+
+ default:
+ return resp;
+ }
+
+ } else {
+ log.debug("VERIFY using software pin entry.");
+ return channel.transmit(ISO7816Utils.createVerifyAPDU(apduSpec, pin));
+ }
+
+ }
+
+ @Override
+ public ResponseAPDU modify(CardChannel channel,
+ ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec,
+ ChangePINProvider provider, int retries) throws CancelledException,
+ InterruptedException, CardException, SignatureCardException {
+
+ char[] oldPin = provider.provideOldPIN(pinSpec, retries);
+ char[] newPin = provider.providePIN(pinSpec, retries);
+
+ ResponseAPDU resp = null;
+ if (!disablePinpad && hasFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+ log.debug("MODIFY using " + FEATURES[FEATURE_MODIFY_PIN_DIRECT] + ".");
+ byte[] s = createPINModifyStructure(apduSpec, pinSpec);
+ resp = new ResponseAPDU(modifyPinDirect(s));
+ } else if (!disablePinpad && hasFeature(FEATURE_MODIFY_PIN_START)) {
+ log.debug("MODIFY using " + FEATURES[FEATURE_MODIFY_PIN_START] + ".");
+ byte[] s = createPINModifyStructure(apduSpec, pinSpec);
+ resp = new ResponseAPDU(modifyPin(s));
+ }
+
+ if (resp != null) {
+
+ switch (resp.getSW()) {
+
+ case 0x6400:
+ log.debug("SPE operation timed out.");
+ throw new TimeoutException();
+ case 0x6401:
+ log.debug("SPE operation was cancelled by the 'Cancel' button.");
+ throw new CancelledException();
+ case 0x6103:
+ log.debug("User entered too short or too long PIN "
+ + "regarding MIN/MAX PIN length.");
+ throw new PINFormatException();
+ case 0x6480:
+ log.debug("SPE operation was aborted by the 'Cancel' operation "
+ + "at the host system.");
+ case 0x6b80:
+ log.info("Invalid parameter in passed structure.");
+
+ default:
+ return resp;
+ }
+
+ } else {
+ log.debug("MODIFY using software pin entry.");
+ return channel.transmit(ISO7816Utils.createChangeReferenceDataAPDU(apduSpec, oldPin, newPin));
+ }
+
+ }
+
+ @Override
+ public ResponseAPDU activate(CardChannel channel,
+ NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec,
+ PINProvider provider) throws CancelledException,
+ InterruptedException, CardException, SignatureCardException {
+
+ char[] newPin = provider.providePIN(pinSpec, -1);
+
+ ResponseAPDU resp = null;
+ if (!disablePinpad && hasFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+ log.debug("MODIFY using " + FEATURES[FEATURE_MODIFY_PIN_DIRECT] + ".");
+ byte[] s = createPINModifyStructure(apduSpec, pinSpec);
+ resp = new ResponseAPDU(modifyPinDirect(s));
+ } else if (!disablePinpad && hasFeature(FEATURE_MODIFY_PIN_START)) {
+ log.debug("MODIFY using " + FEATURES[FEATURE_MODIFY_PIN_START] + ".");
+ byte[] s = createPINModifyStructure(apduSpec, pinSpec);
+ resp = new ResponseAPDU(modifyPin(s));
+ }
+
+ if (resp != null) {
+
+ switch (resp.getSW()) {
+
+ case 0x6400:
+ log.debug("SPE operation timed out.");
+ throw new TimeoutException();
+ case 0x6401:
+ log.debug("SPE operation was cancelled by the 'Cancel' button.");
+ throw new CancelledException();
+ case 0x6103:
+ log.debug("User entered too short or too long PIN "
+ + "regarding MIN/MAX PIN length.");
+ throw new PINFormatException();
+ case 0x6480:
+ log.debug("SPE operation was aborted by the 'Cancel' operation "
+ + "at the host system.");
+ case 0x6b80:
+ log.info("Invalid parameter in passed structure.");
+
+ default:
+ return resp;
+ }
+
+ } else {
+ log.debug("MODIFY using software pin entry.");
+ return channel.transmit(ISO7816Utils.createNewReferenceDataAPDU(apduSpec, newPin));
+ }
+
+ }
+
+
+
+
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/conf/SMCCConfiguration.java b/smcc/src/main/java/at/gv/egiz/smcc/conf/SMCCConfiguration.java
index 8ea49ca6..696709bd 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/conf/SMCCConfiguration.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/conf/SMCCConfiguration.java
@@ -25,6 +25,8 @@ import java.util.Properties;
*/
public class SMCCConfiguration extends Properties {
+ private static final long serialVersionUID = 1L;
+
public static final String DISABLE_PINPAD_P = "disable.pinpad";
public void setDisablePinpad(String value) {
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java b/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java
new file mode 100644
index 00000000..c5c7cbc9
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java
@@ -0,0 +1,359 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.NewReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.SecurityStatusNotSatisfiedException;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.VerifyAPDUSpec;
+
+public class ISO7816Utils {
+
+ public static TransparentFileInputStream openTransparentFileInputStream(
+ final CardChannel channel, int maxSize) {
+
+ TransparentFileInputStream file = new TransparentFileInputStream(maxSize) {
+
+ @Override
+ protected byte[] readBinary(int offset, int len) throws IOException {
+
+ ResponseAPDU resp;
+ try {
+ resp = channel.transmit(new CommandAPDU(0x00, 0xB0,
+ 0x7F & (offset >> 8), offset & 0xFF, len));
+ } catch (CardException e) {
+ throw new IOException(e);
+ }
+
+ Throwable cause;
+ if (resp.getSW() == 0x9000) {
+ return resp.getData();
+ } else if (resp.getSW() == 0x6982) {
+ cause = new SecurityStatusNotSatisfiedException();
+ } else {
+ cause = new SignatureCardException("Failed to read bytes (offset=" + offset + ",len="
+ + len + ") SW=" + Integer.toHexString(resp.getSW()) + ".");
+ }
+ throw new IOException(cause);
+
+ }
+
+ };
+
+ return file;
+
+ }
+
+ public static byte[] readTransparentFile(CardChannel channel, int maxSize)
+ throws CardException, SignatureCardException {
+
+ TransparentFileInputStream is = openTransparentFileInputStream(channel, maxSize);
+
+ try {
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ int len;
+ for (byte[] b = new byte[256]; (len = is.read(b)) != -1;) {
+ os.write(b, 0, len);
+ }
+
+ return os.toByteArray();
+
+ } catch (IOException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof CardException) {
+ throw (CardException) cause;
+ }
+ if (cause instanceof SignatureCardException) {
+ throw (SignatureCardException) cause;
+ }
+ throw new SignatureCardException(e);
+ }
+
+ }
+
+ public static byte[] readTransparentFileTLV(CardChannel channel, int maxSize,
+ byte expectedType) throws CardException, SignatureCardException {
+
+ TransparentFileInputStream is = openTransparentFileInputStream(channel,
+ maxSize);
+
+ try {
+
+ is.mark(256);
+
+ // check expected type
+ int b = is.read();
+ if (b == 0x00) {
+ return null;
+ }
+ if (b == -1 || expectedType != (0xFF & b)) {
+ throw new SignatureCardException("Unexpected TLV type. Expected "
+ + Integer.toHexString(expectedType) + " but was "
+ + Integer.toHexString(b) + ".");
+ }
+
+ // get actual length
+ int actualSize = 2;
+ b = is.read();
+ if (b == -1) {
+ return null;
+ } else if ((0x80 & b) > 0) {
+ int octets = (0x0F & b);
+ actualSize += octets;
+ for (int i = 1; i <= octets; i++) {
+ b = is.read();
+ if (b == -1) {
+ return null;
+ }
+ actualSize += (0xFF & b) << ((octets - i) * 8);
+ }
+ } else {
+ actualSize += 0xFF & b;
+ }
+
+ // set limit to actual size and read into buffer
+ is.reset();
+ is.setLimit(actualSize);
+ byte[] buf = new byte[actualSize];
+ if (is.read(buf) == actualSize) {
+ return buf;
+ } else {
+ return null;
+ }
+
+ } catch (IOException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof CardException) {
+ throw (CardException) cause;
+ }
+ if (cause instanceof SignatureCardException) {
+ throw (SignatureCardException) cause;
+ }
+ throw new SignatureCardException(e);
+ }
+
+ }
+
+ public static int getLengthFromFCx(byte[] fcx) {
+
+ int len = -1;
+
+ if (fcx.length != 0 && (fcx[0] == (byte) 0x62 || fcx[0] == (byte) 0x6F)) {
+ int pos = 2;
+ while (pos < (fcx[1] - 2)) {
+ switch (fcx[pos]) {
+
+ case (byte) 0x80: {
+ len = 0xFF & fcx[pos + 2];
+ for (int i = 1; i < fcx[pos + 1]; i++) {
+ len<<=8;
+ len+=0xFF & fcx[pos + i + 2];
+ }
+ }
+
+ default:
+ pos += 0xFF & fcx[pos + 1] + 2;
+ }
+ }
+ }
+
+ return len;
+
+ }
+
+ public static byte[] readRecord(CardChannel channel, int record) throws CardException, SignatureCardException {
+
+ ResponseAPDU resp = channel.transmit(
+ new CommandAPDU(0x00, 0xB2, record, 0x04, 256));
+ if (resp.getSW() == 0x9000) {
+ return resp.getData();
+ } else {
+ throw new SignatureCardException("Failed to read records. SW="
+ + Integer.toHexString(resp.getSW()));
+ }
+
+ }
+
+ public static void formatPIN(int pinFormat, int pinJustification, byte[] fpin, byte[] mask, char[] pin) {
+
+ boolean left = (pinJustification == VerifyAPDUSpec.PIN_JUSTIFICATION_LEFT);
+
+ int j = (left) ? 0 : fpin.length - 1;
+ int step = (left) ? 1 : - 1;
+ switch (pinFormat) {
+ case VerifyAPDUSpec.PIN_FORMAT_BINARY:
+ if (fpin.length < pin.length) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < pin.length; i++) {
+ fpin[j] = (byte) Character.digit(pin[i], 10);
+ mask[j] = (byte) 0xFF;
+ j += step;
+ }
+ break;
+
+ case VerifyAPDUSpec.PIN_FORMAT_BCD:
+ if (fpin.length * 2 < pin.length) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < pin.length; i++) {
+ int digit = Character.digit(pin[i], 10);
+ boolean h = (i % 2 == 0) ^ left;
+ fpin[j] |= h ? digit : digit << 4 ;
+ mask[j] |= h ? (byte) 0x0F : (byte) 0xF0;
+ j += (i % 2) * step;
+ }
+ break;
+
+ case VerifyAPDUSpec.PIN_FORMAT_ASCII:
+ if (fpin.length < pin.length) {
+ throw new IllegalArgumentException();
+ }
+ byte[] asciiPin = Charset.forName("ASCII").encode(CharBuffer.wrap(pin)).array();
+ for (int i = 0; i < pin.length; i++) {
+ fpin[j] = asciiPin[i];
+ mask[j] = (byte) 0xFF;
+ j += step;
+ }
+ break;
+ }
+
+ }
+
+ public static void insertPIN(byte[] apdu, int pos, byte[] fpin, byte[] mask) {
+ for (int i = 0; i < fpin.length; i++) {
+ apdu[pos + i] &= ~mask[i];
+ apdu[pos + i] |= fpin[i];
+ }
+ }
+
+ public static void insertPINLength(byte[] apdu, int length, int lengthSize, int pos, int offset) {
+
+ // use short (2 byte) to be able to shift the pin length
+ // by the number of bits given by the pin length position
+ short size = (short) (0x00FF & length);
+ short sMask = (short) ((1 << lengthSize) - 1);
+ // shift to the proper position
+ int shift = 16 - lengthSize - (pos % 8);
+ offset += (pos / 8) + 5;
+ size <<= shift;
+ sMask <<= shift;
+ // insert upper byte
+ apdu[offset] &= (0xFF & (~sMask >> 8));
+ apdu[offset] |= (0xFF & (size >> 8));
+ // insert lower byte
+ apdu[offset + 1] &= (0xFF & ~sMask);
+ apdu[offset + 1] |= (0xFF & size);
+
+ }
+
+ public static CommandAPDU createVerifyAPDU(VerifyAPDUSpec apduSpec, char[] pin) {
+
+ // format pin
+ byte[] fpin = new byte[apduSpec.getPinLength()];
+ byte[] mask = new byte[apduSpec.getPinLength()];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, pin);
+
+ byte[] apdu = apduSpec.getApdu();
+
+ // insert formated pin
+ insertPIN(apdu, apduSpec.getPinPosition() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, pin.length, apduSpec.getPinLengthSize(), apduSpec.getPinLengthPos(), 0);
+ }
+
+ return new CommandAPDU(apdu);
+
+ }
+
+ public static CommandAPDU createChangeReferenceDataAPDU(
+ ChangeReferenceDataAPDUSpec apduSpec, char[] oldPin, char[] newPin) {
+
+ // format old pin
+ byte[] fpin = new byte[apduSpec.getPinLength()];
+ byte[] mask = new byte[apduSpec.getPinLength()];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, oldPin);
+
+ byte[] apdu = apduSpec.getApdu();
+
+ // insert formated old pin
+ insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetOld() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, oldPin.length, apduSpec.getPinLengthSize(),
+ apduSpec.getPinLengthPos(), apduSpec.getPinInsertionOffsetOld());
+ }
+
+ // format new pin
+ fpin = new byte[apduSpec.getPinLength()];
+ mask = new byte[apduSpec.getPinLength()];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, newPin);
+
+ // insert formated new pin
+ insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetNew() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, newPin.length, apduSpec.getPinLengthSize(),
+ apduSpec.getPinLengthPos(), apduSpec.getPinInsertionOffsetNew());
+ }
+
+ return new CommandAPDU(apdu);
+
+ }
+
+ public static CommandAPDU createNewReferenceDataAPDU(
+ NewReferenceDataAPDUSpec apduSpec, char[] newPin) {
+
+ // format old pin
+ byte[] fpin = new byte[apduSpec.getPinLength()];
+ byte[] mask = new byte[apduSpec.getPinLength()];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, newPin);
+
+ byte[] apdu = apduSpec.getApdu();
+
+ // insert formated new pin
+ insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetNew() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, newPin.length, apduSpec.getPinLengthSize(),
+ apduSpec.getPinLengthPos(), apduSpec.getPinInsertionOffsetNew());
+ }
+
+ return new CommandAPDU(apdu);
+
+ }
+
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java b/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java
new file mode 100644
index 00000000..781f9137
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java
@@ -0,0 +1,194 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package at.gv.egiz.smcc.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class TransparentFileInputStream extends InputStream {
+
+ private final int chunkSize = 256;
+
+ private byte[] buf = new byte[chunkSize];
+ private int start = 0;
+ private int end = 0;
+
+ private int offset = 0;
+
+ private int length = -1;
+
+ private int limit = -1;
+
+ private int mark = -1;
+
+ private int readlimit = -1;
+
+ public TransparentFileInputStream() {
+ }
+
+ public TransparentFileInputStream(int length) {
+ this.length = length;
+ }
+
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ private int fill() throws IOException {
+ if (start == end && (limit < 0 || offset < limit)) {
+ int l;
+ if (limit > 0 && limit - offset < chunkSize) {
+ l = limit - offset;
+ } else if (length > 0) {
+ if (length - offset < chunkSize) {
+ l = length - offset;
+ } else {
+ l = chunkSize - 1;
+ }
+ } else {
+ l = chunkSize;
+ }
+ byte[] b = readBinary(offset, l);
+ offset += b.length;
+ if (mark < 0) {
+ start = 0;
+ end = b.length;
+ System.arraycopy(b, 0, buf, start, b.length);
+ } else {
+ if (end - mark + b.length > buf.length) {
+ // double buffer size
+ byte[] nbuf = new byte[buf.length * 2];
+ System.arraycopy(buf, mark, nbuf, 0, end - mark);
+ buf = nbuf;
+ } else {
+ System.arraycopy(buf, mark, buf, 0, end - mark);
+ }
+ start = start - mark;
+ end = end - mark + b.length;
+ mark = 0;
+ System.arraycopy(b, 0, buf, start, b.length);
+ }
+ if (l > b.length) {
+ // end of file reached
+ setLimit(offset);
+ }
+ }
+ return end - start;
+ }
+
+ protected abstract byte[] readBinary(int offset, int len) throws IOException;
+
+ @Override
+ public int read() throws IOException {
+ int b = (fill() > 0) ? 0xFF & buf[start++] : -1;
+ if (readlimit > 0 && start > readlimit) {
+ mark = -1;
+ readlimit = -1;
+ }
+ return b;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int count = 0;
+ int l;
+ while (count < len) {
+ if (fill() > 0) {
+ l = Math.min(end - start, len - count);
+ System.arraycopy(buf, start, b, off, l);
+ start += l;
+ off += l;
+ count += l;
+ if (readlimit > 0 && start > readlimit) {
+ mark = -1;
+ readlimit = -1;
+ }
+ } else {
+ return (count > 0) ? count : -1;
+ }
+ }
+
+ return count;
+
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ this.readlimit = readlimit;
+ mark = start;
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (mark < 0) {
+ throw new IOException();
+ } else {
+ start = mark;
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+
+ if (n <= 0) {
+ return 0;
+ }
+
+ if (n <= end - start) {
+ start += n;
+ return n;
+ } else {
+
+ mark = -1;
+
+ long remaining = n - (end - start);
+ start = end;
+
+ if (limit >= 0 && limit < offset + remaining) {
+ remaining -= limit - offset;
+ offset = limit;
+ return n - remaining;
+ }
+
+ if (length >= 0 && length < offset + remaining) {
+ remaining -= length - offset;
+ offset = length;
+ return n - remaining;
+ }
+
+ offset += remaining;
+
+ return n;
+
+ }
+
+ }
+
+}