summaryrefslogtreecommitdiff
path: root/smcc/src
diff options
context:
space:
mode:
Diffstat (limited to 'smcc/src')
-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
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java135
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java56
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/CardAppl.java43
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/CardChannelEmul.java52
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java106
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/CardTerminalEmul.java64
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/CardTest.java298
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/CardTestSuite.java29
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/File.java38
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/PIN.java41
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java267
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/TransparentFileInputStreamTest.java208
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java151
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplSIG.java77
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardChannelEmul.java98
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java36
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java91
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplDEC.java296
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplSIG.java87
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardChannelEmul.java75
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java37
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java143
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSAppl.java79
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java334
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java302
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardChannelEmul.java261
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardEmul.java38
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java243
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTestSuite.java27
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java95
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java332
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java160
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java347
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java375
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java50
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java297
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/util/ISO7816UtilsTest.java175
64 files changed, 7951 insertions, 2350 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;
+
+ }
+
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java
deleted file mode 100644
index 5839d14a..00000000
--- a/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package at.gv.egiz.smcc;
-
-import at.gv.egiz.smcc.SignatureCard.KeyboxName;
-import at.gv.egiz.smcc.util.SMCCHelper;
-import java.util.List;
-import java.util.Locale;
-import javax.smartcardio.ResponseAPDU;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-/**
- *
- * @author clemens
- */
-@Ignore
-public class ACOSCardTest {
-
- static ACOSCard card;
- static PINSpec infPin, decPin, sigPin;
-
- public ACOSCardTest() {
- }
-
- @BeforeClass
- public static void setUpClass() throws Exception {
- SMCCHelper smccHelper = new SMCCHelper();
- switch (smccHelper.getResultCode()) {
- case SMCCHelper.CARD_FOUND:
- SignatureCard sigCard = smccHelper.getSignatureCard(Locale.GERMAN);
- if (sigCard instanceof ACOSCard) {
- System.out.println("ACOS card found");
- card = (ACOSCard) sigCard;
- List<PINSpec> pinSpecs = card.getPINSpecs();
- infPin = pinSpecs.get(ACOSCard.PINSPEC_INF);
- decPin = pinSpecs.get(ACOSCard.PINSPEC_DEC);
- sigPin = pinSpecs.get(ACOSCard.PINSPEC_SIG);
- } else {
- throw new Exception("not STARCOS card: " + sigCard.toString());
- }
- break;
- default:
- throw new Exception("no card found");
- }
- }
-
- @AfterClass
- public static void tearDownClass() throws Exception {
- }
-
- @Before
- public void setUp() {
- }
-
- @After
- public void tearDown() {
- }
-
-
-
- /**
- * Test of verifyPIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testVerifyPIN_pinpad() throws Exception {
- System.out.println("verifyPIN (pinpad)");
- assertNotNull(card);
-
- card.verifyPIN(decPin, new PINProvider() {
-
- @Override
- public char[] providePIN(PINSpec spec, int retries) {
- return null;
- }
- });
- }
-
- /**
- * Test of verifyPIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testVerifyPIN_internal() throws Exception {
- System.out.println("verifyPIN (internal)");
- assertNotNull(card);
-
- card.reset();
-
- card.getCard().beginExclusive();
-
- // 0x6700 without sending an APDU prior to send CtrlCmd
- System.out.println("WARNING: this command will fail if no card " +
- "communication took place prior to sending the CtrlCommand");
- int retries = card.verifyPIN(decPin.getKID(), null); //"1397".toCharArray());
-
- System.out.println("VERIFY PIN returned " + retries);
- card.getCard().endExclusive();
- }
-
- /**
- * Test of changePIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testChangePIN() throws Exception {
- System.out.println("changePIN");
- assertNotNull(card);
-
- card.reset();
- int retries = card.changePIN(decPin.getKID(), null, null);
-
- System.out.println("CHANGE PIN returned " + retries);
- }
-
- /**
- * Test of reset method, of class STARCOSCard.
- */
- @Test
- public void testReset() throws Exception {
- System.out.println("reset");
- assertNotNull(card);
- card.reset();
- }
-
-} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java
new file mode 100644
index 00000000..137de509
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java
@@ -0,0 +1,56 @@
+/*
+* 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;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+
+public abstract class AbstractAppl implements CardAppl {
+
+ public final HashMap<Integer, PIN> pins = new HashMap<Integer, PIN>();
+
+ protected List<File> files = new ArrayList<File>();
+
+ public void checkINS(CommandAPDU command, int ins) {
+ if (command.getINS() != ins) {
+ throw new IllegalArgumentException("INS has to be 0x" + Integer.toHexString(ins) + ".");
+ }
+ }
+
+ @Override
+ public abstract byte[] getAID();
+
+ @Override
+ public abstract byte[] getFCI();
+
+ public void putFile(File file) {
+ files.add(file);
+ }
+
+ public List<File> getFiles() {
+ return files;
+ }
+
+ public abstract void setPin(int kid, char[] value);
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/CardAppl.java
new file mode 100644
index 00000000..76a3e567
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardAppl.java
@@ -0,0 +1,43 @@
+/*
+* 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 javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+
+@SuppressWarnings("restriction")
+public interface CardAppl {
+
+ public byte[] getAID();
+
+ public byte[] getFID();
+
+ public byte[] getFCI();
+
+ public void leaveApplContext();
+
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel) throws CardException;
+
+ public ResponseAPDU cmdPERFORM_SECURITY_OPERATION(CommandAPDU command, CardChannelEmul channel) throws CardException;
+
+ public ResponseAPDU cmdINTERNAL_AUTHENTICATE(CommandAPDU command, CardChannelEmul channel) throws CardException;
+
+ public void setPin(int kid, char[] value);
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/CardChannelEmul.java
new file mode 100644
index 00000000..bfe4e31c
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardChannelEmul.java
@@ -0,0 +1,52 @@
+/*
+* 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.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+
+@SuppressWarnings("restriction")
+public abstract class CardChannelEmul extends CardChannel {
+
+ protected AbstractAppl currentAppl = null;
+ protected File currentFile = null;
+
+ public CardChannelEmul() {
+ super();
+ }
+
+ @Override
+ public int getChannelNumber() {
+ return 0;
+ }
+
+ @Override
+ public void close() throws CardException {
+ throw new IllegalStateException("Basic logical channel cannot be closed.");
+ }
+
+ @Override
+ public int transmit(ByteBuffer command, ByteBuffer response) throws CardException {
+ byte[] responseBytes = transmit(new CommandAPDU(command)).getBytes();
+ response.put(responseBytes);
+ return responseBytes.length;
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java
new file mode 100644
index 00000000..6017bcce
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java
@@ -0,0 +1,106 @@
+/*
+* 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;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+
+
+@SuppressWarnings("restriction")
+public abstract class CardEmul extends Card {
+
+ protected Thread exclThread = null;
+ protected CardChannel channel = newCardChannel(this);
+ protected List<AbstractAppl> applications = new ArrayList<AbstractAppl>();
+
+ public CardEmul() {
+ super();
+ }
+
+ protected abstract CardChannelEmul newCardChannel(CardEmul cardEmul);
+
+ @Override
+ public void beginExclusive() throws CardException {
+
+ if (exclThread == Thread.currentThread()) {
+ throw new CardException("Exclusive access already assigned to current thread.");
+ } else if (exclThread != null) {
+ throw new CardException("Exclusive access already assigned to another thread.");
+ }
+
+ exclThread = Thread.currentThread();
+
+ }
+
+ @Override
+ public void endExclusive() throws CardException {
+
+ if (exclThread == Thread.currentThread()) {
+ exclThread = null;
+ } else if (exclThread == null) {
+ throw new CardException("Exclusive access has not been assigned.");
+ } else {
+ throw new CardException("Exclusive access has not been assigned to current thread.");
+ }
+
+ }
+
+ @Override
+ public CardChannel getBasicChannel() {
+ return channel;
+ }
+
+ @Override
+ public void disconnect(boolean reset) throws CardException {
+ if (reset) {
+ channel = newCardChannel(this);
+ }
+ }
+
+ @Override
+ public CardChannel openLogicalChannel() throws CardException {
+ throw new CardException("Logical channels not supported.");
+ }
+
+ @Override
+ public String getProtocol() {
+ return "T1";
+ }
+
+ @Override
+ public byte[] transmitControlCommand(int arg0, byte[] arg1)
+ throws CardException {
+ throw new CardException("transmitControlCommand() not supported.");
+ }
+
+ public AbstractAppl getApplication(byte[] fid) {
+
+ for(AbstractAppl appl : applications) {
+ if (Arrays.equals(appl.getAID(), fid) || Arrays.equals(appl.getFID(), fid)) {
+ return appl;
+ }
+ }
+ return null;
+
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardTerminalEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/CardTerminalEmul.java
new file mode 100644
index 00000000..b13de62f
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardTerminalEmul.java
@@ -0,0 +1,64 @@
+/*
+* 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 javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+
+public class CardTerminalEmul extends CardTerminal {
+
+ private Card card;
+
+ public CardTerminalEmul(Card card) {
+ this.card = card;
+ }
+
+ @Override
+ public Card connect(String protocol) throws CardException {
+ if ("*".equals(protocol) || "T=1".equals(protocol)) {
+ return card;
+ } else {
+ throw new CardException("Protocol '" + protocol + "' not supported.");
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "CardTerminal Emulation";
+ }
+
+ @Override
+ public boolean isCardPresent() throws CardException {
+ return true;
+ }
+
+ @Override
+ public boolean waitForCardAbsent(long timeout) throws CardException {
+ try {
+ Thread.sleep(timeout);
+ } catch (InterruptedException e) {
+ }
+ return false;
+ }
+
+ @Override
+ public boolean waitForCardPresent(long timeout) throws CardException {
+ return true;
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java
new file mode 100644
index 00000000..298e26a5
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java
@@ -0,0 +1,298 @@
+/*
+* 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 static org.junit.Assert.*;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.smartcardio.Card;
+
+import org.junit.Test;
+
+import at.gv.egiz.smcc.SignatureCard.KeyboxName;
+import at.gv.egiz.smcc.acos.A04ApplDEC;
+
+@SuppressWarnings("restriction")
+public abstract class CardTest {
+
+ public class TestPINProvider implements PINProvider {
+
+ int provided = 0;
+
+ char[] pin;
+
+ public TestPINProvider(char[] pin) {
+ super();
+ this.pin = pin;
+ }
+
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+ provided++;
+ return pin;
+ }
+
+ public int getProvided() {
+ return provided;
+ }
+
+ }
+
+ public class TestChangePINProvider extends TestPINProvider implements
+ ChangePINProvider {
+
+ char[] oldPin;
+
+ public TestChangePINProvider(char[] oldPin, char[] pin) {
+ super(pin);
+ this.oldPin = oldPin;
+ }
+
+ @Override
+ public char[] provideOldPIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+ return oldPin;
+ }
+
+ }
+
+ public CardTest() {
+ super();
+ }
+
+ protected abstract SignatureCard createSignatureCard()
+ throws CardNotSupportedException;
+
+ @Test
+ public void testGetCard() throws CardNotSupportedException {
+ SignatureCard signatureCard = createSignatureCard();
+ Card card = signatureCard.getCard();
+ assertNotNull(card);
+ }
+
+ @Test
+ public void testGetInfoboxIdentityLink() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ final char[] pin = "0000".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ TestPINProvider pinProvider = new TestPINProvider(pin);
+
+ byte[] idlink = signatureCard.getInfobox("IdentityLink",
+ pinProvider, null);
+ assertNotNull(idlink);
+ assertTrue(Arrays.equals(idlink, A04ApplDEC.IDLINK));
+ assertEquals(1, pinProvider.provided);
+
+ }
+
+ @Test(expected = CancelledException.class)
+ public void testSignSIGCancel() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ PINProvider pinProvider = new PINProvider() {
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+ throw new CancelledException();
+ }
+ };
+
+ signatureCard.createSignature(hash, KeyboxName.SECURE_SIGNATURE_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = CancelledException.class)
+ public void testSignDECCancel() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ PINProvider pinProvider = new PINProvider() {
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+ throw new CancelledException();
+ }
+ };
+
+ signatureCard.createSignature(hash, KeyboxName.CERITIFIED_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = InterruptedException.class)
+ public void testSignSIGInterrrupted() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ PINProvider pinProvider = new PINProvider() {
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+ throw new InterruptedException();
+ }
+ };
+
+ signatureCard.createSignature(hash, KeyboxName.SECURE_SIGNATURE_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = InterruptedException.class)
+ public void testSignDECInterrrupted() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ PINProvider pinProvider = new PINProvider() {
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+ throw new InterruptedException();
+ }
+ };
+
+ signatureCard.createSignature(hash, KeyboxName.CERITIFIED_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = CancelledException.class)
+ public void testSignSIGConcurrent() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ final SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ PINProvider pinProvider = new PINProvider() {
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+
+ try {
+ signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR);
+ assertTrue(false);
+ return null;
+ } catch (SignatureCardException e) {
+ // expected
+ throw new CancelledException();
+ }
+
+ }
+ };
+
+ signatureCard.createSignature(hash, KeyboxName.SECURE_SIGNATURE_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = CancelledException.class)
+ public void testSignDECConcurrent() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ final SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ PINProvider pinProvider = new PINProvider() {
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+
+ try {
+ signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR);
+ assertTrue(false);
+ return null;
+ } catch (SignatureCardException e) {
+ // expected
+ throw new CancelledException();
+ }
+
+ }
+ };
+
+ signatureCard.createSignature(hash, KeyboxName.CERITIFIED_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test
+ public void testGetPinSpecs() throws CardNotSupportedException {
+
+ PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
+
+ List<PINSpec> specs = signatureCard.getPINSpecs();
+ assertNotNull(specs);
+ assertTrue(specs.size() > 0);
+
+ }
+
+ @Test(expected = SignatureCardException.class)
+ public void testActivatePin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
+
+ PINProvider pinProvider = new PINProvider() {
+ @Override
+ public char[] providePIN(PINSpec spec, int retries)
+ throws CancelledException, InterruptedException {
+ throw new CancelledException();
+ }
+ };
+
+ List<PINSpec> specs = signatureCard.getPINSpecs();
+
+ signatureCard.activatePIN(specs.get(0), pinProvider);
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardTestSuite.java b/smcc/src/test/java/at/gv/egiz/smcc/CardTestSuite.java
new file mode 100644
index 00000000..3c275a8d
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardTestSuite.java
@@ -0,0 +1,29 @@
+/*
+* 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 org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+import at.gv.egiz.smcc.acos.ACOSCardTestSuite;
+
+@RunWith(Suite.class)
+@SuiteClasses( { ACOSCardTestSuite.class, at.gv.egiz.smcc.starcos.STARCOSCardTest.class })
+public class CardTestSuite {
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/File.java b/smcc/src/test/java/at/gv/egiz/smcc/File.java
new file mode 100644
index 00000000..e47c5f7d
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/File.java
@@ -0,0 +1,38 @@
+/*
+* 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 File {
+ public byte[] fid;
+ public byte[] file;
+ public byte[] fcx;
+ public int kid = -1;
+
+ public File(byte[] fid, byte[] file, byte[] fcx) {
+ this.fid = fid;
+ this.file = file;
+ this.fcx = fcx;
+ }
+
+ public File(byte[] fid, byte[] file, byte[] fcx, int kid) {
+ this.fid = fid;
+ this.file = file;
+ this.fcx = fcx;
+ this.kid = kid;
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/PIN.java b/smcc/src/test/java/at/gv/egiz/smcc/PIN.java
new file mode 100644
index 00000000..ae883727
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/PIN.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;
+
+public class PIN {
+
+ public static final int STATE_RESET = 0;
+
+ public static final int STATE_PIN_VERIFIED = 1;
+
+ public static final int STATE_PIN_BLOCKED = -1;
+
+ public byte[] pin;
+
+ public int kid;
+
+ public int state = STATE_RESET;
+
+ public int kfpc = 10;
+
+ public PIN(byte[] pin, int kid, int kfpc) {
+ this.pin = pin;
+ this.kid = kid;
+ this.kfpc = kfpc;
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
deleted file mode 100644
index 9be8db00..00000000
--- a/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package at.gv.egiz.smcc;
-
-import at.gv.egiz.smcc.SignatureCard.KeyboxName;
-import at.gv.egiz.smcc.util.SMCCHelper;
-import java.util.List;
-import java.util.Locale;
-import javax.smartcardio.ResponseAPDU;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-/**
- *
- * @author clemens
- */
-@Ignore
-public class STARCOSCardTest {
-
- static STARCOSCard card;
- static PINSpec cardPin, ssPin;
-
- public STARCOSCardTest() {
- }
-
- @BeforeClass
- public static void setUpClass() throws Exception {
- SMCCHelper smccHelper = new SMCCHelper();
- switch (smccHelper.getResultCode()) {
- case SMCCHelper.CARD_FOUND:
- SignatureCard sigCard = smccHelper.getSignatureCard(Locale.GERMAN);
- if (sigCard instanceof STARCOSCard) {
- System.out.println("STARCOS card found");
- card = (STARCOSCard) sigCard;
- List<PINSpec> pinSpecs = card.getPINSpecs();
- cardPin = pinSpecs.get(STARCOSCard.PINSPEC_CARD);
- ssPin = pinSpecs.get(STARCOSCard.PINSPEC_SS);
-
- } else {
- throw new Exception("not STARCOS card: " + sigCard.toString());
- }
- break;
- default:
- throw new Exception("no card found");
- }
- }
-
- @AfterClass
- public static void tearDownClass() throws Exception {
- }
-
- @Before
- public void setUp() {
- }
-
- @After
- public void tearDown() {
- }
-
- /**
- * Test of getCertificate method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testGetCertificate() throws Exception {
- System.out.println("getCertificate");
- KeyboxName keyboxName = null;
- STARCOSCard instance = new STARCOSCard();
- byte[] expResult = null;
- byte[] result = instance.getCertificate(keyboxName);
- assertEquals(expResult, result);
- // TODO review the generated test code and remove the default call to fail.
- fail("The test case is a prototype.");
- }
-
- /**
- * Test of getInfobox method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testGetInfobox() throws Exception {
- System.out.println("getInfobox");
- String infobox = "";
- PINProvider provider = null;
- String domainId = "";
- STARCOSCard instance = new STARCOSCard();
- byte[] expResult = null;
- byte[] result = instance.getInfobox(infobox, provider, domainId);
- assertEquals(expResult, result);
- // TODO review the generated test code and remove the default call to fail.
- fail("The test case is a prototype.");
- }
-
- /**
- * Test of createSignature method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testCreateSignature() throws Exception {
- System.out.println("createSignature");
- byte[] hash = null;
- KeyboxName keyboxName = null;
- PINProvider provider = null;
- STARCOSCard instance = new STARCOSCard();
- byte[] expResult = null;
- byte[] result = instance.createSignature(hash, keyboxName, provider);
- assertEquals(expResult, result);
- // TODO review the generated test code and remove the default call to fail.
- fail("The test case is a prototype.");
- }
-
- /**
- * Test of selectFileFID method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testSelectFileFID() throws Exception {
- System.out.println("selectFileFID");
- byte[] fid = null;
- STARCOSCard instance = new STARCOSCard();
- ResponseAPDU expResult = null;
- ResponseAPDU result = instance.selectFileFID(fid);
- assertEquals(expResult, result);
- // TODO review the generated test code and remove the default call to fail.
- fail("The test case is a prototype.");
- }
-
- /**
- * Test of verifyPIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testVerifyPIN_pinpad() throws Exception {
- System.out.println("verifyPIN (pinpad)");
- assertNotNull(card);
-
- card.verifyPIN(cardPin, new PINProvider() {
-
- @Override
- public char[] providePIN(PINSpec spec, int retries) {
- return null;
- }
- });
- }
-
- /**
- * Test of verifyPIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testVerifyPIN_internal() throws Exception {
- System.out.println("verifyPIN (internal)");
- assertNotNull(card);
-
- card.reset();
-
- card.getCard().beginExclusive();
-
- // 0x6700 without sending an APDU prior to send CtrlCmd
- System.out.println("WARNING: this command will fail if no card " +
- "communication took place prior to sending the CtrlCommand");
- int retries = card.verifyPIN(cardPin.getKID(), null); //"1397".toCharArray());
-
- System.out.println("VERIFY PIN returned " + retries);
- card.getCard().endExclusive();
- }
-
- /**
- * Test of verifyPIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testVerifyPIN_byte() throws Exception {
- System.out.println("verifyPIN");
- byte kid = 0;
- STARCOSCard instance = new STARCOSCard();
- int expResult = 0;
- int result = instance.verifyPIN(kid);
- assertEquals(expResult, result);
- // TODO review the generated test code and remove the default call to fail.
- fail("The test case is a prototype.");
- }
-
- /**
- * Test of changePIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testChangePIN() throws Exception {
- System.out.println("changePIN");
- assertNotNull(card);
-
- card.reset();
- int retries = card.changePIN(cardPin.getKID(), null, null);
-
- System.out.println("CHANGE PIN returned " + retries);
- }
-
- /**
- * Test of activatePIN method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testActivatePIN() throws Exception {
- System.out.println("activatePIN");
- assertNotNull(card);
-
- card.reset();
- card.activatePIN(cardPin, new PINProvider() {
-
- @Override
- public char[] providePIN(PINSpec spec, int retries) throws CancelledException, InterruptedException {
- return null;
- }
- });
- }
-
- /**
- * Test of encodePINBlock method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testEncodePINBlock() throws Exception {
- System.out.println("encodePINBlock");
- char[] pin = null;
- STARCOSCard instance = new STARCOSCard();
- byte[] expResult = null;
- byte[] result = instance.encodePINBlock(pin);
- assertEquals(expResult, result);
- // TODO review the generated test code and remove the default call to fail.
- fail("The test case is a prototype.");
- }
-
- /**
- * Test of reset method, of class STARCOSCard.
- */
- @Test
- public void testReset() throws Exception {
- System.out.println("reset");
- assertNotNull(card);
- card.reset();
- }
-
- /**
- * Test of toString method, of class STARCOSCard.
- */
- @Test
- @Ignore
- public void testToString() {
- System.out.println("toString");
- STARCOSCard instance = new STARCOSCard();
- String expResult = "";
- String result = instance.toString();
- assertEquals(expResult, result);
- // TODO review the generated test code and remove the default call to fail.
- fail("The test case is a prototype.");
- }
-
-} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/TransparentFileInputStreamTest.java b/smcc/src/test/java/at/gv/egiz/smcc/TransparentFileInputStreamTest.java
new file mode 100644
index 00000000..4ae48335
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/TransparentFileInputStreamTest.java
@@ -0,0 +1,208 @@
+/*
+* 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.io.IOException;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import at.gv.egiz.smcc.util.TransparentFileInputStream;
+import static org.junit.Assert.*;
+
+public class TransparentFileInputStreamTest {
+
+ public class TestTransparentFileInputStream extends TransparentFileInputStream {
+
+ private byte[] data;
+
+ public TestTransparentFileInputStream(byte[] data) {
+ this.data = data;
+ }
+
+ @Override
+ protected byte[] readBinary(int offset, int len) throws IOException {
+ int l = Math.min(len, data.length - offset);
+ byte[] b = new byte[l];
+ System.arraycopy(data, offset, b, 0, l);
+ return b;
+ }
+
+ }
+
+ protected static byte[] file;
+
+ protected static byte[] file_bs;
+
+ @BeforeClass
+ public static void setUpClass() {
+
+ byte b = 0x00;
+ file = new byte[1000];
+ for (int i = 0; i < file.length; i++) {
+ file[i] = b++;
+ }
+
+ file_bs = new byte[256];
+ b = 0x00;
+ for (int i = 0; i < file_bs.length; i++) {
+ file_bs[i] = b++;
+ }
+
+ }
+
+ @Test
+ public void testReadSeq() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ int i = 0;
+ int b;
+ while ((b = is.read()) != -1) {
+ assertEquals(0xFF & i++, b);
+ }
+ assertEquals(file.length, i);
+
+ }
+
+ @Test
+ public void testReadBlock() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ int i = 0;
+ byte[] b = new byte[28];
+ int l;
+ while ((l = is.read(b)) != -1) {
+ for(int j = 0; j < l; j++) {
+ assertEquals(0xFF & i++, 0xFF & b[j]);
+ }
+ }
+ assertEquals(file.length, i);
+
+ }
+
+ @Test
+ public void testReadBlockBS() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file_bs);
+ int i = 0;
+ byte[] b = new byte[28];
+ int l;
+ while ((l = is.read(b)) != -1) {
+ for(int j = 0; j < l; j++) {
+ assertEquals(0xFF & i++, 0xFF & b[j]);
+ }
+ }
+ assertEquals(file_bs.length, i);
+
+ }
+
+ @Test(expected = IOException.class)
+ public void testReset() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ is.read(new byte[128]);
+ is.reset();
+
+ }
+
+ @Test
+ public void testMark() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ int i = 0;
+ is.mark(12);
+ byte[] b = new byte[37];
+ int l;
+ while ((l = is.read(b)) != -1) {
+ for(int j = 0; j < l; j++) {
+ assertEquals(0xFF & i++, 0xFF & b[j]);
+ }
+ }
+ assertEquals(file.length, i);
+
+ }
+
+ @Test
+ public void testMarkReset() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ int i = 128;
+ is.read(new byte[i]);
+ is.mark(512);
+ byte[] b = new byte[256];
+ is.read(b);
+ for(int j = 0; j < b.length; j++) {
+ assertEquals(0xFF & i + j, 0xFF & b[j]);
+ }
+ is.reset();
+ int l;
+ while ((l = is.read(b)) != -1) {
+ for(int j = 0; j < l; j++) {
+ assertEquals(0xFF & i++, 0xFF & b[j]);
+ }
+ }
+ assertEquals(file.length, i);
+
+ }
+
+
+ @Test(expected = IOException.class)
+ public void testMarkResetLimit() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ int i = 128;
+ is.read(new byte[i]);
+ is.mark(128);
+ byte[] b = new byte[256];
+ is.read(b);
+ for(int j = 0; j < b.length; j++) {
+ assertEquals(0xFF & i + j, 0xFF & b[j]);
+ }
+ is.reset();
+
+ }
+
+ @Test
+ public void testSkipSmall() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ int i = 0;
+ i+= is.read(new byte[128]);
+ i+= is.skip(3);
+ byte[] b = new byte[256];
+ int l = is.read(b);
+ for (int j = 0; j < l; j++) {
+ assertEquals(0xFF & i + j, 0xFF & b[j]);
+ }
+
+ }
+ @Test
+ public void testSkipBig() throws IOException {
+
+ TransparentFileInputStream is = new TestTransparentFileInputStream(file);
+ int i = 0;
+ i+= is.read(new byte[128]);
+ i+= is.skip(300);
+ byte[] b = new byte[256];
+ int l = is.read(b);
+ for (int j = 0; j < l; j++) {
+ assertEquals(0xFF & i + j, 0xFF & b[j]);
+ }
+
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java
new file mode 100644
index 00000000..9fd96d73
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java
@@ -0,0 +1,151 @@
+/*
+* 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.acos;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+
+@SuppressWarnings("restriction")
+public class A03ApplDEC extends ACOSApplDEC {
+
+ public static final int KID_PIN_INF = 0x83;
+
+ public A03ApplDEC() {
+ super();
+
+ System.arraycopy(IDLINK, 0, EF_INFOBOX, 0, IDLINK.length);
+ putFile(new File(FID_EF_INFOBOX, EF_INFOBOX, FCI_EF_INFOBOX, KID_PIN_INF));
+
+ try {
+ pins.put(KID_PIN_INF, new PIN("0000\0\0\0\0".getBytes("ASCII"), KID_PIN_INF, 10));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel) {
+
+ checkINS(command, 0x22);
+
+ switch (command.getP2()) {
+ case 0xA4:
+ switch (command.getP1()) {
+ case 0x41: {
+ // INTERNAL AUTHENTICATE
+ byte[] dst = new byte[] { (byte) 0x84, (byte) 0x01, (byte) 0x88, (byte) 0x80, (byte) 0x01, (byte) 0x01 };
+ if (Arrays.equals(dst, command.getData())) {
+ securityEnv = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+ case 0x81:
+ // EXTERNAL AUTHENTICATE
+ }
+ case 0xB6:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO - COMPUTE DIGITAL SIGNATURE
+ case 0x81:
+ // PSO - VERIFY DGITAL SIGNATURE
+ }
+ case 0xB8:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO � DECIPHER
+ case 0x81:
+ // PSO � ENCIPHER
+ }
+ default:
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+ @Override
+ public ResponseAPDU cmdPERFORM_SECURITY_OPERATION(CommandAPDU command, CardChannelEmul channel) {
+
+ checkINS(command, 0x2A);
+
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00});
+
+ }
+
+ @Override
+ public ResponseAPDU cmdINTERNAL_AUTHENTICATE(CommandAPDU command, CardChannelEmul channel) {
+
+ checkINS(command, 0x88);
+
+ if (command.getP1() == 0x10 && command.getP2() == 0x00) {
+
+ byte[] data = command.getData();
+
+ if (securityEnv == null) {
+ // Security Environment not set or wrong
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+
+ 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) 0x14
+ };
+
+ if (data.length != 35 || !Arrays.equals(digestInfo, Arrays.copyOf(data, 15))) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+
+ if (pins.get(KID_PIN_DEC).state != PIN.STATE_PIN_VERIFIED) {
+ // Security Status not satisfied
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+
+ byte[] signature = new byte[48];
+
+ // TODO replace by signature creation
+ Random random = new Random();
+ random.nextBytes(signature);
+
+ byte[] response = new byte[signature.length + 2];
+ System.arraycopy(signature, 0, response, 0, signature.length);
+ response[signature.length] = (byte) 0x90;
+ response[signature.length + 1] = (byte) 0x00;
+
+ hash = null;
+ pins.get(KID_PIN_DEC).state = PIN.STATE_RESET;
+
+ return new ResponseAPDU(response);
+
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplSIG.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplSIG.java
new file mode 100644
index 00000000..d059ad57
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplSIG.java
@@ -0,0 +1,77 @@
+/*
+* 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.acos;
+
+import java.util.Arrays;
+
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+
+
+@SuppressWarnings("restriction")
+public class A03ApplSIG extends ACOSApplSIG {
+
+ public A03ApplSIG() {
+ super();
+ System.arraycopy(C_CH_DS, 0, EF_C_CH_DS, 0, C_CH_DS.length);
+ }
+
+ @Override
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel) {
+
+ checkINS(command, 0x22);
+
+ switch (command.getP2()) {
+ case 0xA4:
+ switch (command.getP1()) {
+ case 0x41:
+ // INTERNAL AUTHENTICATE
+ case 0x81:
+ // EXTERNAL AUTHENTICATE
+ }
+ case 0xB6:
+ switch (command.getP1()) {
+ case 0x41: {
+ // PSO - COMPUTE DIGITAL SIGNATURE
+ byte[] dst = new byte[] { (byte) 0x84, (byte) 0x01, (byte) 0x88, (byte) 0x80, (byte) 0x01, (byte) 0x14 };
+ if (Arrays.equals(dst, command.getData())) {
+ securityEnv = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+ case 0x81:
+ // PSO - VERIFY DGITAL SIGNATURE
+ }
+ case 0xB8:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO � DECIPHER
+ case 0x81:
+ // PSO � ENCIPHER
+ }
+ default:
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardChannelEmul.java
new file mode 100644
index 00000000..c8d5382c
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardChannelEmul.java
@@ -0,0 +1,98 @@
+/*
+* 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.acos;
+
+
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.PIN;
+
+
+@SuppressWarnings("restriction")
+public class A03CardChannelEmul extends ACOSCardChannelEmul {
+
+ public A03CardChannelEmul(CardEmul cardEmul) {
+ super(cardEmul);
+ }
+
+ @Override
+ public ResponseAPDU cmdREAD_BINARY(CommandAPDU command) throws CardException {
+
+ if (command.getINS() != 0xB0) {
+ throw new IllegalArgumentException("INS has to be 0xB0.");
+ }
+
+ if (currentFile == null) {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x86});
+ }
+
+ if ((command.getP1() & 0x80) > 0) {
+ throw new CardException("Not implemented.");
+ }
+
+ int offset = command.getP2() + (command.getP1() << 8);
+ if (offset > currentFile.file.length) {
+ // Wrong length
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ if (command.getNe() == 0) {
+ throw new CardException("Not implemented.");
+ }
+
+ if (currentFile.kid != -1) {
+ if ((currentFile.kid & 0x80) > 0) {
+ PIN pin;
+ if (currentAppl == null
+ || (pin = currentAppl.pins.get(currentFile.kid)) == null
+ || pin.state != PIN.STATE_PIN_VERIFIED) {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+ } else {
+ // Global PINs not implemented
+ throw new CardException("Not implemented.");
+ }
+ }
+
+ int len;
+ if (command.getNe() == 256) {
+ if (currentFile.file.length > 256) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ } else {
+ len = Math.min(command.getNe(), currentFile.file.length - offset);
+ }
+ } else {
+ if (command.getNe() >= currentFile.file.length - offset) {
+ return new ResponseAPDU(new byte[] {(byte) 0x62, (byte) 0x82});
+ } else {
+ len = command.getNe();
+ }
+ }
+
+ byte[] response = new byte[len + 2];
+ System.arraycopy(currentFile.file, offset, response, 0, len);
+ response[len] = (byte) 0x90;
+ response[len + 1] = (byte) 0x00;
+ return new ResponseAPDU(response);
+
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java
new file mode 100644
index 00000000..58216b6b
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java
@@ -0,0 +1,36 @@
+/*
+* 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.acos;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.CardEmul;
+
+
+
+public class A03CardEmul extends ACOSCardEmul {
+
+ public A03CardEmul(A03ApplSIG applSIG, A03ApplDEC applDEC) {
+ applications.add(applSIG);
+ applications.add(applDEC);
+ }
+
+ @Override
+ protected CardChannelEmul newCardChannel(CardEmul cardEmul) {
+ return new A03CardChannelEmul(this);
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java
new file mode 100644
index 00000000..776c0370
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java
@@ -0,0 +1,91 @@
+/*
+* 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.acos;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import at.gv.egiz.smcc.ACOSCard;
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.CardNotSupportedException;
+import at.gv.egiz.smcc.CardTerminalEmul;
+import at.gv.egiz.smcc.LockedException;
+import at.gv.egiz.smcc.NotActivatedException;
+import at.gv.egiz.smcc.PINFormatException;
+import at.gv.egiz.smcc.PINMgmtSignatureCard;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.SignatureCard;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.SignatureCardFactory;
+
+public class A03CardTest extends ACOSCardTest {
+
+ @Override
+ protected SignatureCard createSignatureCard()
+ throws CardNotSupportedException {
+ SignatureCardFactory factory = SignatureCardFactory.getInstance();
+ CardEmul card = new A03CardEmul(new A03ApplSIG(), new A03ApplDEC());
+ SignatureCard signatureCard = factory.createSignatureCard(card,
+ new CardTerminalEmul(card));
+ assertTrue(signatureCard instanceof PINMgmtSignatureCard);
+ return signatureCard;
+ }
+
+ @Override
+ protected int getVersion() {
+ return 1;
+ }
+
+ @Test
+ public void testChangePin() throws CardNotSupportedException,
+ LockedException, NotActivatedException, CancelledException,
+ PINFormatException, SignatureCardException, InterruptedException {
+
+ char[] defaultPin = "123456".toCharArray();
+
+ PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplSIG applSIG = (ACOSApplSIG) card.getApplication(ACOSAppl.AID_SIG);
+ applSIG.setPin(ACOSApplSIG.KID_PIN_SIG, defaultPin);
+ ACOSApplDEC applDEC = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
+ applDEC.setPin(ACOSApplDEC.KID_PIN_DEC, defaultPin);
+ applDEC.setPin(A03ApplDEC.KID_PIN_INF, defaultPin);
+
+ for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
+
+ char[] pin = defaultPin;
+
+ for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) {
+ signatureCard.verifyPIN(pinSpec, new TestPINProvider(pin));
+ char[] newPin = new char[i];
+ Arrays.fill(newPin, '0');
+ signatureCard
+ .changePIN(pinSpec, new TestChangePINProvider(pin, newPin));
+ signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin));
+ pin = newPin;
+ }
+
+ }
+
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplDEC.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplDEC.java
new file mode 100644
index 00000000..e38a8e80
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplDEC.java
@@ -0,0 +1,296 @@
+/*
+* 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.acos;
+
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+
+@SuppressWarnings("restriction")
+public class A04ApplDEC extends ACOSApplDEC {
+
+ private static final byte[] SEC_ENV_INTERNAL_AUTHENTICATE = new byte[] { (byte) 0x84,
+ (byte) 0x01, (byte) 0x88, (byte) 0x80, (byte) 0x01, (byte) 0x01 };
+
+ private static final byte[] SEC_ENV_DECIPHER = new byte[] { (byte) 0x84,
+ (byte) 0x01, (byte) 0x88, (byte) 0x80, (byte) 0x01, (byte) 0x02 };
+
+ private static final RSAPrivateKey SK_CH_EKEY;
+
+ private static final RSAPublicKey PK_CH_EKEY;
+
+ static {
+ try {
+ KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
+ gen.initialize(1536);
+ KeyPair keyPair = gen.generateKeyPair();
+ SK_CH_EKEY = (RSAPrivateKey) keyPair.getPrivate();
+ PK_CH_EKEY = (RSAPublicKey) keyPair.getPublic();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public A04ApplDEC() {
+ this(false);
+ }
+
+ public A04ApplDEC(boolean encrypt) {
+
+ int offset = 0;
+
+ // HEADER 'AIK' + version
+ byte[] header;
+ try {
+ header = "AIK".getBytes("ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ System.arraycopy(header, 0, EF_INFOBOX, offset, header.length);
+ offset += header.length;
+ EF_INFOBOX[offset++] = 1;
+
+ // HEADER identity link
+ EF_INFOBOX[offset++] = (byte) 0x01; // Personenbindung
+ if (encrypt) {
+ EF_INFOBOX[offset++] = (byte) 0x01; // Modifier
+
+ byte[] cipherText;
+ byte[] encKey;
+ try {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
+ SecretKey secretKey = keyGenerator.generateKey();
+
+ byte[] keyBytes = secretKey.getEncoded();
+
+ Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
+ byte[] iv = new byte[8];
+ Arrays.fill(iv, (byte) 0x00);
+ IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
+ cipherText = cipher.doFinal(IDLINK);
+
+ cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, PK_CH_EKEY);
+ encKey = cipher.doFinal(keyBytes);
+
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ }
+
+ int len = encKey.length + cipherText.length + 2;
+
+ EF_INFOBOX[offset++] = (byte) (0xFF & len);
+ EF_INFOBOX[offset++] = (byte) (0xFF & len >> 8);
+
+ EF_INFOBOX[offset++] = (byte) (0xFF & encKey.length);
+ EF_INFOBOX[offset++] = (byte) (0xFF & encKey.length >> 8);
+
+ System.arraycopy(encKey, 0, EF_INFOBOX, offset, encKey.length);
+ offset += encKey.length;
+
+ System.arraycopy(cipherText, 0, EF_INFOBOX, offset, cipherText.length);
+
+ } else {
+ EF_INFOBOX[offset++] = (byte) 0x00; // Modifier
+ EF_INFOBOX[offset++] = (byte) (0xFF & IDLINK.length);
+ EF_INFOBOX[offset++] = (byte) (0xFF & IDLINK.length >> 8);
+ System.arraycopy(IDLINK, 0, EF_INFOBOX, offset, IDLINK.length);
+ offset += IDLINK.length;
+ }
+
+ putFile(new File(FID_EF_INFOBOX, EF_INFOBOX, FCI_EF_INFOBOX));
+ }
+
+ @Override
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel) {
+
+ checkINS(command, 0x22);
+
+ switch (command.getP2()) {
+ case 0xA4:
+ switch (command.getP1()) {
+ case 0x41: {
+ // INTERNAL AUTHENTICATE
+ if (Arrays.equals(SEC_ENV_INTERNAL_AUTHENTICATE, command.getData())) {
+ securityEnv = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x85});
+ }
+ }
+ case 0x81:
+ // EXTERNAL AUTHENTICATE
+ }
+ case 0xB6:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO - COMPUTE DIGITAL SIGNATURE
+ case 0x81:
+ // PSO - VERIFY DGITAL SIGNATURE
+ }
+ case 0xB8:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO � DECIPHER
+ if (Arrays.equals(SEC_ENV_DECIPHER, command.getData())) {
+ securityEnv = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x85});
+ }
+ case 0x81:
+ // PSO � ENCIPHER
+ }
+ default:
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+ @Override
+ public ResponseAPDU cmdPERFORM_SECURITY_OPERATION(CommandAPDU command, CardChannelEmul channel) throws CardException {
+
+ checkINS(command, 0x2A);
+
+ if (command.getP1() == 0x80 && command.getP2() == 0x86) {
+
+ byte[] data = command.getData();
+
+ if (!Arrays.equals(securityEnv, SEC_ENV_DECIPHER)) {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+
+ if (data.length != 193) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ if (pins.get(KID_PIN_DEC).state != PIN.STATE_PIN_VERIFIED) {
+ // Security Status not satisfied
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+
+ byte[] cipherText = Arrays.copyOfRange(data, 1, data.length);
+
+ byte[] plainText;
+ try {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.DECRYPT_MODE, SK_CH_EKEY);
+ plainText = cipher.doFinal(cipherText);
+ } catch (GeneralSecurityException e) {
+ throw new CardException(e);
+ }
+
+ byte[] response = new byte[plainText.length + 2];
+ System.arraycopy(plainText, 0, response, 0, plainText.length);
+ response[plainText.length] = (byte) 0x90;
+ response[plainText.length + 1] = (byte) 0x00;
+
+ return new ResponseAPDU(response);
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00});
+ }
+
+ }
+
+ @Override
+ public ResponseAPDU cmdINTERNAL_AUTHENTICATE(CommandAPDU command, CardChannelEmul channel) throws CardException {
+
+ checkINS(command, 0x88);
+
+ if (command.getP1() == 0x10 && command.getP2() == 0x00) {
+
+ byte[] data = command.getData();
+
+ if (!Arrays.equals(securityEnv, SEC_ENV_INTERNAL_AUTHENTICATE)) {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+
+ 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) 0x14
+ };
+
+ if (data.length != 35 || !Arrays.equals(digestInfo, Arrays.copyOf(data, 15))) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+
+ if (pins.get(KID_PIN_DEC).state != PIN.STATE_PIN_VERIFIED) {
+ // Security Status not satisfied
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+
+ byte[] digest = Arrays.copyOfRange(data, 15, 35);
+
+ byte[] sig;
+ try {
+ Signature signature = Signature.getInstance("RSA");
+ signature.initSign(SK_CH_EKEY);
+ signature.update(digest);
+ sig = signature.sign();
+ } catch (GeneralSecurityException e) {
+ throw new CardException(e);
+ }
+
+ byte[] response = new byte[sig.length + 2];
+ System.arraycopy(sig, 0, response, 0, sig.length);
+ response[sig.length] = (byte) 0x90;
+ response[sig.length + 1] = (byte) 0x00;
+
+ hash = null;
+ pins.get(KID_PIN_DEC).state = PIN.STATE_RESET;
+
+ return new ResponseAPDU(response);
+
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplSIG.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplSIG.java
new file mode 100644
index 00000000..aee6a7f7
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04ApplSIG.java
@@ -0,0 +1,87 @@
+/*
+* 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.acos;
+
+import java.util.Arrays;
+
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.File;
+
+
+@SuppressWarnings("restriction")
+public class A04ApplSIG extends ACOSApplSIG {
+
+ private static byte[] FID_EF_INFO = new byte[] { (byte) 0xd0, (byte) 0x02 };
+
+ private static byte[] FCI_EF_INFO = new byte[] { (byte) 0x6f, (byte) 0x07,
+ (byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x08, (byte) 0x82,
+ (byte) 0x01, (byte) 0x01 };
+
+ private static byte[] EF_INFO = new byte[] { (byte) 0x02, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x90, (byte) 0x00 };
+
+ public A04ApplSIG() {
+ putFile(new File(FID_EF_INFO, EF_INFO, FCI_EF_INFO));
+ }
+
+ @Override
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel) {
+
+ checkINS(command, 0x22);
+
+ switch (command.getP2()) {
+ case 0xA4:
+ switch (command.getP1()) {
+ case 0x41:
+ // INTERNAL AUTHENTICATE
+ case 0x81:
+ // EXTERNAL AUTHENTICATE
+ }
+ case 0xB6:
+ switch (command.getP1()) {
+ case 0x41: {
+ // PSO - COMPUTE DIGITAL SIGNATURE
+ byte[] dst = new byte[] { (byte) 0x84, (byte) 0x01, (byte) 0x88, (byte) 0x80, (byte) 0x01, (byte) 0x14 };
+ if (Arrays.equals(dst, command.getData())) {
+ securityEnv = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+ case 0x81:
+ // PSO - VERIFY DGITAL SIGNATURE
+ }
+ case 0xB8:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO � DECIPHER
+ case 0x81:
+ // PSO � ENCIPHER
+ }
+ default:
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardChannelEmul.java
new file mode 100644
index 00000000..3eaece91
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardChannelEmul.java
@@ -0,0 +1,75 @@
+/*
+* 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.acos;
+
+
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardEmul;
+
+
+@SuppressWarnings("restriction")
+public class A04CardChannelEmul extends ACOSCardChannelEmul {
+
+ public A04CardChannelEmul(CardEmul cardEmul) {
+ super(cardEmul);
+ }
+
+ @Override
+ public ResponseAPDU cmdREAD_BINARY(CommandAPDU command) throws CardException {
+
+ if (command.getINS() != 0xB0) {
+ throw new IllegalArgumentException("INS has to be 0xB0.");
+ }
+
+ if (currentFile == null) {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x86});
+ }
+
+ if ((command.getP1() & 0x80) > 0) {
+ throw new CardException("Not implemented.");
+ }
+
+ int offset = command.getP2() + (command.getP1() << 8);
+ if (offset > currentFile.file.length) {
+ // Wrong length
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ if (command.getNe() == 0) {
+ throw new CardException("Not implemented.");
+ }
+
+ if (command.getNe() == 256 || command.getNe() <= currentFile.file.length - offset) {
+ int len = Math.min(command.getNe(), currentFile.file.length - offset);
+ byte[] response = new byte[len + 2];
+ System.arraycopy(currentFile.file, offset, response, 0, len);
+ response[len] = (byte) 0x90;
+ response[len + 1] = (byte) 0x00;
+ return new ResponseAPDU(response);
+ } else if (command.getNe() >= currentFile.file.length - offset) {
+ return new ResponseAPDU(new byte[] {(byte) 0x62, (byte) 0x82});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java
new file mode 100644
index 00000000..70925aa6
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java
@@ -0,0 +1,37 @@
+/*
+* 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.acos;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.CardEmul;
+
+
+
+public class A04CardEmul extends ACOSCardEmul {
+
+ public A04CardEmul(A04ApplSIG applSIG, A04ApplDEC applDEC) {
+ applications.add(applSIG);
+ applications.add(applDEC);
+ }
+
+ @Override
+ protected CardChannelEmul newCardChannel(CardEmul cardEmul) {
+ return new A04CardChannelEmul(this);
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java
new file mode 100644
index 00000000..d15e80d7
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java
@@ -0,0 +1,143 @@
+/*
+* 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.acos;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import iaik.security.provider.IAIK;
+
+import java.security.Security;
+import java.util.Arrays;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import at.gv.egiz.smcc.ACOSCard;
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.CardNotSupportedException;
+import at.gv.egiz.smcc.CardTerminalEmul;
+import at.gv.egiz.smcc.LockedException;
+import at.gv.egiz.smcc.NotActivatedException;
+import at.gv.egiz.smcc.PINFormatException;
+import at.gv.egiz.smcc.PINMgmtSignatureCard;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.SignatureCard;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.SignatureCardFactory;
+import at.gv.egiz.smcc.CardTest.TestPINProvider;
+
+public class A04CardTest extends ACOSCardTest {
+
+ @Override
+ protected SignatureCard createSignatureCard()
+ throws CardNotSupportedException {
+ SignatureCardFactory factory = SignatureCardFactory.getInstance();
+ CardEmul card = new A04CardEmul(new A04ApplSIG(), new A04ApplDEC());
+ SignatureCard signatureCard = factory.createSignatureCard(card,
+ new CardTerminalEmul(card));
+ assertTrue(signatureCard instanceof PINMgmtSignatureCard);
+ return signatureCard;
+ }
+
+ @Override
+ protected int getVersion() {
+ return 2;
+ }
+
+ @BeforeClass
+ public static void setupClass() {
+ IAIK.addAsProvider();
+ }
+
+ @Test
+ public void testChangePin() throws CardNotSupportedException,
+ LockedException, NotActivatedException, CancelledException,
+ PINFormatException, SignatureCardException, InterruptedException {
+
+ char[] defaultPin = "123456".toCharArray();
+
+ PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplSIG applSIG = (ACOSApplSIG) card.getApplication(ACOSAppl.AID_SIG);
+ applSIG.setPin(ACOSApplSIG.KID_PIN_SIG, defaultPin);
+ ACOSApplDEC applDEC = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
+ applDEC.setPin(ACOSApplDEC.KID_PIN_DEC, defaultPin);
+
+ for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
+
+ char[] pin = defaultPin;
+
+ for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) {
+ char[] newPin = new char[i];
+ Arrays.fill(newPin, '0');
+ signatureCard
+ .changePIN(pinSpec, new TestChangePINProvider(pin, newPin));
+ signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin));
+ pin = newPin;
+ }
+
+ }
+
+ }
+
+ @Test
+ public void testGetInfoboxIdentityLinkEncrypted()
+ throws CardNotSupportedException, SignatureCardException,
+ InterruptedException {
+
+ char[] pin = "0000".toCharArray();
+
+ SignatureCardFactory factory = SignatureCardFactory.getInstance();
+ A04ApplDEC applDEC = new A04ApplDEC(true);
+ applDEC.setPin(A04ApplDEC.KID_PIN_DEC, pin);
+ CardEmul card = new A04CardEmul(new A04ApplSIG(), applDEC);
+ SignatureCard signatureCard = factory.createSignatureCard(card,
+ new CardTerminalEmul(card));
+
+ TestPINProvider pinProvider = new TestPINProvider(pin);
+
+ byte[] idlink = signatureCard.getInfobox("IdentityLink",
+ pinProvider, null);
+ assertNotNull(idlink);
+ assertTrue(Arrays.equals(idlink, A04ApplDEC.IDLINK));
+ assertEquals(1, pinProvider.getProvided());
+
+ }
+
+ @Test
+ public void testGetInfoboxIdentityLink() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ final char[] pin = "0000".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ TestPINProvider pinProvider = new TestPINProvider(pin);
+
+ byte[] idlink = signatureCard.getInfobox("IdentityLink",
+ pinProvider, null);
+ assertNotNull(idlink);
+ assertTrue(Arrays.equals(idlink, A04ApplDEC.IDLINK));
+ assertEquals(0, pinProvider.getProvided());
+
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSAppl.java
new file mode 100644
index 00000000..4c340d61
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSAppl.java
@@ -0,0 +1,79 @@
+/*
+* 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.acos;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.AbstractAppl;
+import at.gv.egiz.smcc.CardAppl;
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public abstract class ACOSAppl extends AbstractAppl implements CardAppl {
+
+ public static byte[] AID_SIG = new byte[] { (byte) 0xA0, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x43 };
+
+ public static byte[] FID_SIG = new byte[] { (byte) 0xDF, (byte) 0x70 };
+
+ public static byte[] AID_DEC = new byte[] { (byte) 0xA0, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x4E };
+
+ public static byte[] FID_DEC = new byte[] { (byte) 0xDF, (byte) 0x71 };
+
+ protected byte[] securityEnv;
+
+ protected byte[] hash;
+
+ @Override
+ public ResponseAPDU cmdINTERNAL_AUTHENTICATE(CommandAPDU command, CardChannelEmul channel) throws CardException {
+ return new ResponseAPDU(new byte[] {(byte) 0x6D, (byte) 0x00});
+ }
+
+ @Override
+ public void leaveApplContext() {
+ Iterator<PIN> pin = pins.values().iterator();
+ while (pin.hasNext()) {
+ pin.next().state = PIN.STATE_RESET;
+ }
+ }
+
+ public void setPin(int kid, char[] value) {
+ try {
+ PIN pin = pins.get(kid);
+ if (pin != null) {
+ if (value == null) {
+ Arrays.fill(pin.pin, (byte) 0x00);
+ pin.state = PIN.STATE_PIN_BLOCKED;
+ } else {
+ int l = pin.pin.length;
+ pin.pin = Arrays.copyOf(new String(value).getBytes("ASCII"), l);
+ }
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java
new file mode 100644
index 00000000..08979536
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java
@@ -0,0 +1,334 @@
+/*
+* 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.acos;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+public abstract class ACOSApplDEC extends ACOSAppl {
+
+ public static final byte[] IDLINK = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x11, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x0c,
+ (byte) 0x26, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f,
+ (byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x7a,
+ (byte) 0x6d, (byte) 0x72, (byte) 0x2f, (byte) 0x70, (byte) 0x65, (byte) 0x72, (byte) 0x73, (byte) 0x62,
+ (byte) 0x32, (byte) 0x30, (byte) 0x34, (byte) 0x2e, (byte) 0x78, (byte) 0x73, (byte) 0x6c, (byte) 0x0c,
+ (byte) 0x29, (byte) 0x73, (byte) 0x7a, (byte) 0x72, (byte) 0x2e, (byte) 0x62, (byte) 0x6d, (byte) 0x69,
+ (byte) 0x2e, (byte) 0x67, (byte) 0x76, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2d, (byte) 0x41,
+ (byte) 0x73, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e,
+ (byte) 0x49, (byte) 0x44, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x36, (byte) 0x33, (byte) 0x35,
+ (byte) 0x36, (byte) 0x33, (byte) 0x36, (byte) 0x36, (byte) 0x37, (byte) 0x39, (byte) 0x39, (byte) 0x39,
+ (byte) 0x31, (byte) 0x39, (byte) 0x0c, (byte) 0x19, (byte) 0x32, (byte) 0x30, (byte) 0x30, (byte) 0x39,
+ (byte) 0x2d, (byte) 0x30, (byte) 0x33, (byte) 0x2d, (byte) 0x30, (byte) 0x36, (byte) 0x54, (byte) 0x31,
+ (byte) 0x36, (byte) 0x3a, (byte) 0x31, (byte) 0x39, (byte) 0x3a, (byte) 0x32, (byte) 0x36, (byte) 0x2b,
+ (byte) 0x30, (byte) 0x31, (byte) 0x3a, (byte) 0x30, (byte) 0x30, (byte) 0xa0, (byte) 0x42, (byte) 0x30,
+ (byte) 0x40, (byte) 0x0c, (byte) 0x18, (byte) 0x45, (byte) 0x68, (byte) 0x42, (byte) 0x53, (byte) 0x36,
+ (byte) 0x54, (byte) 0x6f, (byte) 0x31, (byte) 0x49, (byte) 0x6c, (byte) 0x54, (byte) 0x4b, (byte) 0x4f,
+ (byte) 0x4a, (byte) 0x45, (byte) 0x39, (byte) 0x75, (byte) 0x62, (byte) 0x74, (byte) 0x48, (byte) 0x69,
+ (byte) 0x51, (byte) 0x3d, (byte) 0x3d, (byte) 0x0c, (byte) 0x0a, (byte) 0x58, (byte) 0x58, (byte) 0x58,
+ (byte) 0xc5, (byte) 0x90, (byte) 0x7a, (byte) 0x67, (byte) 0xc3, (byte) 0xbc, (byte) 0x72, (byte) 0x0c,
+ (byte) 0x0c, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x54, (byte) 0xc3, (byte) 0xbc, (byte) 0x7a,
+ (byte) 0x65, (byte) 0x6b, (byte) 0xc3, (byte) 0xa7, (byte) 0x69, (byte) 0x0c, (byte) 0x0a, (byte) 0x31,
+ (byte) 0x39, (byte) 0x37, (byte) 0x33, (byte) 0x2d, (byte) 0x30, (byte) 0x36, (byte) 0x2d, (byte) 0x30,
+ (byte) 0x34, (byte) 0x30, (byte) 0x0a, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x00,
+ (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x82, (byte) 0x01,
+ (byte) 0x01, (byte) 0x00, (byte) 0x9f, (byte) 0xa5, (byte) 0x68, (byte) 0xa9, (byte) 0x14, (byte) 0x4c,
+ (byte) 0xa4, (byte) 0x5d, (byte) 0x9d, (byte) 0x09, (byte) 0x99, (byte) 0x2e, (byte) 0xe7, (byte) 0x45,
+ (byte) 0x2e, (byte) 0x42, (byte) 0x49, (byte) 0x02, (byte) 0x16, (byte) 0xd9, (byte) 0xcb, (byte) 0x90,
+ (byte) 0x43, (byte) 0x27, (byte) 0x03, (byte) 0x43, (byte) 0x6d, (byte) 0xb4, (byte) 0x8c, (byte) 0xdc,
+ (byte) 0x1c, (byte) 0x77, (byte) 0xd4, (byte) 0x2e, (byte) 0xa1, (byte) 0x40, (byte) 0xe7, (byte) 0xe0,
+ (byte) 0x03, (byte) 0x60, (byte) 0x15, (byte) 0xf7, (byte) 0xdb, (byte) 0x03, (byte) 0x5e, (byte) 0xca,
+ (byte) 0xe4, (byte) 0x35, (byte) 0xba, (byte) 0x2b, (byte) 0xfd, (byte) 0xe6, (byte) 0xb8, (byte) 0xd8,
+ (byte) 0xb7, (byte) 0x2a, (byte) 0x80, (byte) 0xdd, (byte) 0x38, (byte) 0xe0, (byte) 0x8a, (byte) 0x69,
+ (byte) 0xad, (byte) 0x67, (byte) 0x60, (byte) 0x65, (byte) 0x42, (byte) 0xc9, (byte) 0x41, (byte) 0x60,
+ (byte) 0x94, (byte) 0xde, (byte) 0x84, (byte) 0x54, (byte) 0xad, (byte) 0xb3, (byte) 0xf4, (byte) 0xf7,
+ (byte) 0x44, (byte) 0xd5, (byte) 0xf3, (byte) 0xd3, (byte) 0xb6, (byte) 0x87, (byte) 0x8a, (byte) 0x22,
+ (byte) 0x38, (byte) 0x00, (byte) 0xcb, (byte) 0xa4, (byte) 0x4f, (byte) 0x96, (byte) 0xc2, (byte) 0x28,
+ (byte) 0xc2, (byte) 0x8d, (byte) 0x91, (byte) 0x95, (byte) 0xb4, (byte) 0xea, (byte) 0x00, (byte) 0x59,
+ (byte) 0x2e, (byte) 0xec, (byte) 0x78, (byte) 0xd8, (byte) 0x0f, (byte) 0x26, (byte) 0x04, (byte) 0xee,
+ (byte) 0xed, (byte) 0x13, (byte) 0xbf, (byte) 0x81, (byte) 0x68, (byte) 0x81, (byte) 0x43, (byte) 0xbe,
+ (byte) 0x15, (byte) 0x0e, (byte) 0xba, (byte) 0xf9, (byte) 0x6a, (byte) 0x18, (byte) 0xeb, (byte) 0x95,
+ (byte) 0xad, (byte) 0xb4, (byte) 0x0f, (byte) 0x3c, (byte) 0x94, (byte) 0x63, (byte) 0x32, (byte) 0x81,
+ (byte) 0x90, (byte) 0xcf, (byte) 0x3f, (byte) 0x95, (byte) 0xff, (byte) 0x8d, (byte) 0x86, (byte) 0xed,
+ (byte) 0xe4, (byte) 0x75, (byte) 0xd5, (byte) 0x09, (byte) 0x32, (byte) 0x17, (byte) 0x38, (byte) 0xb2,
+ (byte) 0x68, (byte) 0x35, (byte) 0x49, (byte) 0x8c, (byte) 0xa6, (byte) 0xd0, (byte) 0x3e, (byte) 0xde,
+ (byte) 0x6e, (byte) 0x47, (byte) 0x68, (byte) 0xbf, (byte) 0x98, (byte) 0x33, (byte) 0xae, (byte) 0x59,
+ (byte) 0x9f, (byte) 0xe0, (byte) 0x19, (byte) 0x9b, (byte) 0x5b, (byte) 0x1b, (byte) 0x8f, (byte) 0x74,
+ (byte) 0xd2, (byte) 0x9c, (byte) 0x01, (byte) 0x1a, (byte) 0xdf, (byte) 0xaf, (byte) 0xf8, (byte) 0x96,
+ (byte) 0x91, (byte) 0xcb, (byte) 0xf8, (byte) 0xbf, (byte) 0x06, (byte) 0xc7, (byte) 0xd5, (byte) 0x17,
+ (byte) 0x95, (byte) 0xef, (byte) 0xc5, (byte) 0x97, (byte) 0x37, (byte) 0x1b, (byte) 0xb0, (byte) 0xa1,
+ (byte) 0x4f, (byte) 0x9f, (byte) 0x01, (byte) 0x82, (byte) 0x90, (byte) 0x4a, (byte) 0x6a, (byte) 0x04,
+ (byte) 0xdb, (byte) 0x31, (byte) 0x1a, (byte) 0x58, (byte) 0xeb, (byte) 0xcd, (byte) 0x68, (byte) 0xe3,
+ (byte) 0x68, (byte) 0x0b, (byte) 0xa0, (byte) 0x11, (byte) 0x44, (byte) 0x08, (byte) 0xa0, (byte) 0x5c,
+ (byte) 0xfc, (byte) 0x61, (byte) 0x15, (byte) 0x1f, (byte) 0xbb, (byte) 0x22, (byte) 0x87, (byte) 0x18,
+ (byte) 0xa3, (byte) 0x07, (byte) 0x9b, (byte) 0x0d, (byte) 0x13, (byte) 0x7c, (byte) 0xff, (byte) 0x30,
+ (byte) 0xcf, (byte) 0xf3, (byte) 0xaf, (byte) 0xe4, (byte) 0x45, (byte) 0x05, (byte) 0xa0, (byte) 0x8e,
+ (byte) 0x6b, (byte) 0xef, (byte) 0x70, (byte) 0xf5, (byte) 0x4b, (byte) 0x68, (byte) 0x8f, (byte) 0x61,
+ (byte) 0xd6, (byte) 0xf5, (byte) 0xa0, (byte) 0x17, (byte) 0x03, (byte) 0x15, (byte) 0x00, (byte) 0x8e,
+ (byte) 0xa8, (byte) 0xdf, (byte) 0xa9, (byte) 0x77, (byte) 0xfd, (byte) 0x9b, (byte) 0x4b, (byte) 0x91,
+ (byte) 0x89, (byte) 0x34, (byte) 0x84, (byte) 0xf3, (byte) 0x24, (byte) 0xb2, (byte) 0x5a, (byte) 0x39,
+ (byte) 0xa9, (byte) 0xf2, (byte) 0x17, (byte) 0xa1, (byte) 0x17, (byte) 0x03, (byte) 0x15, (byte) 0x00,
+ (byte) 0xdb, (byte) 0xa2, (byte) 0xfd, (byte) 0xa4, (byte) 0xe7, (byte) 0x65, (byte) 0x2e, (byte) 0x7e,
+ (byte) 0xb0, (byte) 0xc8, (byte) 0xfa, (byte) 0x4d, (byte) 0x13, (byte) 0x28, (byte) 0xdf, (byte) 0xb1,
+ (byte) 0x58, (byte) 0x3b, (byte) 0x9e, (byte) 0x29, (byte) 0xa2, (byte) 0x17, (byte) 0x03, (byte) 0x15,
+ (byte) 0x00, (byte) 0x68, (byte) 0xa0, (byte) 0x17, (byte) 0x18, (byte) 0xb7, (byte) 0xb3, (byte) 0xc3,
+ (byte) 0x60, (byte) 0x77, (byte) 0x82, (byte) 0x8d, (byte) 0xf1, (byte) 0x5e, (byte) 0x10, (byte) 0xc3,
+ (byte) 0x2d, (byte) 0x78, (byte) 0x2c, (byte) 0x11, (byte) 0x0b
+ };
+ private static byte[] FCI = new byte[] { (byte) 0x6f, (byte) 0x1a, (byte) 0x84,
+ (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00, (byte) 0x01,
+ (byte) 0x18, (byte) 0x4e, (byte) 0x43, (byte) 0x85, (byte) 0x0f,
+ (byte) 0x50, (byte) 0x0d, (byte) 0x44, (byte) 0x49, (byte) 0x47,
+ (byte) 0x53, (byte) 0x49, (byte) 0x47, (byte) 0x20, (byte) 0x43,
+ (byte) 0x43, (byte) 0x20, (byte) 0x45, (byte) 0x4e, (byte) 0x43 };
+ protected static byte[] FID_EF_C_CH_EKEY = new byte[] { (byte) 0xc0, (byte) 0x01 };
+ protected static byte[] FCI_EF_C_CH_EKEY = new byte[] { (byte) 0x6f, (byte) 0x07,
+ (byte) 0x80, (byte) 0x02, (byte) 0x07, (byte) 0xd0, (byte) 0x82,
+ (byte) 0x01, (byte) 0x01};
+ protected static byte[] C_CH_EKEY = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x05, (byte) 0x7f, (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x67,
+ (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x03, (byte) 0x02,
+ (byte) 0x05, (byte) 0x51, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xa1, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
+ (byte) 0x54, (byte) 0x31, (byte) 0x48, (byte) 0x30, (byte) 0x46, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x3f, (byte) 0x41, (byte) 0x2d, (byte) 0x54, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x47, (byte) 0x65, (byte) 0x73, (byte) 0x2e,
+ (byte) 0x20, (byte) 0x66, (byte) 0x2e, (byte) 0x20, (byte) 0x53, (byte) 0x69, (byte) 0x63, (byte) 0x68,
+ (byte) 0x65, (byte) 0x72, (byte) 0x68, (byte) 0x65, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x73,
+ (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x6d, (byte) 0x65, (byte) 0x20, (byte) 0x69,
+ (byte) 0x6d, (byte) 0x20, (byte) 0x65, (byte) 0x6c, (byte) 0x65, (byte) 0x6b, (byte) 0x74, (byte) 0x72,
+ (byte) 0x2e, (byte) 0x20, (byte) 0x44, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x6e, (byte) 0x76,
+ (byte) 0x65, (byte) 0x72, (byte) 0x6b, (byte) 0x65, (byte) 0x68, (byte) 0x72, (byte) 0x20, (byte) 0x47,
+ (byte) 0x6d, (byte) 0x62, (byte) 0x48, (byte) 0x31, (byte) 0x23, (byte) 0x30, (byte) 0x21, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x1a, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65,
+ (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2d, (byte) 0x45, (byte) 0x6e, (byte) 0x63, (byte) 0x2d, (byte) 0x30, (byte) 0x32,
+ (byte) 0x31, (byte) 0x23, (byte) 0x30, (byte) 0x21, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x03, (byte) 0x0c, (byte) 0x1a, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67,
+ (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75,
+ (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x45,
+ (byte) 0x6e, (byte) 0x63, (byte) 0x2d, (byte) 0x30, (byte) 0x32, (byte) 0x30, (byte) 0x1e, (byte) 0x17,
+ (byte) 0x0d, (byte) 0x30, (byte) 0x39, (byte) 0x30, (byte) 0x31, (byte) 0x31, (byte) 0x33, (byte) 0x30,
+ (byte) 0x39, (byte) 0x34, (byte) 0x35, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x17, (byte) 0x0d,
+ (byte) 0x31, (byte) 0x32, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x31, (byte) 0x30, (byte) 0x39,
+ (byte) 0x34, (byte) 0x35, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x70, (byte) 0x31,
+ (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+ (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x54, (byte) 0x31, (byte) 0x1f, (byte) 0x30, (byte) 0x1d,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x16, (byte) 0x58,
+ (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x6f, (byte) 0x20, (byte) 0x58,
+ (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x61, (byte) 0x6b, (byte) 0x72,
+ (byte) 0x69, (byte) 0x6e, (byte) 0x67, (byte) 0x65, (byte) 0x72, (byte) 0x31, (byte) 0x17, (byte) 0x30,
+ (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x04, (byte) 0x0c, (byte) 0x0e,
+ (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x61, (byte) 0x6b,
+ (byte) 0x72, (byte) 0x69, (byte) 0x6e, (byte) 0x67, (byte) 0x65, (byte) 0x72, (byte) 0x31, (byte) 0x10,
+ (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x2a, (byte) 0x0c,
+ (byte) 0x07, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x6f,
+ (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x05, (byte) 0x13, (byte) 0x0c, (byte) 0x39, (byte) 0x37, (byte) 0x30, (byte) 0x30, (byte) 0x31,
+ (byte) 0x36, (byte) 0x38, (byte) 0x36, (byte) 0x36, (byte) 0x31, (byte) 0x37, (byte) 0x34, (byte) 0x30,
+ (byte) 0x81, (byte) 0xdf, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+ (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0xcd, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xc9,
+ (byte) 0x02, (byte) 0x81, (byte) 0xc1, (byte) 0x00, (byte) 0xae, (byte) 0xe6, (byte) 0x07, (byte) 0x1d,
+ (byte) 0xb9, (byte) 0x56, (byte) 0x0a, (byte) 0x98, (byte) 0x1a, (byte) 0xde, (byte) 0x52, (byte) 0xf2,
+ (byte) 0x77, (byte) 0xdc, (byte) 0x5e, (byte) 0x76, (byte) 0x7f, (byte) 0xe5, (byte) 0xc1, (byte) 0x79,
+ (byte) 0xb9, (byte) 0x51, (byte) 0x97, (byte) 0x08, (byte) 0x20, (byte) 0x4e, (byte) 0xa6, (byte) 0xa3,
+ (byte) 0xab, (byte) 0xdf, (byte) 0x49, (byte) 0x21, (byte) 0x2b, (byte) 0x65, (byte) 0x4f, (byte) 0x7c,
+ (byte) 0x26, (byte) 0xe8, (byte) 0xb9, (byte) 0x47, (byte) 0xdf, (byte) 0x03, (byte) 0x0f, (byte) 0xf7,
+ (byte) 0x4e, (byte) 0xf4, (byte) 0x47, (byte) 0x3d, (byte) 0x32, (byte) 0x61, (byte) 0x05, (byte) 0x33,
+ (byte) 0x0f, (byte) 0xdc, (byte) 0x97, (byte) 0x3e, (byte) 0xbf, (byte) 0x9b, (byte) 0xf2, (byte) 0xf8,
+ (byte) 0xb3, (byte) 0xe2, (byte) 0xc4, (byte) 0x4d, (byte) 0xe0, (byte) 0x48, (byte) 0x6a, (byte) 0x1b,
+ (byte) 0xd2, (byte) 0xfe, (byte) 0xfa, (byte) 0xee, (byte) 0x24, (byte) 0x08, (byte) 0xdc, (byte) 0x60,
+ (byte) 0x2a, (byte) 0x78, (byte) 0x6c, (byte) 0x1d, (byte) 0xd3, (byte) 0x74, (byte) 0x43, (byte) 0x1f,
+ (byte) 0x1f, (byte) 0x4e, (byte) 0xd2, (byte) 0x0f, (byte) 0x89, (byte) 0x3c, (byte) 0xe3, (byte) 0x1e,
+ (byte) 0xfa, (byte) 0x31, (byte) 0x5a, (byte) 0xc2, (byte) 0x04, (byte) 0x24, (byte) 0xd1, (byte) 0xe5,
+ (byte) 0x51, (byte) 0xc4, (byte) 0x94, (byte) 0x26, (byte) 0xd1, (byte) 0x32, (byte) 0x1e, (byte) 0xdf,
+ (byte) 0x64, (byte) 0xaa, (byte) 0xaf, (byte) 0x2c, (byte) 0x85, (byte) 0x25, (byte) 0x88, (byte) 0x8f,
+ (byte) 0x80, (byte) 0xe4, (byte) 0x05, (byte) 0x74, (byte) 0xd5, (byte) 0xda, (byte) 0x69, (byte) 0x88,
+ (byte) 0x4a, (byte) 0x0c, (byte) 0x6a, (byte) 0x85, (byte) 0x5f, (byte) 0x67, (byte) 0x51, (byte) 0x6c,
+ (byte) 0x5c, (byte) 0x1c, (byte) 0x41, (byte) 0x88, (byte) 0x4c, (byte) 0xad, (byte) 0x83, (byte) 0xc9,
+ (byte) 0x10, (byte) 0x97, (byte) 0x45, (byte) 0x00, (byte) 0x3f, (byte) 0xbd, (byte) 0x1d, (byte) 0x2f,
+ (byte) 0x28, (byte) 0x2e, (byte) 0x78, (byte) 0x97, (byte) 0x05, (byte) 0xa5, (byte) 0x41, (byte) 0x42,
+ (byte) 0x37, (byte) 0x08, (byte) 0x60, (byte) 0x0b, (byte) 0x66, (byte) 0xb1, (byte) 0xb8, (byte) 0xdd,
+ (byte) 0x98, (byte) 0x03, (byte) 0x03, (byte) 0x33, (byte) 0xc9, (byte) 0x15, (byte) 0xf7, (byte) 0x5b,
+ (byte) 0x35, (byte) 0xa5, (byte) 0xaa, (byte) 0x7a, (byte) 0x5e, (byte) 0xe9, (byte) 0xa7, (byte) 0x60,
+ (byte) 0xba, (byte) 0xd8, (byte) 0x0d, (byte) 0x6d, (byte) 0xb3, (byte) 0x85, (byte) 0x70, (byte) 0x0e,
+ (byte) 0x38, (byte) 0x6f, (byte) 0xf0, (byte) 0xfd, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00,
+ (byte) 0x01, (byte) 0xa3, (byte) 0x82, (byte) 0x02, (byte) 0x32, (byte) 0x30, (byte) 0x82, (byte) 0x02,
+ (byte) 0x2e, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23,
+ (byte) 0x04, (byte) 0x0c, (byte) 0x30, (byte) 0x0a, (byte) 0x80, (byte) 0x08, (byte) 0x4b, (byte) 0x5d,
+ (byte) 0x02, (byte) 0x5c, (byte) 0x6d, (byte) 0x58, (byte) 0x24, (byte) 0x67, (byte) 0x30, (byte) 0x81,
+ (byte) 0x84, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x07, (byte) 0x01, (byte) 0x01, (byte) 0x04, (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x30,
+ (byte) 0x2c, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x07, (byte) 0x30, (byte) 0x01, (byte) 0x86, (byte) 0x20, (byte) 0x68, (byte) 0x74, (byte) 0x74,
+ (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x6f, (byte) 0x63, (byte) 0x73, (byte) 0x70,
+ (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74,
+ (byte) 0x2f, (byte) 0x6f, (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x30, (byte) 0x46, (byte) 0x06,
+ (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30,
+ (byte) 0x02, (byte) 0x86, (byte) 0x3a, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a,
+ (byte) 0x2f, (byte) 0x2f, (byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74,
+ (byte) 0x2f, (byte) 0x63, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x73, (byte) 0x2f, (byte) 0x61,
+ (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72,
+ (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x45, (byte) 0x6e, (byte) 0x63, (byte) 0x2d, (byte) 0x30,
+ (byte) 0x32, (byte) 0x2e, (byte) 0x63, (byte) 0x72, (byte) 0x74, (byte) 0x30, (byte) 0x81, (byte) 0x93,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x20, (byte) 0x04, (byte) 0x81, (byte) 0x8b,
+ (byte) 0x30, (byte) 0x81, (byte) 0x88, (byte) 0x30, (byte) 0x81, (byte) 0x85, (byte) 0x06, (byte) 0x06,
+ (byte) 0x2a, (byte) 0x28, (byte) 0x00, (byte) 0x11, (byte) 0x01, (byte) 0x03, (byte) 0x30, (byte) 0x7b,
+ (byte) 0x30, (byte) 0x3d, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05,
+ (byte) 0x05, (byte) 0x07, (byte) 0x02, (byte) 0x01, (byte) 0x16, (byte) 0x31, (byte) 0x68, (byte) 0x74,
+ (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x77, (byte) 0x77, (byte) 0x77,
+ (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x64, (byte) 0x6f, (byte) 0x63, (byte) 0x73,
+ (byte) 0x2f, (byte) 0x63, (byte) 0x70, (byte) 0x2f, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69,
+ (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x70, (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69,
+ (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x30,
+ (byte) 0x3a, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x07, (byte) 0x02, (byte) 0x02, (byte) 0x30, (byte) 0x2e, (byte) 0x1a, (byte) 0x2c, (byte) 0x44,
+ (byte) 0x69, (byte) 0x65, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x20, (byte) 0x5a, (byte) 0x65,
+ (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x6b, (byte) 0x61, (byte) 0x74,
+ (byte) 0x20, (byte) 0x64, (byte) 0x69, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x20, (byte) 0x6e,
+ (byte) 0x75, (byte) 0x72, (byte) 0x20, (byte) 0x7a, (byte) 0x75, (byte) 0x20, (byte) 0x54, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x7a, (byte) 0x77, (byte) 0x65, (byte) 0x63, (byte) 0x6b, (byte) 0x65,
+ (byte) 0x6e, (byte) 0x20, (byte) 0x21, (byte) 0x30, (byte) 0x81, (byte) 0xa4, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1d, (byte) 0x1f, (byte) 0x04, (byte) 0x81, (byte) 0x9c, (byte) 0x30, (byte) 0x81,
+ (byte) 0x99, (byte) 0x30, (byte) 0x81, (byte) 0x96, (byte) 0xa0, (byte) 0x81, (byte) 0x93, (byte) 0xa0,
+ (byte) 0x81, (byte) 0x90, (byte) 0x86, (byte) 0x81, (byte) 0x8d, (byte) 0x6c, (byte) 0x64, (byte) 0x61,
+ (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x6c, (byte) 0x64, (byte) 0x61, (byte) 0x70,
+ (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74,
+ (byte) 0x2f, (byte) 0x6f, (byte) 0x75, (byte) 0x3d, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69,
+ (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69,
+ (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d,
+ (byte) 0x45, (byte) 0x6e, (byte) 0x63, (byte) 0x2d, (byte) 0x30, (byte) 0x32, (byte) 0x2c, (byte) 0x6f,
+ (byte) 0x3d, (byte) 0x41, (byte) 0x2d, (byte) 0x54, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2c, (byte) 0x63, (byte) 0x3d, (byte) 0x41, (byte) 0x54, (byte) 0x3f, (byte) 0x63, (byte) 0x65,
+ (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61, (byte) 0x74,
+ (byte) 0x65, (byte) 0x72, (byte) 0x65, (byte) 0x76, (byte) 0x6f, (byte) 0x63, (byte) 0x61, (byte) 0x74,
+ (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x6c, (byte) 0x69, (byte) 0x73, (byte) 0x74, (byte) 0x3f,
+ (byte) 0x62, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x3f, (byte) 0x6f, (byte) 0x62, (byte) 0x6a,
+ (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73,
+ (byte) 0x3d, (byte) 0x65, (byte) 0x69, (byte) 0x64, (byte) 0x43, (byte) 0x65, (byte) 0x72, (byte) 0x74,
+ (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f,
+ (byte) 0x6e, (byte) 0x41, (byte) 0x75, (byte) 0x74, (byte) 0x68, (byte) 0x6f, (byte) 0x72, (byte) 0x69,
+ (byte) 0x74, (byte) 0x79, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
+ (byte) 0x0e, (byte) 0x04, (byte) 0x0a, (byte) 0x04, (byte) 0x08, (byte) 0x4a, (byte) 0x24, (byte) 0x43,
+ (byte) 0xc0, (byte) 0x85, (byte) 0x2a, (byte) 0xb4, (byte) 0x51, (byte) 0x30, (byte) 0x0e, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x04,
+ (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x04, (byte) 0xb0, (byte) 0x30, (byte) 0x25, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x11, (byte) 0x04, (byte) 0x1e, (byte) 0x30, (byte) 0x1c,
+ (byte) 0x81, (byte) 0x1a, (byte) 0x74, (byte) 0x68, (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x73,
+ (byte) 0x2e, (byte) 0x72, (byte) 0x6f, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x6c, (byte) 0x65,
+ (byte) 0x72, (byte) 0x40, (byte) 0x65, (byte) 0x67, (byte) 0x69, (byte) 0x7a, (byte) 0x2e, (byte) 0x67,
+ (byte) 0x76, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30,
+ (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7,
+ (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82,
+ (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x4a, (byte) 0x36, (byte) 0x02, (byte) 0xb3, (byte) 0xab,
+ (byte) 0x02, (byte) 0xe9, (byte) 0xe1, (byte) 0xaf, (byte) 0x3f, (byte) 0xd5, (byte) 0xcd, (byte) 0x3d,
+ (byte) 0x51, (byte) 0x08, (byte) 0xb8, (byte) 0x73, (byte) 0x23, (byte) 0x68, (byte) 0x0c, (byte) 0x22,
+ (byte) 0x32, (byte) 0xcd, (byte) 0xbe, (byte) 0xc8, (byte) 0x77, (byte) 0xbc, (byte) 0x47, (byte) 0x37,
+ (byte) 0xdd, (byte) 0x89, (byte) 0x7c, (byte) 0x22, (byte) 0x24, (byte) 0x2f, (byte) 0x23, (byte) 0xea,
+ (byte) 0x3e, (byte) 0xc2, (byte) 0xf4, (byte) 0x59, (byte) 0x78, (byte) 0xa6, (byte) 0xbe, (byte) 0xcd,
+ (byte) 0x71, (byte) 0xaa, (byte) 0xb5, (byte) 0xbc, (byte) 0xe3, (byte) 0xbc, (byte) 0x3f, (byte) 0xf1,
+ (byte) 0xfa, (byte) 0x1a, (byte) 0x43, (byte) 0x2b, (byte) 0x91, (byte) 0x35, (byte) 0x67, (byte) 0xa5,
+ (byte) 0x62, (byte) 0x9d, (byte) 0x55, (byte) 0x85, (byte) 0xe0, (byte) 0x3f, (byte) 0xed, (byte) 0x00,
+ (byte) 0x67, (byte) 0x80, (byte) 0x6a, (byte) 0xfb, (byte) 0x46, (byte) 0x8a, (byte) 0xed, (byte) 0x48,
+ (byte) 0x03, (byte) 0xe7, (byte) 0x9d, (byte) 0x5c, (byte) 0xac, (byte) 0xdf, (byte) 0xec, (byte) 0x2d,
+ (byte) 0x53, (byte) 0x8b, (byte) 0x01, (byte) 0xdb, (byte) 0x14, (byte) 0x91, (byte) 0x21, (byte) 0xaf,
+ (byte) 0xa7, (byte) 0x91, (byte) 0x69, (byte) 0x7e, (byte) 0x97, (byte) 0x68, (byte) 0xcc, (byte) 0x2a,
+ (byte) 0x06, (byte) 0x1a, (byte) 0xbc, (byte) 0x53, (byte) 0x35, (byte) 0xde, (byte) 0xd7, (byte) 0x62,
+ (byte) 0x12, (byte) 0xbd, (byte) 0x54, (byte) 0xb5, (byte) 0x4c, (byte) 0x3c, (byte) 0xaf, (byte) 0x55,
+ (byte) 0xa4, (byte) 0x5b, (byte) 0x28, (byte) 0x61, (byte) 0x68, (byte) 0x03, (byte) 0xc6, (byte) 0x72,
+ (byte) 0xc0, (byte) 0xa2, (byte) 0x3f, (byte) 0x84, (byte) 0x02, (byte) 0xf8, (byte) 0x3d, (byte) 0x70,
+ (byte) 0x3f, (byte) 0xde, (byte) 0x9d, (byte) 0x6a, (byte) 0x71, (byte) 0x16, (byte) 0x87, (byte) 0x9d,
+ (byte) 0x93, (byte) 0x3d, (byte) 0x46, (byte) 0x41, (byte) 0xa9, (byte) 0x6a, (byte) 0xca, (byte) 0x87,
+ (byte) 0xd4, (byte) 0xd1, (byte) 0x3f, (byte) 0x1d, (byte) 0x6e, (byte) 0x6a, (byte) 0xbf, (byte) 0x02,
+ (byte) 0x9b, (byte) 0xfb, (byte) 0x4a, (byte) 0x47, (byte) 0xe0, (byte) 0x20, (byte) 0x4a, (byte) 0x2d,
+ (byte) 0x5a, (byte) 0x0c, (byte) 0x6b, (byte) 0x25, (byte) 0xd6, (byte) 0x2d, (byte) 0xd4, (byte) 0x53,
+ (byte) 0x08, (byte) 0x41, (byte) 0xa9, (byte) 0x16, (byte) 0xa2, (byte) 0xa0, (byte) 0xef, (byte) 0x13,
+ (byte) 0xa8, (byte) 0xec, (byte) 0x7e, (byte) 0x99, (byte) 0x15, (byte) 0xf9, (byte) 0x1a, (byte) 0x18,
+ (byte) 0x5e, (byte) 0x75, (byte) 0xc7, (byte) 0x5d, (byte) 0x40, (byte) 0xd4, (byte) 0x84, (byte) 0x4a,
+ (byte) 0xd2, (byte) 0xf7, (byte) 0x7c, (byte) 0x65, (byte) 0x12, (byte) 0xc7, (byte) 0xae, (byte) 0xbc,
+ (byte) 0x9d, (byte) 0x3e, (byte) 0xce, (byte) 0x42, (byte) 0xfe, (byte) 0xe4, (byte) 0x98, (byte) 0x10,
+ (byte) 0x63, (byte) 0x0d, (byte) 0xaa, (byte) 0x2d, (byte) 0x73, (byte) 0x7d, (byte) 0x46, (byte) 0x19,
+ (byte) 0xca, (byte) 0x78, (byte) 0x94, (byte) 0xe5, (byte) 0x11, (byte) 0x83, (byte) 0x87, (byte) 0xb2,
+ (byte) 0xf7, (byte) 0x59, (byte) 0x90, (byte) 0x47, (byte) 0x86, (byte) 0x57, (byte) 0xcf, (byte) 0xc7,
+ (byte) 0x7b, (byte) 0x8f, (byte) 0xac, (byte) 0x20, (byte) 0xbd, (byte) 0x46, (byte) 0xea, (byte) 0xa2,
+ (byte) 0x10, (byte) 0xe1, (byte) 0x72, (byte) 0x3e, (byte) 0xe3, (byte) 0x72, (byte) 0x20, (byte) 0x24,
+ (byte) 0xa5, (byte) 0x2f, (byte) 0xc5
+ };
+ protected static final int KID_PIN_DEC = 0x81;
+
+ protected static byte[] FID_EF_INFOBOX = new byte[] { (byte) 0xc0, (byte) 0x02 };
+ protected static byte[] FCI_EF_INFOBOX = new byte[] { (byte) 0x6f, (byte) 0x07,
+ (byte) 0x80, (byte) 0x02, (byte) 0x05, (byte) 0xdc, (byte) 0x82,
+ (byte) 0x01, (byte) 0x01};
+
+ protected byte[] EF_INFOBOX = new byte[1500];
+
+ protected byte[] EF_C_CH_EKEY = new byte[2000];
+
+ public ACOSApplDEC() {
+ System.arraycopy(C_CH_EKEY, 0, EF_C_CH_EKEY, 0, C_CH_EKEY.length);
+ putFile(new File(FID_EF_C_CH_EKEY, EF_C_CH_EKEY, FCI_EF_C_CH_EKEY));
+ try {
+ pins.put(KID_PIN_DEC, new PIN("1234\0\0\0\0".getBytes("ASCII"), KID_PIN_DEC, 10));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public byte[] getAID() {
+ return AID_DEC;
+ }
+
+ @Override
+ public byte[] getFID() {
+ return FID_DEC;
+ }
+
+ @Override
+ public byte[] getFCI() {
+ return FCI;
+ }
+
+ public void clearInfobox() {
+ Arrays.fill(EF_INFOBOX, (byte) 0x00);
+ }
+
+ public void setInfoboxHeader(byte b) {
+ EF_INFOBOX[0] = b;
+ }
+
+ public void clearCert() {
+ Arrays.fill(EF_C_CH_EKEY, (byte) 0x00);
+ }
+
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java
new file mode 100644
index 00000000..e476b434
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java
@@ -0,0 +1,302 @@
+/*
+* 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.acos;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public abstract class ACOSApplSIG extends ACOSAppl {
+
+ private static byte[] FCI = new byte[] { (byte) 0x6f, (byte) 0x1a,
+ (byte) 0x84, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00,
+ (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x43, (byte) 0x85,
+ (byte) 0x0f, (byte) 0x50, (byte) 0x0d, (byte) 0x44, (byte) 0x49,
+ (byte) 0x47, (byte) 0x53, (byte) 0x49, (byte) 0x47, (byte) 0x20,
+ (byte) 0x43, (byte) 0x43, (byte) 0x20, (byte) 0x45, (byte) 0x43,
+ (byte) 0x43 };
+ protected static byte[] FID_EF_C_CH_DS = new byte[] { (byte) 0xc0, (byte) 0x02 };
+ protected static byte[] FCI_EF_C_CH_DS = new byte[] { (byte) 0x6f, (byte) 0x07,
+ (byte) 0x80, (byte) 0x02, (byte) 0x07, (byte) 0xd0, (byte) 0x82,
+ (byte) 0x01, (byte) 0x01 };
+ protected static byte[] C_CH_DS = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x05, (byte) 0x2b, (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x13,
+ (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x03, (byte) 0x02,
+ (byte) 0x05, (byte) 0x52, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xa1, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
+ (byte) 0x54, (byte) 0x31, (byte) 0x48, (byte) 0x30, (byte) 0x46, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x3f, (byte) 0x41, (byte) 0x2d, (byte) 0x54, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x47, (byte) 0x65, (byte) 0x73, (byte) 0x2e,
+ (byte) 0x20, (byte) 0x66, (byte) 0x2e, (byte) 0x20, (byte) 0x53, (byte) 0x69, (byte) 0x63, (byte) 0x68,
+ (byte) 0x65, (byte) 0x72, (byte) 0x68, (byte) 0x65, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x73,
+ (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x6d, (byte) 0x65, (byte) 0x20, (byte) 0x69,
+ (byte) 0x6d, (byte) 0x20, (byte) 0x65, (byte) 0x6c, (byte) 0x65, (byte) 0x6b, (byte) 0x74, (byte) 0x72,
+ (byte) 0x2e, (byte) 0x20, (byte) 0x44, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x6e, (byte) 0x76,
+ (byte) 0x65, (byte) 0x72, (byte) 0x6b, (byte) 0x65, (byte) 0x68, (byte) 0x72, (byte) 0x20, (byte) 0x47,
+ (byte) 0x6d, (byte) 0x62, (byte) 0x48, (byte) 0x31, (byte) 0x23, (byte) 0x30, (byte) 0x21, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x1a, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65,
+ (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2d, (byte) 0x53, (byte) 0x69, (byte) 0x67, (byte) 0x2d, (byte) 0x30, (byte) 0x32,
+ (byte) 0x31, (byte) 0x23, (byte) 0x30, (byte) 0x21, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x03, (byte) 0x0c, (byte) 0x1a, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67,
+ (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75,
+ (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x53,
+ (byte) 0x69, (byte) 0x67, (byte) 0x2d, (byte) 0x30, (byte) 0x32, (byte) 0x30, (byte) 0x1e, (byte) 0x17,
+ (byte) 0x0d, (byte) 0x30, (byte) 0x39, (byte) 0x30, (byte) 0x31, (byte) 0x31, (byte) 0x33, (byte) 0x30,
+ (byte) 0x39, (byte) 0x34, (byte) 0x35, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x17, (byte) 0x0d,
+ (byte) 0x31, (byte) 0x32, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x31, (byte) 0x30, (byte) 0x39,
+ (byte) 0x34, (byte) 0x35, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x70, (byte) 0x31,
+ (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+ (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x54, (byte) 0x31, (byte) 0x1f, (byte) 0x30, (byte) 0x1d,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x16, (byte) 0x58,
+ (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x6f, (byte) 0x20, (byte) 0x58,
+ (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x61, (byte) 0x6b, (byte) 0x72,
+ (byte) 0x69, (byte) 0x6e, (byte) 0x67, (byte) 0x65, (byte) 0x72, (byte) 0x31, (byte) 0x17, (byte) 0x30,
+ (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x04, (byte) 0x0c, (byte) 0x0e,
+ (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x61, (byte) 0x6b,
+ (byte) 0x72, (byte) 0x69, (byte) 0x6e, (byte) 0x67, (byte) 0x65, (byte) 0x72, (byte) 0x31, (byte) 0x10,
+ (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x2a, (byte) 0x0c,
+ (byte) 0x07, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x4f, (byte) 0x74, (byte) 0x74, (byte) 0x6f,
+ (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x05, (byte) 0x13, (byte) 0x0c, (byte) 0x39, (byte) 0x37, (byte) 0x30, (byte) 0x30, (byte) 0x31,
+ (byte) 0x36, (byte) 0x38, (byte) 0x36, (byte) 0x36, (byte) 0x31, (byte) 0x37, (byte) 0x34, (byte) 0x30,
+ (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
+ (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86,
+ (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x42,
+ (byte) 0x00, (byte) 0x04, (byte) 0x6b, (byte) 0xde, (byte) 0x5f, (byte) 0x5e, (byte) 0xd5, (byte) 0x2b,
+ (byte) 0xbe, (byte) 0x1e, (byte) 0xb9, (byte) 0x82, (byte) 0x19, (byte) 0x75, (byte) 0xf4, (byte) 0x3b,
+ (byte) 0xc1, (byte) 0x34, (byte) 0xe9, (byte) 0xdb, (byte) 0x0b, (byte) 0x25, (byte) 0x31, (byte) 0x33,
+ (byte) 0xfa, (byte) 0x8b, (byte) 0x72, (byte) 0xd4, (byte) 0x9f, (byte) 0x21, (byte) 0xf5, (byte) 0x62,
+ (byte) 0xb9, (byte) 0xf6, (byte) 0x50, (byte) 0xdb, (byte) 0xcc, (byte) 0xbf, (byte) 0x43, (byte) 0xb9,
+ (byte) 0x5e, (byte) 0x75, (byte) 0x2a, (byte) 0x37, (byte) 0xbe, (byte) 0x32, (byte) 0xa6, (byte) 0x83,
+ (byte) 0xb1, (byte) 0x5c, (byte) 0xc3, (byte) 0x9d, (byte) 0xf0, (byte) 0xab, (byte) 0xe6, (byte) 0x8f,
+ (byte) 0xe4, (byte) 0x97, (byte) 0x83, (byte) 0x57, (byte) 0x89, (byte) 0xe0, (byte) 0x13, (byte) 0xe3,
+ (byte) 0x13, (byte) 0xa8, (byte) 0xa3, (byte) 0x82, (byte) 0x02, (byte) 0x65, (byte) 0x30, (byte) 0x82,
+ (byte) 0x02, (byte) 0x61, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
+ (byte) 0x23, (byte) 0x04, (byte) 0x0c, (byte) 0x30, (byte) 0x0a, (byte) 0x80, (byte) 0x08, (byte) 0x46,
+ (byte) 0x06, (byte) 0x9f, (byte) 0x8e, (byte) 0x41, (byte) 0x8e, (byte) 0x15, (byte) 0xbd, (byte) 0x30,
+ (byte) 0x27, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x07, (byte) 0x01, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x04, (byte) 0x18,
+ (byte) 0x30, (byte) 0x16, (byte) 0x30, (byte) 0x08, (byte) 0x06, (byte) 0x06, (byte) 0x04, (byte) 0x00,
+ (byte) 0x8e, (byte) 0x46, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0a, (byte) 0x06, (byte) 0x08,
+ (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x0b, (byte) 0x01,
+ (byte) 0x30, (byte) 0x81, (byte) 0x84, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x01, (byte) 0x01, (byte) 0x04, (byte) 0x78, (byte) 0x30,
+ (byte) 0x76, (byte) 0x30, (byte) 0x2c, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30, (byte) 0x01, (byte) 0x86, (byte) 0x20, (byte) 0x68,
+ (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x6f, (byte) 0x63,
+ (byte) 0x73, (byte) 0x70, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2e,
+ (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e,
+ (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x6f, (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x30,
+ (byte) 0x46, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x07, (byte) 0x30, (byte) 0x02, (byte) 0x86, (byte) 0x3a, (byte) 0x68, (byte) 0x74, (byte) 0x74,
+ (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e,
+ (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e,
+ (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x63, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x73,
+ (byte) 0x2f, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d,
+ (byte) 0x50, (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d,
+ (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x53, (byte) 0x69, (byte) 0x67,
+ (byte) 0x2d, (byte) 0x30, (byte) 0x32, (byte) 0x2e, (byte) 0x63, (byte) 0x72, (byte) 0x74, (byte) 0x30,
+ (byte) 0x81, (byte) 0x9d, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x20, (byte) 0x04,
+ (byte) 0x81, (byte) 0x95, (byte) 0x30, (byte) 0x81, (byte) 0x92, (byte) 0x30, (byte) 0x81, (byte) 0x85,
+ (byte) 0x06, (byte) 0x06, (byte) 0x2a, (byte) 0x28, (byte) 0x00, (byte) 0x11, (byte) 0x01, (byte) 0x03,
+ (byte) 0x30, (byte) 0x7b, (byte) 0x30, (byte) 0x3d, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06,
+ (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x02, (byte) 0x01, (byte) 0x16, (byte) 0x31,
+ (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x77,
+ (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75,
+ (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x64, (byte) 0x6f,
+ (byte) 0x63, (byte) 0x73, (byte) 0x2f, (byte) 0x63, (byte) 0x70, (byte) 0x2f, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x70, (byte) 0x72, (byte) 0x65,
+ (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x30, (byte) 0x3a, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x02, (byte) 0x02, (byte) 0x30, (byte) 0x2e, (byte) 0x1a,
+ (byte) 0x2c, (byte) 0x44, (byte) 0x69, (byte) 0x65, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x20,
+ (byte) 0x5a, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x6b,
+ (byte) 0x61, (byte) 0x74, (byte) 0x20, (byte) 0x64, (byte) 0x69, (byte) 0x65, (byte) 0x6e, (byte) 0x74,
+ (byte) 0x20, (byte) 0x6e, (byte) 0x75, (byte) 0x72, (byte) 0x20, (byte) 0x7a, (byte) 0x75, (byte) 0x20,
+ (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x7a, (byte) 0x77, (byte) 0x65, (byte) 0x63,
+ (byte) 0x6b, (byte) 0x65, (byte) 0x6e, (byte) 0x20, (byte) 0x21, (byte) 0x30, (byte) 0x08, (byte) 0x06,
+ (byte) 0x06, (byte) 0x04, (byte) 0x00, (byte) 0x8b, (byte) 0x30, (byte) 0x01, (byte) 0x01, (byte) 0x30,
+ (byte) 0x81, (byte) 0xa4, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x1f, (byte) 0x04,
+ (byte) 0x81, (byte) 0x9c, (byte) 0x30, (byte) 0x81, (byte) 0x99, (byte) 0x30, (byte) 0x81, (byte) 0x96,
+ (byte) 0xa0, (byte) 0x81, (byte) 0x93, (byte) 0xa0, (byte) 0x81, (byte) 0x90, (byte) 0x86, (byte) 0x81,
+ (byte) 0x8d, (byte) 0x6c, (byte) 0x64, (byte) 0x61, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f,
+ (byte) 0x6c, (byte) 0x64, (byte) 0x61, (byte) 0x70, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x6f, (byte) 0x75, (byte) 0x3d,
+ (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x50,
+ (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x54,
+ (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x53, (byte) 0x69, (byte) 0x67, (byte) 0x2d,
+ (byte) 0x30, (byte) 0x32, (byte) 0x2c, (byte) 0x6f, (byte) 0x3d, (byte) 0x41, (byte) 0x2d, (byte) 0x54,
+ (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2c, (byte) 0x63, (byte) 0x3d, (byte) 0x41,
+ (byte) 0x54, (byte) 0x3f, (byte) 0x63, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66,
+ (byte) 0x69, (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x65, (byte) 0x76,
+ (byte) 0x6f, (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x6c,
+ (byte) 0x69, (byte) 0x73, (byte) 0x74, (byte) 0x3f, (byte) 0x62, (byte) 0x61, (byte) 0x73, (byte) 0x65,
+ (byte) 0x3f, (byte) 0x6f, (byte) 0x62, (byte) 0x6a, (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x63,
+ (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x3d, (byte) 0x65, (byte) 0x69, (byte) 0x64,
+ (byte) 0x43, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63,
+ (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x41, (byte) 0x75, (byte) 0x74,
+ (byte) 0x68, (byte) 0x6f, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x79, (byte) 0x30, (byte) 0x11,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x0a, (byte) 0x04,
+ (byte) 0x08, (byte) 0x46, (byte) 0x08, (byte) 0xda, (byte) 0x9e, (byte) 0x68, (byte) 0xf8, (byte) 0xe5,
+ (byte) 0x81, (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0f,
+ (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x04, (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x06,
+ (byte) 0xc0, (byte) 0x30, (byte) 0x25, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x11,
+ (byte) 0x04, (byte) 0x1e, (byte) 0x30, (byte) 0x1c, (byte) 0x81, (byte) 0x1a, (byte) 0x74, (byte) 0x68,
+ (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x73, (byte) 0x2e, (byte) 0x72, (byte) 0x6f, (byte) 0x65,
+ (byte) 0x73, (byte) 0x73, (byte) 0x6c, (byte) 0x65, (byte) 0x72, (byte) 0x40, (byte) 0x65, (byte) 0x67,
+ (byte) 0x69, (byte) 0x7a, (byte) 0x2e, (byte) 0x67, (byte) 0x76, (byte) 0x2e, (byte) 0x61, (byte) 0x74,
+ (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04,
+ (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+ (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0xd8,
+ (byte) 0xec, (byte) 0xe5, (byte) 0x5c, (byte) 0x17, (byte) 0x42, (byte) 0xe8, (byte) 0x2f, (byte) 0x04,
+ (byte) 0x1f, (byte) 0xe2, (byte) 0x04, (byte) 0x57, (byte) 0x07, (byte) 0x30, (byte) 0xdc, (byte) 0x4f,
+ (byte) 0x61, (byte) 0x7d, (byte) 0xd8, (byte) 0x89, (byte) 0x36, (byte) 0x31, (byte) 0x26, (byte) 0x45,
+ (byte) 0x55, (byte) 0x64, (byte) 0xd3, (byte) 0x55, (byte) 0x1b, (byte) 0x83, (byte) 0x51, (byte) 0xa0,
+ (byte) 0x39, (byte) 0x1b, (byte) 0x6a, (byte) 0x7e, (byte) 0xfa, (byte) 0x7e, (byte) 0x2c, (byte) 0xd0,
+ (byte) 0xd3, (byte) 0x86, (byte) 0x7b, (byte) 0x8d, (byte) 0x29, (byte) 0x8f, (byte) 0xa3, (byte) 0x83,
+ (byte) 0xd2, (byte) 0x72, (byte) 0xce, (byte) 0x43, (byte) 0xcf, (byte) 0xc1, (byte) 0x27, (byte) 0xf1,
+ (byte) 0x4d, (byte) 0x11, (byte) 0xe2, (byte) 0x67, (byte) 0xbe, (byte) 0x6e, (byte) 0x34, (byte) 0x7d,
+ (byte) 0x04, (byte) 0x1f, (byte) 0xba, (byte) 0x55, (byte) 0x34, (byte) 0xea, (byte) 0xc2, (byte) 0xcf,
+ (byte) 0x0f, (byte) 0x64, (byte) 0x7b, (byte) 0x84, (byte) 0xe0, (byte) 0x55, (byte) 0x05, (byte) 0x82,
+ (byte) 0xdd, (byte) 0x9d, (byte) 0xd7, (byte) 0xeb, (byte) 0x91, (byte) 0x78, (byte) 0x69, (byte) 0x49,
+ (byte) 0x58, (byte) 0x70, (byte) 0xff, (byte) 0x83, (byte) 0x70, (byte) 0xa0, (byte) 0xb3, (byte) 0xb7,
+ (byte) 0x3d, (byte) 0x0f, (byte) 0x8e, (byte) 0xe9, (byte) 0x1b, (byte) 0x21, (byte) 0xef, (byte) 0x31,
+ (byte) 0x0b, (byte) 0xe3, (byte) 0xac, (byte) 0xc6, (byte) 0x0f, (byte) 0x57, (byte) 0x4f, (byte) 0xd8,
+ (byte) 0xd6, (byte) 0xb2, (byte) 0xd0, (byte) 0xca, (byte) 0xd9, (byte) 0x6f, (byte) 0x3f, (byte) 0x6e,
+ (byte) 0x83, (byte) 0x8c, (byte) 0xff, (byte) 0x47, (byte) 0xca, (byte) 0xbc, (byte) 0x81, (byte) 0x60,
+ (byte) 0x5f, (byte) 0xe2, (byte) 0xdd, (byte) 0xbd, (byte) 0x89, (byte) 0xb2, (byte) 0x52, (byte) 0xac,
+ (byte) 0xc3, (byte) 0x8b, (byte) 0x44, (byte) 0x99, (byte) 0x70, (byte) 0xe7, (byte) 0x2c, (byte) 0x52,
+ (byte) 0x21, (byte) 0xaa, (byte) 0xa2, (byte) 0x0f, (byte) 0x38, (byte) 0xc6, (byte) 0x98, (byte) 0x4d,
+ (byte) 0x48, (byte) 0xda, (byte) 0x65, (byte) 0x41, (byte) 0xa4, (byte) 0xad, (byte) 0x41, (byte) 0x7c,
+ (byte) 0x99, (byte) 0x14, (byte) 0xe5, (byte) 0xcb, (byte) 0x51, (byte) 0xd7, (byte) 0xab, (byte) 0x76,
+ (byte) 0xb1, (byte) 0x20, (byte) 0xce, (byte) 0x32, (byte) 0x1b, (byte) 0x11, (byte) 0x5c, (byte) 0xef,
+ (byte) 0x8b, (byte) 0x4f, (byte) 0xf3, (byte) 0x46, (byte) 0x5b, (byte) 0x11, (byte) 0xd7, (byte) 0x91,
+ (byte) 0xb6, (byte) 0x41, (byte) 0xd3, (byte) 0x23, (byte) 0xb6, (byte) 0x03, (byte) 0xa8, (byte) 0x98,
+ (byte) 0x40, (byte) 0x76, (byte) 0x13, (byte) 0x5d, (byte) 0x4c, (byte) 0xb2, (byte) 0xe9, (byte) 0xfe,
+ (byte) 0x90, (byte) 0x27, (byte) 0x04, (byte) 0xfc, (byte) 0x10, (byte) 0x45, (byte) 0x8b, (byte) 0x10,
+ (byte) 0xc3, (byte) 0xb2, (byte) 0x4b, (byte) 0x3c, (byte) 0xd2, (byte) 0x5b, (byte) 0x0f, (byte) 0xe8,
+ (byte) 0xfb, (byte) 0xb9, (byte) 0x45, (byte) 0xaf, (byte) 0x05, (byte) 0xc4, (byte) 0xba, (byte) 0xc7,
+ (byte) 0xfc, (byte) 0xa5, (byte) 0x7d, (byte) 0xdb, (byte) 0x4f, (byte) 0xa9, (byte) 0x76, (byte) 0xe2,
+ (byte) 0xfa, (byte) 0xc7, (byte) 0xe0, (byte) 0xad, (byte) 0x70, (byte) 0xaa, (byte) 0x40, (byte) 0x15,
+ (byte) 0x64, (byte) 0x01, (byte) 0xba, (byte) 0xc6, (byte) 0xc3, (byte) 0x83, (byte) 0x65, (byte) 0x95,
+ (byte) 0x3c, (byte) 0x05, (byte) 0x53, (byte) 0x88, (byte) 0xe7, (byte) 0x19, (byte) 0x98
+ };
+
+ protected static final int KID_PIN_SIG = 0x81;
+
+ protected byte[] EF_C_CH_DS = new byte[2000];
+
+ public ACOSApplSIG() {
+ // Files
+ System.arraycopy(C_CH_DS, 0, EF_C_CH_DS, 0, C_CH_DS.length);
+ putFile(new File(FID_EF_C_CH_DS, EF_C_CH_DS, FCI_EF_C_CH_DS));
+
+ // PINs
+ try {
+ pins.put(KID_PIN_SIG, new PIN(Arrays.copyOf("123456".getBytes("ASCII"), 8), KID_PIN_SIG, 3));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public byte[] getAID() {
+ return AID_SIG;
+ }
+
+ @Override
+ public byte[] getFID() {
+ return FID_SIG;
+ }
+
+ @Override
+ public byte[] getFCI() {
+ return FCI;
+ }
+
+ @Override
+ public ResponseAPDU cmdPERFORM_SECURITY_OPERATION(CommandAPDU command, CardChannelEmul channel) {
+
+ checkINS(command, 0x2A);
+
+ if (command.getP1() == 0x90 && command.getP2() == 0x81) {
+
+ // PUT HASH
+ hash = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+
+ } else if (command.getP1() == 0x9E && command.getP2() == 0x9A) {
+
+ // COMPUTE DIGITAL SIGNATURE
+ if (securityEnv == null) {
+ // No security environment
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ if (hash == null) {
+ // Command sequence not correct
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x03});
+ }
+ if (hash.length != 20) {
+ // Invalid hash length
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80});
+ }
+ if (pins.get(KID_PIN_SIG).state != PIN.STATE_PIN_VERIFIED) {
+ // Security Status not satisfied
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+
+ byte[] signature = new byte[48];
+
+ // TODO replace by signature creation
+ Random random = new Random();
+ random.nextBytes(signature);
+
+ byte[] response = new byte[signature.length + 2];
+ System.arraycopy(signature, 0, response, 0, signature.length);
+ response[signature.length] = (byte) 0x90;
+ response[signature.length + 1] = (byte) 0x00;
+
+ hash = null;
+ pins.get(KID_PIN_SIG).state = PIN.STATE_RESET;
+
+ return new ResponseAPDU(response);
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00});
+ }
+
+ }
+
+ public void clearCert() {
+ Arrays.fill(EF_C_CH_DS, (byte) 0x00);
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardChannelEmul.java
new file mode 100644
index 00000000..25923686
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardChannelEmul.java
@@ -0,0 +1,261 @@
+/*
+* 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.acos;
+
+import java.util.Arrays;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.AbstractAppl;
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public abstract class ACOSCardChannelEmul extends CardChannelEmul {
+
+ /**
+ *
+ */
+ protected CardEmul cardEmul;
+
+ public ACOSCardChannelEmul(CardEmul cardEmul) {
+ this.cardEmul = cardEmul;
+ }
+
+ @Override
+ public Card getCard() {
+ return cardEmul;
+ }
+
+ protected ResponseAPDU cmdSELECT(CommandAPDU command) throws CardException {
+
+ byte[] fid = command.getData();
+
+ AbstractAppl appl = cardEmul.getApplication(fid);
+ if (appl != null) {
+ if (currentAppl != null && currentAppl != appl) {
+ currentAppl.leaveApplContext();
+ currentFile = null;
+ }
+ currentAppl = appl;
+
+ byte[] fci = currentAppl.getFCI();
+ byte[] response = new byte[fci.length + 2];
+ System.arraycopy(fci, 0, response, 0, fci.length);
+ response[fci.length] = (byte) 0x90;
+ response[fci.length + 1] = (byte) 0x00;
+ return new ResponseAPDU(response);
+ }
+
+ if (command.getP1() == 0x00) {
+ // SELECT with FID
+ if (currentAppl instanceof AbstractAppl) {
+
+ for (File file : ((AbstractAppl) currentAppl).getFiles()) {
+
+ if (Arrays.equals(fid, file.fid)) {
+ currentFile = file;
+ byte[] response = new byte[file.fcx.length + 2];
+ System.arraycopy(file.fcx, 0, response, 0, file.fcx.length);
+ response[file.fcx.length] = (byte) 0x90;
+ response[file.fcx.length + 1] = (byte) 0x00;
+ return new ResponseAPDU(response);
+ }
+
+ }
+
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82});
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82});
+ }
+ }
+
+ // Not found
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82});
+
+ }
+
+ public abstract ResponseAPDU cmdREAD_BINARY(CommandAPDU command) throws CardException;
+
+
+ @Override
+ public ResponseAPDU transmit(CommandAPDU command) throws CardException {
+
+ if (command.getCLA() == 0x00) {
+
+ switch (command.getINS()) {
+
+ // SELECT
+ case 0xA4:
+ return cmdSELECT(command);
+
+ // READ BINARY
+ case 0xB0:
+ return cmdREAD_BINARY(command);
+
+ // VERIFY
+ case 0x20:
+ if ((command.getP2() & 0x80) > 0) {
+ return cmdVERIFY(command);
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ // MANAGE SECURITY ENVIRONMENT
+ case 0x22: {
+ if (currentAppl != null) {
+ return currentAppl.cmdMANAGE_SECURITY_ENVIRONMENT(command, this);
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+
+ // CHANGE REFERENCE DATA
+ case 0x24: {
+ return cmdCHANGE_REFERENCE_DATA(command);
+ }
+
+ // PERFORM SECURITY OPERATION
+ case 0x2A: {
+ if (currentAppl != null) {
+ return currentAppl.cmdPERFORM_SECURITY_OPERATION(command, this);
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+
+ // INTERNAL AUTHENTICATE
+ case 0x88: {
+ if (currentAppl != null) {
+ return currentAppl.cmdINTERNAL_AUTHENTICATE(command, this);
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+
+ default:
+ return new ResponseAPDU(new byte[] { (byte) 0x6D, (byte) 0x00});
+ }
+
+ } else {
+ return new ResponseAPDU(new byte[] { (byte) 0x6E, (byte) 0x00});
+ }
+
+ }
+
+ protected ResponseAPDU verifyPin(int kid, byte[] reference) {
+
+ PIN pin;
+ if (currentAppl != null) {
+ pin = currentAppl.pins.get(kid);
+ } else {
+ pin = null;
+ }
+
+ if (pin != null) {
+
+ if (reference.length != 8) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ if (Arrays.equals(reference, pin.pin)) {
+ switch (pin.state) {
+ case PIN.STATE_PIN_BLOCKED:
+ return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 });
+
+ case PIN.STATE_RESET:
+ pin.state = PIN.STATE_PIN_VERIFIED;
+
+ default:
+ pin.kfpc = 10;
+ return new ResponseAPDU(new byte[] { (byte) 0x90, (byte) 0x00 });
+ }
+ } else {
+ switch (pin.state) {
+ case PIN.STATE_PIN_BLOCKED:
+ return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 });
+
+ default:
+ if (--pin.kfpc > 0) {
+ return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)});
+ } else {
+ pin.state = PIN.STATE_PIN_BLOCKED;
+ return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 });
+ }
+ }
+
+ }
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00});
+ }
+
+ }
+
+ public ResponseAPDU cmdVERIFY(CommandAPDU command) throws CardException {
+
+ if (command.getINS() != 0x20) {
+ throw new IllegalArgumentException("INS has to be 0x20.");
+ }
+
+ if (command.getP1() != 00) {
+ return new ResponseAPDU(new byte[] {(byte) 0x6B, (byte) 0x00});
+ }
+
+ return verifyPin(command.getP2(), command.getData());
+
+ }
+
+ public ResponseAPDU cmdCHANGE_REFERENCE_DATA(CommandAPDU command) {
+
+ if (command.getINS() != 0x24) {
+ throw new IllegalArgumentException("INS has to be 0x24.");
+ }
+
+ if (command.getP1() == 0x00) {
+
+ byte[] data = command.getData();
+ if (data.length != 16) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ ResponseAPDU response = verifyPin(command.getP2(), Arrays.copyOf(data, 8));
+ if (response.getSW() == 0x9000) {
+ PIN pin;
+ if (currentAppl != null) {
+ pin = currentAppl.pins.get(command.getP2());
+ } else {
+ pin = null;
+ }
+ pin.pin = Arrays.copyOfRange(data, 8, 16);
+ }
+
+ return response;
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardEmul.java
new file mode 100644
index 00000000..b9f70a5d
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardEmul.java
@@ -0,0 +1,38 @@
+/*
+* 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.acos;
+
+
+import javax.smartcardio.ATR;
+
+import at.gv.egiz.smcc.CardEmul;
+
+@SuppressWarnings("restriction")
+public abstract class ACOSCardEmul extends CardEmul {
+
+ protected static ATR ATR = new ATR(new byte[] {
+ (byte) 0x3b, (byte) 0xbf, (byte) 0x11, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45,
+ (byte) 0x45, (byte) 0x50, (byte) 0x41, (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) 0xf1
+ });
+
+ @Override
+ public ATR getATR() {
+ return ATR;
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java
new file mode 100644
index 00000000..90bb039e
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java
@@ -0,0 +1,243 @@
+/*
+* 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.acos;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import at.gv.egiz.smcc.ACOSCard;
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.CardNotSupportedException;
+import at.gv.egiz.smcc.CardTest;
+import at.gv.egiz.smcc.LockedException;
+import at.gv.egiz.smcc.NotActivatedException;
+import at.gv.egiz.smcc.SignatureCard;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.SignatureCard.KeyboxName;
+
+public abstract class ACOSCardTest extends CardTest {
+
+ public ACOSCardTest() {
+ super();
+ }
+
+ protected abstract int getVersion();
+
+ @Test
+ public void testGetInfoboxIdentityLinkEmpty() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ char[] pin = "0000".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
+ appl.clearInfobox();
+
+ byte[] idlink = signatureCard.getInfobox("IdentityLink",
+ new TestPINProvider(pin), null);
+ assertNull(idlink);
+
+ }
+
+ @Test(expected = SignatureCardException.class)
+ public void testGetInfoboxIdentityInvalid() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ char[] pin = "0000".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
+ appl.setInfoboxHeader((byte) 0xFF);
+
+ signatureCard.getInfobox("IdentityLink", new TestPINProvider(pin), null);
+
+ }
+
+ @Test
+ public void testGetCerts() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ byte[] cert;
+
+ cert = signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR);
+ assertNotNull(cert);
+ assertTrue(Arrays.equals(cert, A04ApplSIG.C_CH_DS));
+
+ cert = signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR);
+ assertNotNull(cert);
+ assertTrue(Arrays.equals(cert, A04ApplDEC.C_CH_EKEY));
+
+ }
+
+ @Test(expected = NotActivatedException.class)
+ public void testGetSIGCertEmpty() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplSIG appl = (ACOSApplSIG) card.getApplication(ACOSAppl.AID_SIG);
+ appl.clearCert();
+
+ signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR);
+
+ }
+
+ @Test(expected = NotActivatedException.class)
+ public void testGetDECCertEmpty() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
+ appl.clearCert();
+
+ signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR);
+
+ }
+
+ @Test
+ public void testSignSIG() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ char[] pin = "123456".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplSIG appl = (ACOSApplSIG) card.getApplication(ACOSAppl.AID_SIG);
+ appl.setPin(ACOSApplSIG.KID_PIN_SIG, pin);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ byte[] signature = signatureCard.createSignature(hash,
+ KeyboxName.SECURE_SIGNATURE_KEYPAIR, new TestPINProvider(pin));
+
+ assertNotNull(signature);
+
+ }
+
+ @Test
+ public void testSignDEC() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ char[] pin = "1234".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
+ appl.setPin(ACOSApplDEC.KID_PIN_DEC, pin);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ byte[] signature = signatureCard.createSignature(hash,
+ KeyboxName.CERITIFIED_KEYPAIR, new TestPINProvider(pin));
+
+ assertNotNull(signature);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignSIGInvalidPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+
+ signatureCard.createSignature(hash, KeyboxName.SECURE_SIGNATURE_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignDECInvalidPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray());
+
+ signatureCard.createSignature(hash, KeyboxName.CERITIFIED_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignSIGBlockedPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplSIG appl = (ACOSApplSIG) card.getApplication(ACOSAppl.AID_SIG);
+ appl.setPin(ACOSApplSIG.KID_PIN_SIG, null);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+
+ signatureCard.createSignature(hash, KeyboxName.SECURE_SIGNATURE_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignDECBlockedPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
+ appl.setPin(ACOSApplDEC.KID_PIN_DEC, null);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray());
+
+ signatureCard.createSignature(hash, KeyboxName.CERITIFIED_KEYPAIR,
+ pinProvider);
+
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTestSuite.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTestSuite.java
new file mode 100644
index 00000000..101f7edc
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTestSuite.java
@@ -0,0 +1,27 @@
+/*
+* 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.acos;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses( { A03CardTest.class, A04CardTest.class })
+public class ACOSCardTestSuite {
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java
new file mode 100644
index 00000000..2ca63eea
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.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.starcos;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.AbstractAppl;
+import at.gv.egiz.smcc.CardAppl;
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public abstract class STARCOSAppl extends AbstractAppl implements CardAppl {
+
+ public static byte[] AID_SichereSignatur = new byte[] { (byte) 0xD0, (byte) 0x40,
+ (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x12, (byte) 0x01 };
+
+ public static byte[] FID_SichereSignatur = new byte[] { (byte) 0x3F, (byte) 0x04 };
+
+ public static byte[] AID_Infobox = new byte[] { (byte) 0xD0, (byte) 0x40,
+ (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x18, (byte) 0x01 };
+
+ public static byte[] FID_Infobox = new byte[] { (byte) 0x3F, (byte) 0x06 };
+
+ public static byte[] AID_GewoehnlicheSignatur = new byte[] { (byte) 0xD0, (byte) 0x40,
+ (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x13, (byte) 0x01 };
+
+ public static byte[] FID_GewoehnlicheSignatur = new byte[] { (byte) 0x3F, (byte) 0x05 };
+
+ protected STARCOSCardChannelEmul channel;
+
+ protected byte[] securityEnv;
+
+ protected byte[] hash;
+
+ public STARCOSAppl(STARCOSCardChannelEmul channel) {
+ this.channel = channel;
+ }
+
+ @Override
+ public ResponseAPDU cmdINTERNAL_AUTHENTICATE(CommandAPDU command, CardChannelEmul channel) {
+ return new ResponseAPDU(new byte[] {(byte) 0x6D, (byte) 0x00});
+ }
+
+ @Override
+ public void leaveApplContext() {
+ Iterator<PIN> pin = pins.values().iterator();
+ while (pin.hasNext()) {
+ pin.next().state = PIN.STATE_RESET;
+ }
+ }
+
+ public void setPin(int kid, char[] value) {
+ PIN pin = pins.get(kid);
+ if (pin != null) {
+ if (value == null) {
+ pin.pin = null;
+ } else {
+ byte[] b = new byte[8];
+ b[0] = (byte) (0x20 | value.length);
+ for(int i = 1, j = 0; i < b.length; i++) {
+ int h = ((j < value.length)
+ ? Character.digit(value[j++], 10)
+ : 0x0F);
+ int l = ((j < value.length)
+ ? Character.digit(value[j++], 10)
+ : 0x0F);
+ b[i] = (byte) ((h << 4) | l);
+ }
+ pin.pin = b;
+ }
+ }
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java
new file mode 100644
index 00000000..cec305da
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java
@@ -0,0 +1,332 @@
+/*
+* 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.starcos;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public class STARCOSApplGewoehnlicheSignatur extends STARCOSAppl {
+
+ private static byte[] FCI = new byte[] { (byte) 0x6f, (byte) 0x14,
+ (byte) 0x84, (byte) 0x08, (byte) 0xd0, (byte) 0x40, (byte) 0x00,
+ (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x13, (byte) 0x01,
+ (byte) 0xa5, (byte) 0x08, (byte) 0x53, (byte) 0x02, (byte) 0x01,
+ (byte) 0x10, (byte) 0x54, (byte) 0x02, (byte) 0x01, (byte) 0x00 };
+
+ protected static byte[] FID_EF_C_X509_CH_AUT = new byte[] { (byte) 0x2f,
+ (byte) 0x01 };
+
+ protected static byte[] FCI_EF_C_X509_CH_AUT = new byte[] { (byte) 0x62,
+ (byte) 0x16, (byte) 0x80, (byte) 0x02, (byte) 0x04, (byte) 0x9c,
+ (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x83, (byte) 0x02,
+ (byte) 0x2f, (byte) 0x01, (byte) 0x88, (byte) 0x01, (byte) 0x08,
+ (byte) 0x8a, (byte) 0x01, (byte) 0x05, (byte) 0xa1, (byte) 0x03,
+ (byte) 0x8b, (byte) 0x01, (byte) 0x08 };
+
+ protected static byte[] C_X509_CH_AUT = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x98, (byte) 0x30, (byte) 0x82, (byte) 0x03, (byte) 0x80,
+ (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x03, (byte) 0x02,
+ (byte) 0x06, (byte) 0x5f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x95, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
+ (byte) 0x54, (byte) 0x31, (byte) 0x48, (byte) 0x30, (byte) 0x46, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x3f, (byte) 0x41, (byte) 0x2d, (byte) 0x54, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x47, (byte) 0x65, (byte) 0x73, (byte) 0x2e,
+ (byte) 0x20, (byte) 0x66, (byte) 0x2e, (byte) 0x20, (byte) 0x53, (byte) 0x69, (byte) 0x63, (byte) 0x68,
+ (byte) 0x65, (byte) 0x72, (byte) 0x68, (byte) 0x65, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x73,
+ (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x6d, (byte) 0x65, (byte) 0x20, (byte) 0x69,
+ (byte) 0x6d, (byte) 0x20, (byte) 0x65, (byte) 0x6c, (byte) 0x65, (byte) 0x6b, (byte) 0x74, (byte) 0x72,
+ (byte) 0x2e, (byte) 0x20, (byte) 0x44, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x6e, (byte) 0x76,
+ (byte) 0x65, (byte) 0x72, (byte) 0x6b, (byte) 0x65, (byte) 0x68, (byte) 0x72, (byte) 0x20, (byte) 0x47,
+ (byte) 0x6d, (byte) 0x62, (byte) 0x48, (byte) 0x31, (byte) 0x1d, (byte) 0x30, (byte) 0x1b, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x14, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x74, (byte) 0x6f, (byte) 0x6b,
+ (byte) 0x65, (byte) 0x6e, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d,
+ (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x1d, (byte) 0x30, (byte) 0x1b, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x14, (byte) 0x61, (byte) 0x2d, (byte) 0x73,
+ (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x74, (byte) 0x6f, (byte) 0x6b, (byte) 0x65,
+ (byte) 0x6e, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x30,
+ (byte) 0x33, (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x30, (byte) 0x39, (byte) 0x30,
+ (byte) 0x33, (byte) 0x30, (byte) 0x36, (byte) 0x31, (byte) 0x35, (byte) 0x32, (byte) 0x32, (byte) 0x33,
+ (byte) 0x38, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32, (byte) 0x30, (byte) 0x33,
+ (byte) 0x30, (byte) 0x36, (byte) 0x31, (byte) 0x35, (byte) 0x32, (byte) 0x32, (byte) 0x33, (byte) 0x38,
+ (byte) 0x5a, (byte) 0x30, (byte) 0x72, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x54,
+ (byte) 0x31, (byte) 0x20, (byte) 0x30, (byte) 0x1e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x03, (byte) 0x0c, (byte) 0x17, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0xc5, (byte) 0x90,
+ (byte) 0x7a, (byte) 0x67, (byte) 0xc3, (byte) 0xbc, (byte) 0x72, (byte) 0x20, (byte) 0x58, (byte) 0x58,
+ (byte) 0x58, (byte) 0x54, (byte) 0xc3, (byte) 0xbc, (byte) 0x7a, (byte) 0x65, (byte) 0x6b, (byte) 0xc3,
+ (byte) 0xa7, (byte) 0x69, (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x04, (byte) 0x04, (byte) 0x0c, (byte) 0x0c, (byte) 0x58, (byte) 0x58, (byte) 0x58,
+ (byte) 0x54, (byte) 0xc3, (byte) 0xbc, (byte) 0x7a, (byte) 0x65, (byte) 0x6b, (byte) 0xc3, (byte) 0xa7,
+ (byte) 0x69, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x2a, (byte) 0x0c, (byte) 0x0a, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0xc5,
+ (byte) 0x90, (byte) 0x7a, (byte) 0x67, (byte) 0xc3, (byte) 0xbc, (byte) 0x72, (byte) 0x31, (byte) 0x15,
+ (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x05, (byte) 0x13,
+ (byte) 0x0c, (byte) 0x37, (byte) 0x30, (byte) 0x34, (byte) 0x38, (byte) 0x37, (byte) 0x31, (byte) 0x30,
+ (byte) 0x35, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x38, (byte) 0x30, (byte) 0x49, (byte) 0x30,
+ (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d,
+ (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce,
+ (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x32, (byte) 0x00, (byte) 0x04,
+ (byte) 0x02, (byte) 0x55, (byte) 0x51, (byte) 0xf9, (byte) 0x2a, (byte) 0xea, (byte) 0x6f, (byte) 0xd3,
+ (byte) 0xf5, (byte) 0xda, (byte) 0xa9, (byte) 0x7a, (byte) 0x22, (byte) 0xfc, (byte) 0xb4, (byte) 0x38,
+ (byte) 0xe9, (byte) 0x5c, (byte) 0xdc, (byte) 0x6b, (byte) 0x86, (byte) 0xa6, (byte) 0x77, (byte) 0xa7,
+ (byte) 0x90, (byte) 0xf3, (byte) 0x36, (byte) 0xe0, (byte) 0xc4, (byte) 0xde, (byte) 0x72, (byte) 0xf2,
+ (byte) 0x1a, (byte) 0x07, (byte) 0xfa, (byte) 0xd0, (byte) 0xc8, (byte) 0x1c, (byte) 0xa0, (byte) 0xc8,
+ (byte) 0x8b, (byte) 0x5d, (byte) 0xde, (byte) 0x9e, (byte) 0xf8, (byte) 0x3b, (byte) 0x7c, (byte) 0x8c,
+ (byte) 0xa3, (byte) 0x82, (byte) 0x01, (byte) 0xec, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0xe8,
+ (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04,
+ (byte) 0x0c, (byte) 0x30, (byte) 0x0a, (byte) 0x80, (byte) 0x08, (byte) 0x47, (byte) 0x7e, (byte) 0x5b,
+ (byte) 0xdb, (byte) 0x37, (byte) 0x33, (byte) 0xb1, (byte) 0xfa, (byte) 0x30, (byte) 0x7e, (byte) 0x06,
+ (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x01,
+ (byte) 0x01, (byte) 0x04, (byte) 0x72, (byte) 0x30, (byte) 0x70, (byte) 0x30, (byte) 0x2c, (byte) 0x06,
+ (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30,
+ (byte) 0x01, (byte) 0x86, (byte) 0x20, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a,
+ (byte) 0x2f, (byte) 0x2f, (byte) 0x6f, (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x2d, (byte) 0x74,
+ (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x6f,
+ (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x30, (byte) 0x40, (byte) 0x06, (byte) 0x08, (byte) 0x2b,
+ (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30, (byte) 0x02, (byte) 0x86,
+ (byte) 0x34, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f,
+ (byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x63,
+ (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x73, (byte) 0x2f, (byte) 0x61, (byte) 0x2d, (byte) 0x73,
+ (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x74, (byte) 0x6f, (byte) 0x6b, (byte) 0x65,
+ (byte) 0x6e, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x30,
+ (byte) 0x33, (byte) 0x2e, (byte) 0x63, (byte) 0x72, (byte) 0x74, (byte) 0x30, (byte) 0x81, (byte) 0x86,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x20, (byte) 0x04, (byte) 0x7f, (byte) 0x30,
+ (byte) 0x7d, (byte) 0x30, (byte) 0x7b, (byte) 0x06, (byte) 0x06, (byte) 0x2a, (byte) 0x28, (byte) 0x00,
+ (byte) 0x11, (byte) 0x01, (byte) 0x03, (byte) 0x30, (byte) 0x71, (byte) 0x30, (byte) 0x35, (byte) 0x06,
+ (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x02,
+ (byte) 0x01, (byte) 0x16, (byte) 0x29, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a,
+ (byte) 0x2f, (byte) 0x2f, (byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74,
+ (byte) 0x2f, (byte) 0x64, (byte) 0x6f, (byte) 0x63, (byte) 0x73, (byte) 0x2f, (byte) 0x63, (byte) 0x70,
+ (byte) 0x2f, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d,
+ (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x30, (byte) 0x38, (byte) 0x06, (byte) 0x08,
+ (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x02, (byte) 0x02,
+ (byte) 0x30, (byte) 0x2c, (byte) 0x1a, (byte) 0x2a, (byte) 0x44, (byte) 0x69, (byte) 0x65, (byte) 0x73,
+ (byte) 0x65, (byte) 0x73, (byte) 0x20, (byte) 0x5a, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69,
+ (byte) 0x66, (byte) 0x69, (byte) 0x6b, (byte) 0x61, (byte) 0x74, (byte) 0x20, (byte) 0x64, (byte) 0x69,
+ (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x20, (byte) 0x6e, (byte) 0x75, (byte) 0x72, (byte) 0x20,
+ (byte) 0x7a, (byte) 0x75, (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x7a,
+ (byte) 0x77, (byte) 0x65, (byte) 0x63, (byte) 0x6b, (byte) 0x65, (byte) 0x6e, (byte) 0x30, (byte) 0x81,
+ (byte) 0x99, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x1f, (byte) 0x04, (byte) 0x81,
+ (byte) 0x91, (byte) 0x30, (byte) 0x81, (byte) 0x8e, (byte) 0x30, (byte) 0x81, (byte) 0x8b, (byte) 0xa0,
+ (byte) 0x81, (byte) 0x88, (byte) 0xa0, (byte) 0x81, (byte) 0x85, (byte) 0x86, (byte) 0x81, (byte) 0x82,
+ (byte) 0x6c, (byte) 0x64, (byte) 0x61, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x6c,
+ (byte) 0x64, (byte) 0x61, (byte) 0x70, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x6f, (byte) 0x75, (byte) 0x3d, (byte) 0x61,
+ (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x74, (byte) 0x6f,
+ (byte) 0x6b, (byte) 0x65, (byte) 0x6e, (byte) 0x2d, (byte) 0x30, (byte) 0x33, (byte) 0x2c, (byte) 0x6f,
+ (byte) 0x3d, (byte) 0x41, (byte) 0x2d, (byte) 0x54, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2c, (byte) 0x63, (byte) 0x3d, (byte) 0x41, (byte) 0x54, (byte) 0x3f, (byte) 0x63, (byte) 0x65,
+ (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61, (byte) 0x74,
+ (byte) 0x65, (byte) 0x72, (byte) 0x65, (byte) 0x76, (byte) 0x6f, (byte) 0x63, (byte) 0x61, (byte) 0x74,
+ (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x6c, (byte) 0x69, (byte) 0x73, (byte) 0x74, (byte) 0x3f,
+ (byte) 0x62, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x3f, (byte) 0x6f, (byte) 0x62, (byte) 0x6a,
+ (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73,
+ (byte) 0x3d, (byte) 0x65, (byte) 0x69, (byte) 0x64, (byte) 0x43, (byte) 0x65, (byte) 0x72, (byte) 0x74,
+ (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f,
+ (byte) 0x6e, (byte) 0x41, (byte) 0x75, (byte) 0x74, (byte) 0x68, (byte) 0x6f, (byte) 0x72, (byte) 0x69,
+ (byte) 0x74, (byte) 0x79, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
+ (byte) 0x0e, (byte) 0x04, (byte) 0x0a, (byte) 0x04, (byte) 0x08, (byte) 0x4a, (byte) 0x43, (byte) 0x51,
+ (byte) 0x30, (byte) 0x45, (byte) 0xfc, (byte) 0x2a, (byte) 0x00, (byte) 0x30, (byte) 0x0e, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x04,
+ (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x04, (byte) 0xb0, (byte) 0x30, (byte) 0x09, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00,
+ (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03,
+ (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x31, (byte) 0xdc, (byte) 0xf3, (byte) 0x43,
+ (byte) 0x79, (byte) 0xdd, (byte) 0xa9, (byte) 0x2a, (byte) 0xdc, (byte) 0x21, (byte) 0xf9, (byte) 0xd9,
+ (byte) 0x8f, (byte) 0x9a, (byte) 0x4e, (byte) 0x01, (byte) 0x40, (byte) 0x9a, (byte) 0xf1, (byte) 0x14,
+ (byte) 0x8d, (byte) 0x3a, (byte) 0x5e, (byte) 0x88, (byte) 0x36, (byte) 0x45, (byte) 0x1f, (byte) 0x16,
+ (byte) 0x3e, (byte) 0xeb, (byte) 0xa2, (byte) 0xef, (byte) 0xbf, (byte) 0x55, (byte) 0xbd, (byte) 0x5e,
+ (byte) 0x0e, (byte) 0x19, (byte) 0xc7, (byte) 0x0c, (byte) 0xbd, (byte) 0xed, (byte) 0xdf, (byte) 0xb8,
+ (byte) 0x75, (byte) 0x4e, (byte) 0x6a, (byte) 0x3a, (byte) 0x9a, (byte) 0x10, (byte) 0xfa, (byte) 0x49,
+ (byte) 0xc1, (byte) 0xd2, (byte) 0x35, (byte) 0xc5, (byte) 0x9a, (byte) 0xd7, (byte) 0xf4, (byte) 0xf0,
+ (byte) 0xcd, (byte) 0x13, (byte) 0xd1, (byte) 0x24, (byte) 0x06, (byte) 0xf8, (byte) 0x1f, (byte) 0xea,
+ (byte) 0xd6, (byte) 0x7a, (byte) 0xcb, (byte) 0x4f, (byte) 0xb5, (byte) 0x3e, (byte) 0x6c, (byte) 0xb2,
+ (byte) 0xfc, (byte) 0xe3, (byte) 0xaa, (byte) 0x2b, (byte) 0x20, (byte) 0x91, (byte) 0xf5, (byte) 0x5b,
+ (byte) 0xf1, (byte) 0x94, (byte) 0x0e, (byte) 0x06, (byte) 0x0a, (byte) 0xfd, (byte) 0x25, (byte) 0x71,
+ (byte) 0x11, (byte) 0xfc, (byte) 0x84, (byte) 0x46, (byte) 0xef, (byte) 0x5b, (byte) 0x0b, (byte) 0xa4,
+ (byte) 0x4a, (byte) 0x5d, (byte) 0x42, (byte) 0x99, (byte) 0xc8, (byte) 0x4e, (byte) 0x51, (byte) 0xd8,
+ (byte) 0x63, (byte) 0xd1, (byte) 0xbd, (byte) 0x00, (byte) 0xa3, (byte) 0xdd, (byte) 0x8f, (byte) 0x12,
+ (byte) 0x42, (byte) 0xbe, (byte) 0xca, (byte) 0x15, (byte) 0x37, (byte) 0x4c, (byte) 0xd2, (byte) 0xc9,
+ (byte) 0xa7, (byte) 0x37, (byte) 0xb2, (byte) 0x76, (byte) 0xb7, (byte) 0x34, (byte) 0x92, (byte) 0x98,
+ (byte) 0x60, (byte) 0xe7, (byte) 0x3d, (byte) 0x55, (byte) 0xa2, (byte) 0x6c, (byte) 0xb6, (byte) 0x66,
+ (byte) 0x67, (byte) 0xe1, (byte) 0xe4, (byte) 0x8f, (byte) 0xe3, (byte) 0xa5, (byte) 0xb8, (byte) 0xb5,
+ (byte) 0xc8, (byte) 0x8f, (byte) 0x9e, (byte) 0xe3, (byte) 0xf1, (byte) 0xaa, (byte) 0x8e, (byte) 0xe6,
+ (byte) 0xe2, (byte) 0x47, (byte) 0x49, (byte) 0x3d, (byte) 0xbe, (byte) 0x8c, (byte) 0xdd, (byte) 0xce,
+ (byte) 0x8d, (byte) 0x52, (byte) 0xac, (byte) 0xb9, (byte) 0x83, (byte) 0xe9, (byte) 0x9d, (byte) 0x98,
+ (byte) 0x7b, (byte) 0xda, (byte) 0x2b, (byte) 0xbc, (byte) 0x83, (byte) 0xcb, (byte) 0x74, (byte) 0x64,
+ (byte) 0x17, (byte) 0x4c, (byte) 0x33, (byte) 0xbb, (byte) 0x88, (byte) 0xc2, (byte) 0xdd, (byte) 0x08,
+ (byte) 0x69, (byte) 0xd8, (byte) 0xa2, (byte) 0xac, (byte) 0x95, (byte) 0x71, (byte) 0xd3, (byte) 0xf8,
+ (byte) 0xc9, (byte) 0xd1, (byte) 0xd6, (byte) 0x0e, (byte) 0xc3, (byte) 0x67, (byte) 0xa1, (byte) 0xdb,
+ (byte) 0xca, (byte) 0x58, (byte) 0xaa, (byte) 0x4b, (byte) 0xec, (byte) 0x37, (byte) 0x46, (byte) 0x73,
+ (byte) 0xc3, (byte) 0xa3, (byte) 0x7b, (byte) 0x1e, (byte) 0xdd, (byte) 0xf9, (byte) 0xb3, (byte) 0xbb,
+ (byte) 0xe0, (byte) 0x16, (byte) 0x39, (byte) 0xaf, (byte) 0xa0, (byte) 0x19, (byte) 0x9e, (byte) 0x89,
+ (byte) 0x37, (byte) 0x1e, (byte) 0x6e, (byte) 0x41, (byte) 0x59, (byte) 0xe1, (byte) 0x86, (byte) 0xea,
+ (byte) 0x0b, (byte) 0x39, (byte) 0x03, (byte) 0x89, (byte) 0xd2, (byte) 0xba, (byte) 0xd5, (byte) 0x0c,
+ (byte) 0x84, (byte) 0x09, (byte) 0xdd, (byte) 0xc7, (byte) 0x00, (byte) 0x2c, (byte) 0x2e, (byte) 0x1a,
+ (byte) 0x69, (byte) 0xeb, (byte) 0xdf, (byte) 0xb1
+ };
+
+
+ protected byte[] EF_C_X509_CH_AUT = new byte[2000];
+
+ public STARCOSApplGewoehnlicheSignatur(STARCOSCardChannelEmul channel) {
+ super(channel);
+ // Files
+ System.arraycopy(C_X509_CH_AUT, 0, EF_C_X509_CH_AUT, 0, C_X509_CH_AUT.length);
+ putFile(new File(FID_EF_C_X509_CH_AUT, EF_C_X509_CH_AUT, FCI_EF_C_X509_CH_AUT));
+ }
+
+ @Override
+ public byte[] getAID() {
+ return AID_GewoehnlicheSignatur;
+ }
+
+ @Override
+ public byte[] getFID() {
+ return FID_GewoehnlicheSignatur;
+ }
+
+ @Override
+ public byte[] getFCI() {
+ return FCI;
+ }
+
+ public void clearCert() {
+ Arrays.fill(EF_C_X509_CH_AUT, (byte) 0x00);
+ }
+
+ @Override
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel) throws CardException {
+
+ checkINS(command, 0x22);
+
+ switch (command.getP2()) {
+ case 0xA4:
+ switch (command.getP1()) {
+ case 0x41:
+ // INTERNAL AUTHENTICATE
+ case 0x81:
+ // EXTERNAL AUTHENTICATE
+ }
+ case 0xB6:
+ switch (command.getP1()) {
+ case 0x41: {
+ // PSO - COMPUTE DIGITAL SIGNATURE
+ byte[] dst = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80,
+ (byte) 0x02, (byte) 0x00, (byte) 0x89, (byte) 0x03, (byte) 0x13, (byte) 0x35, (byte) 0x10};
+ if (Arrays.equals(dst, command.getData())) {
+ securityEnv = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80});
+ }
+ }
+ case 0x81:
+ // PSO - VERIFY DGITAL SIGNATURE
+ }
+ case 0xB8:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO � DECIPHER
+ case 0x81:
+ // PSO � ENCIPHER
+ }
+ default:
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+
+ }
+
+ @Override
+ public ResponseAPDU cmdPERFORM_SECURITY_OPERATION(CommandAPDU command, CardChannelEmul channel) throws CardException {
+
+ checkINS(command, 0x2A);
+
+ if (command.getP1() == 0x90 && command.getP2() == 0xA0) {
+
+ // HASH
+ byte[] data = command.getData();
+ if (data[0] == (byte) 0x90 && data[1] == (byte) 0x14) {
+ hash = Arrays.copyOfRange(data, 2, data.length);
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ throw new CardException("HASH command only supports complete hash.");
+ }
+
+ } else if (command.getP1() == 0x9E && command.getP2() == 0x9A) {
+
+ // COMPUTE DIGITAL SIGNATURE
+ if (securityEnv == null) {
+ // No security environment
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ if (hash == null) {
+ // Command sequence not correct
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x03});
+ }
+ if (hash.length != 20) {
+ // Invalid hash length
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80});
+ }
+ STARCOSCardChannelEmul c = (STARCOSCardChannelEmul) channel;
+ if (c.globalPins.get(STARCOSCardChannelEmul.KID_PIN_Glob).state != PIN.STATE_PIN_VERIFIED) {
+ // Security Status not satisfied
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+
+ byte[] signature = new byte[48];
+
+ // TODO replace by signature creation
+ Random random = new Random();
+ random.nextBytes(signature);
+
+ byte[] response = new byte[signature.length + 2];
+ System.arraycopy(signature, 0, response, 0, signature.length);
+ response[signature.length] = (byte) 0x90;
+ response[signature.length + 1] = (byte) 0x00;
+
+ hash = null;
+
+ return new ResponseAPDU(response);
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00});
+ }
+
+ }
+
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java
new file mode 100644
index 00000000..b7835a43
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java
@@ -0,0 +1,160 @@
+/*
+* 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.starcos;
+
+import java.util.Arrays;
+
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.File;
+
+@SuppressWarnings("restriction")
+public class STARCOSApplInfobox extends STARCOSAppl {
+
+ public static final byte[] IDLINK = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x11, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x0c,
+ (byte) 0x26, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f,
+ (byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x7a,
+ (byte) 0x6d, (byte) 0x72, (byte) 0x2f, (byte) 0x70, (byte) 0x65, (byte) 0x72, (byte) 0x73, (byte) 0x62,
+ (byte) 0x32, (byte) 0x30, (byte) 0x34, (byte) 0x2e, (byte) 0x78, (byte) 0x73, (byte) 0x6c, (byte) 0x0c,
+ (byte) 0x29, (byte) 0x73, (byte) 0x7a, (byte) 0x72, (byte) 0x2e, (byte) 0x62, (byte) 0x6d, (byte) 0x69,
+ (byte) 0x2e, (byte) 0x67, (byte) 0x76, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2d, (byte) 0x41,
+ (byte) 0x73, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e,
+ (byte) 0x49, (byte) 0x44, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x36, (byte) 0x33, (byte) 0x35,
+ (byte) 0x36, (byte) 0x33, (byte) 0x36, (byte) 0x36, (byte) 0x37, (byte) 0x39, (byte) 0x39, (byte) 0x39,
+ (byte) 0x31, (byte) 0x39, (byte) 0x0c, (byte) 0x19, (byte) 0x32, (byte) 0x30, (byte) 0x30, (byte) 0x39,
+ (byte) 0x2d, (byte) 0x30, (byte) 0x33, (byte) 0x2d, (byte) 0x30, (byte) 0x36, (byte) 0x54, (byte) 0x31,
+ (byte) 0x36, (byte) 0x3a, (byte) 0x31, (byte) 0x39, (byte) 0x3a, (byte) 0x32, (byte) 0x36, (byte) 0x2b,
+ (byte) 0x30, (byte) 0x31, (byte) 0x3a, (byte) 0x30, (byte) 0x30, (byte) 0xa0, (byte) 0x42, (byte) 0x30,
+ (byte) 0x40, (byte) 0x0c, (byte) 0x18, (byte) 0x45, (byte) 0x68, (byte) 0x42, (byte) 0x53, (byte) 0x36,
+ (byte) 0x54, (byte) 0x6f, (byte) 0x31, (byte) 0x49, (byte) 0x6c, (byte) 0x54, (byte) 0x4b, (byte) 0x4f,
+ (byte) 0x4a, (byte) 0x45, (byte) 0x39, (byte) 0x75, (byte) 0x62, (byte) 0x74, (byte) 0x48, (byte) 0x69,
+ (byte) 0x51, (byte) 0x3d, (byte) 0x3d, (byte) 0x0c, (byte) 0x0a, (byte) 0x58, (byte) 0x58, (byte) 0x58,
+ (byte) 0xc5, (byte) 0x90, (byte) 0x7a, (byte) 0x67, (byte) 0xc3, (byte) 0xbc, (byte) 0x72, (byte) 0x0c,
+ (byte) 0x0c, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x54, (byte) 0xc3, (byte) 0xbc, (byte) 0x7a,
+ (byte) 0x65, (byte) 0x6b, (byte) 0xc3, (byte) 0xa7, (byte) 0x69, (byte) 0x0c, (byte) 0x0a, (byte) 0x31,
+ (byte) 0x39, (byte) 0x37, (byte) 0x33, (byte) 0x2d, (byte) 0x30, (byte) 0x36, (byte) 0x2d, (byte) 0x30,
+ (byte) 0x34, (byte) 0x30, (byte) 0x0a, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x00,
+ (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x82, (byte) 0x01,
+ (byte) 0x01, (byte) 0x00, (byte) 0x9f, (byte) 0xa5, (byte) 0x68, (byte) 0xa9, (byte) 0x14, (byte) 0x4c,
+ (byte) 0xa4, (byte) 0x5d, (byte) 0x9d, (byte) 0x09, (byte) 0x99, (byte) 0x2e, (byte) 0xe7, (byte) 0x45,
+ (byte) 0x2e, (byte) 0x42, (byte) 0x49, (byte) 0x02, (byte) 0x16, (byte) 0xd9, (byte) 0xcb, (byte) 0x90,
+ (byte) 0x43, (byte) 0x27, (byte) 0x03, (byte) 0x43, (byte) 0x6d, (byte) 0xb4, (byte) 0x8c, (byte) 0xdc,
+ (byte) 0x1c, (byte) 0x77, (byte) 0xd4, (byte) 0x2e, (byte) 0xa1, (byte) 0x40, (byte) 0xe7, (byte) 0xe0,
+ (byte) 0x03, (byte) 0x60, (byte) 0x15, (byte) 0xf7, (byte) 0xdb, (byte) 0x03, (byte) 0x5e, (byte) 0xca,
+ (byte) 0xe4, (byte) 0x35, (byte) 0xba, (byte) 0x2b, (byte) 0xfd, (byte) 0xe6, (byte) 0xb8, (byte) 0xd8,
+ (byte) 0xb7, (byte) 0x2a, (byte) 0x80, (byte) 0xdd, (byte) 0x38, (byte) 0xe0, (byte) 0x8a, (byte) 0x69,
+ (byte) 0xad, (byte) 0x67, (byte) 0x60, (byte) 0x65, (byte) 0x42, (byte) 0xc9, (byte) 0x41, (byte) 0x60,
+ (byte) 0x94, (byte) 0xde, (byte) 0x84, (byte) 0x54, (byte) 0xad, (byte) 0xb3, (byte) 0xf4, (byte) 0xf7,
+ (byte) 0x44, (byte) 0xd5, (byte) 0xf3, (byte) 0xd3, (byte) 0xb6, (byte) 0x87, (byte) 0x8a, (byte) 0x22,
+ (byte) 0x38, (byte) 0x00, (byte) 0xcb, (byte) 0xa4, (byte) 0x4f, (byte) 0x96, (byte) 0xc2, (byte) 0x28,
+ (byte) 0xc2, (byte) 0x8d, (byte) 0x91, (byte) 0x95, (byte) 0xb4, (byte) 0xea, (byte) 0x00, (byte) 0x59,
+ (byte) 0x2e, (byte) 0xec, (byte) 0x78, (byte) 0xd8, (byte) 0x0f, (byte) 0x26, (byte) 0x04, (byte) 0xee,
+ (byte) 0xed, (byte) 0x13, (byte) 0xbf, (byte) 0x81, (byte) 0x68, (byte) 0x81, (byte) 0x43, (byte) 0xbe,
+ (byte) 0x15, (byte) 0x0e, (byte) 0xba, (byte) 0xf9, (byte) 0x6a, (byte) 0x18, (byte) 0xeb, (byte) 0x95,
+ (byte) 0xad, (byte) 0xb4, (byte) 0x0f, (byte) 0x3c, (byte) 0x94, (byte) 0x63, (byte) 0x32, (byte) 0x81,
+ (byte) 0x90, (byte) 0xcf, (byte) 0x3f, (byte) 0x95, (byte) 0xff, (byte) 0x8d, (byte) 0x86, (byte) 0xed,
+ (byte) 0xe4, (byte) 0x75, (byte) 0xd5, (byte) 0x09, (byte) 0x32, (byte) 0x17, (byte) 0x38, (byte) 0xb2,
+ (byte) 0x68, (byte) 0x35, (byte) 0x49, (byte) 0x8c, (byte) 0xa6, (byte) 0xd0, (byte) 0x3e, (byte) 0xde,
+ (byte) 0x6e, (byte) 0x47, (byte) 0x68, (byte) 0xbf, (byte) 0x98, (byte) 0x33, (byte) 0xae, (byte) 0x59,
+ (byte) 0x9f, (byte) 0xe0, (byte) 0x19, (byte) 0x9b, (byte) 0x5b, (byte) 0x1b, (byte) 0x8f, (byte) 0x74,
+ (byte) 0xd2, (byte) 0x9c, (byte) 0x01, (byte) 0x1a, (byte) 0xdf, (byte) 0xaf, (byte) 0xf8, (byte) 0x96,
+ (byte) 0x91, (byte) 0xcb, (byte) 0xf8, (byte) 0xbf, (byte) 0x06, (byte) 0xc7, (byte) 0xd5, (byte) 0x17,
+ (byte) 0x95, (byte) 0xef, (byte) 0xc5, (byte) 0x97, (byte) 0x37, (byte) 0x1b, (byte) 0xb0, (byte) 0xa1,
+ (byte) 0x4f, (byte) 0x9f, (byte) 0x01, (byte) 0x82, (byte) 0x90, (byte) 0x4a, (byte) 0x6a, (byte) 0x04,
+ (byte) 0xdb, (byte) 0x31, (byte) 0x1a, (byte) 0x58, (byte) 0xeb, (byte) 0xcd, (byte) 0x68, (byte) 0xe3,
+ (byte) 0x68, (byte) 0x0b, (byte) 0xa0, (byte) 0x11, (byte) 0x44, (byte) 0x08, (byte) 0xa0, (byte) 0x5c,
+ (byte) 0xfc, (byte) 0x61, (byte) 0x15, (byte) 0x1f, (byte) 0xbb, (byte) 0x22, (byte) 0x87, (byte) 0x18,
+ (byte) 0xa3, (byte) 0x07, (byte) 0x9b, (byte) 0x0d, (byte) 0x13, (byte) 0x7c, (byte) 0xff, (byte) 0x30,
+ (byte) 0xcf, (byte) 0xf3, (byte) 0xaf, (byte) 0xe4, (byte) 0x45, (byte) 0x05, (byte) 0xa0, (byte) 0x8e,
+ (byte) 0x6b, (byte) 0xef, (byte) 0x70, (byte) 0xf5, (byte) 0x4b, (byte) 0x68, (byte) 0x8f, (byte) 0x61,
+ (byte) 0xd6, (byte) 0xf5, (byte) 0xa0, (byte) 0x17, (byte) 0x03, (byte) 0x15, (byte) 0x00, (byte) 0x8e,
+ (byte) 0xa8, (byte) 0xdf, (byte) 0xa9, (byte) 0x77, (byte) 0xfd, (byte) 0x9b, (byte) 0x4b, (byte) 0x91,
+ (byte) 0x89, (byte) 0x34, (byte) 0x84, (byte) 0xf3, (byte) 0x24, (byte) 0xb2, (byte) 0x5a, (byte) 0x39,
+ (byte) 0xa9, (byte) 0xf2, (byte) 0x17, (byte) 0xa1, (byte) 0x17, (byte) 0x03, (byte) 0x15, (byte) 0x00,
+ (byte) 0xdb, (byte) 0xa2, (byte) 0xfd, (byte) 0xa4, (byte) 0xe7, (byte) 0x65, (byte) 0x2e, (byte) 0x7e,
+ (byte) 0xb0, (byte) 0xc8, (byte) 0xfa, (byte) 0x4d, (byte) 0x13, (byte) 0x28, (byte) 0xdf, (byte) 0xb1,
+ (byte) 0x58, (byte) 0x3b, (byte) 0x9e, (byte) 0x29, (byte) 0xa2, (byte) 0x17, (byte) 0x03, (byte) 0x15,
+ (byte) 0x00, (byte) 0x68, (byte) 0xa0, (byte) 0x17, (byte) 0x18, (byte) 0xb7, (byte) 0xb3, (byte) 0xc3,
+ (byte) 0x60, (byte) 0x77, (byte) 0x82, (byte) 0x8d, (byte) 0xf1, (byte) 0x5e, (byte) 0x10, (byte) 0xc3,
+ (byte) 0x2d, (byte) 0x78, (byte) 0x2c, (byte) 0x11, (byte) 0x0b
+ };
+
+ private static byte[] FCP = new byte[] { (byte) 0x6f, (byte) 0x14,
+ (byte) 0x84, (byte) 0x08, (byte) 0xd0, (byte) 0x40, (byte) 0x00,
+ (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x18, (byte) 0x01,
+ (byte) 0xa5, (byte) 0x08, (byte) 0x53, (byte) 0x02, (byte) 0x01,
+ (byte) 0x11, (byte) 0x54, (byte) 0x02, (byte) 0x01, (byte) 0x00 };
+
+ protected static byte[] FID_EF_IdentityLink = new byte[] { (byte) 0xef, (byte) 0x01 };
+
+ protected static byte[] FCP_EF_IdentityLink = new byte[] { (byte) 0x62,
+ (byte) 0x16, (byte) 0x80, (byte) 0x02, (byte) 0x04, (byte) 0x00,
+ (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x83, (byte) 0x02,
+ (byte) 0xef, (byte) 0x01, (byte) 0x88, (byte) 0x01, (byte) 0x08,
+ (byte) 0x8a, (byte) 0x01, (byte) 0x05, (byte) 0xa1, (byte) 0x03,
+ (byte) 0x8b, (byte) 0x01, (byte) 0x02 };
+
+ protected static byte[] EF_IdentityLink = new byte[1500];
+
+ public STARCOSApplInfobox(STARCOSCardChannelEmul channel) {
+ super(channel);
+ System.arraycopy(IDLINK, 0, EF_IdentityLink, 0, IDLINK.length);
+ putFile(new File(FID_EF_IdentityLink, EF_IdentityLink, FCP_EF_IdentityLink, 0x01));
+ }
+
+ @Override
+ public byte[] getAID() {
+ return AID_Infobox;
+ }
+
+ @Override
+ public byte[] getFID() {
+ return FID_Infobox;
+ }
+
+ @Override
+ public byte[] getFCI() {
+ return FCP;
+ }
+
+ public void clearInfobox() {
+ Arrays.fill(EF_IdentityLink, (byte) 0x00);
+ }
+
+ public void setInfoboxHeader(byte b) {
+ EF_IdentityLink[0] = b;
+ }
+
+ @Override
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel)
+ throws CardException {
+ throw new CardException("Not supported.");
+ }
+
+ @Override
+ public ResponseAPDU cmdPERFORM_SECURITY_OPERATION(CommandAPDU command, CardChannelEmul channel)
+ throws CardException {
+ throw new CardException("Not supported.");
+ }
+
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java
new file mode 100644
index 00000000..9fb5ad37
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java
@@ -0,0 +1,347 @@
+/*
+* 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.starcos;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public class STARCOSApplSichereSignatur extends STARCOSAppl {
+
+ private static byte[] FCI = new byte[] { (byte) 0x6f, (byte) 0x16,
+ (byte) 0x84, (byte) 0x08, (byte) 0xd0, (byte) 0x40, (byte) 0x00,
+ (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x12, (byte) 0x01,
+ (byte) 0xa5, (byte) 0x0a, (byte) 0x53, (byte) 0x02, (byte) 0x01,
+ (byte) 0x10, (byte) 0x54, (byte) 0x04, (byte) 0x01, (byte) 0x00,
+ (byte) 0x03, (byte) 0x00 };
+
+ protected static byte[] FID_EF_C_X509_CH_DS = new byte[] { (byte) 0xc0,
+ (byte) 0x00 };
+
+ protected static byte[] FCI_EF_C_X509_CH_DS = new byte[] { (byte) 0x62,
+ (byte) 0x16, (byte) 0x80, (byte) 0x02, (byte) 0x04, (byte) 0xef,
+ (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x83, (byte) 0x02,
+ (byte) 0xc0, (byte) 0x00, (byte) 0x88, (byte) 0x01, (byte) 0x08,
+ (byte) 0x8a, (byte) 0x01, (byte) 0x05, (byte) 0xa1, (byte) 0x03,
+ (byte) 0x8b, (byte) 0x01, (byte) 0x0e };
+
+ protected static byte[] C_X509_CH_DS = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0xeb, (byte) 0x30, (byte) 0x82, (byte) 0x03, (byte) 0xd3,
+ (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x03, (byte) 0x02,
+ (byte) 0x06, (byte) 0x5e, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xa1, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
+ (byte) 0x54, (byte) 0x31, (byte) 0x48, (byte) 0x30, (byte) 0x46, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x3f, (byte) 0x41, (byte) 0x2d, (byte) 0x54, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x47, (byte) 0x65, (byte) 0x73, (byte) 0x2e,
+ (byte) 0x20, (byte) 0x66, (byte) 0x2e, (byte) 0x20, (byte) 0x53, (byte) 0x69, (byte) 0x63, (byte) 0x68,
+ (byte) 0x65, (byte) 0x72, (byte) 0x68, (byte) 0x65, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x73,
+ (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x6d, (byte) 0x65, (byte) 0x20, (byte) 0x69,
+ (byte) 0x6d, (byte) 0x20, (byte) 0x65, (byte) 0x6c, (byte) 0x65, (byte) 0x6b, (byte) 0x74, (byte) 0x72,
+ (byte) 0x2e, (byte) 0x20, (byte) 0x44, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x6e, (byte) 0x76,
+ (byte) 0x65, (byte) 0x72, (byte) 0x6b, (byte) 0x65, (byte) 0x68, (byte) 0x72, (byte) 0x20, (byte) 0x47,
+ (byte) 0x6d, (byte) 0x62, (byte) 0x48, (byte) 0x31, (byte) 0x23, (byte) 0x30, (byte) 0x21, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x1a, (byte) 0x61, (byte) 0x2d,
+ (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65,
+ (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2d, (byte) 0x53, (byte) 0x69, (byte) 0x67, (byte) 0x2d, (byte) 0x30, (byte) 0x32,
+ (byte) 0x31, (byte) 0x23, (byte) 0x30, (byte) 0x21, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x03, (byte) 0x0c, (byte) 0x1a, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67,
+ (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75,
+ (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x53,
+ (byte) 0x69, (byte) 0x67, (byte) 0x2d, (byte) 0x30, (byte) 0x32, (byte) 0x30, (byte) 0x1e, (byte) 0x17,
+ (byte) 0x0d, (byte) 0x30, (byte) 0x39, (byte) 0x30, (byte) 0x33, (byte) 0x30, (byte) 0x36, (byte) 0x31,
+ (byte) 0x35, (byte) 0x32, (byte) 0x32, (byte) 0x33, (byte) 0x37, (byte) 0x5a, (byte) 0x17, (byte) 0x0d,
+ (byte) 0x31, (byte) 0x32, (byte) 0x30, (byte) 0x33, (byte) 0x30, (byte) 0x36, (byte) 0x31, (byte) 0x35,
+ (byte) 0x32, (byte) 0x32, (byte) 0x33, (byte) 0x37, (byte) 0x5a, (byte) 0x30, (byte) 0x72, (byte) 0x31,
+ (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+ (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x54, (byte) 0x31, (byte) 0x20, (byte) 0x30, (byte) 0x1e,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x17, (byte) 0x58,
+ (byte) 0x58, (byte) 0x58, (byte) 0xc5, (byte) 0x90, (byte) 0x7a, (byte) 0x67, (byte) 0xc3, (byte) 0xbc,
+ (byte) 0x72, (byte) 0x20, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x54, (byte) 0xc3, (byte) 0xbc,
+ (byte) 0x7a, (byte) 0x65, (byte) 0x6b, (byte) 0xc3, (byte) 0xa7, (byte) 0x69, (byte) 0x31, (byte) 0x15,
+ (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x04, (byte) 0x0c,
+ (byte) 0x0c, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x54, (byte) 0xc3, (byte) 0xbc, (byte) 0x7a,
+ (byte) 0x65, (byte) 0x6b, (byte) 0xc3, (byte) 0xa7, (byte) 0x69, (byte) 0x31, (byte) 0x13, (byte) 0x30,
+ (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x2a, (byte) 0x0c, (byte) 0x0a,
+ (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0xc5, (byte) 0x90, (byte) 0x7a, (byte) 0x67, (byte) 0xc3,
+ (byte) 0xbc, (byte) 0x72, (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x04, (byte) 0x05, (byte) 0x13, (byte) 0x0c, (byte) 0x37, (byte) 0x30, (byte) 0x34,
+ (byte) 0x38, (byte) 0x37, (byte) 0x31, (byte) 0x30, (byte) 0x35, (byte) 0x30, (byte) 0x30, (byte) 0x30,
+ (byte) 0x38, (byte) 0x30, (byte) 0x49, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
+ (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08,
+ (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x01,
+ (byte) 0x03, (byte) 0x32, (byte) 0x00, (byte) 0x04, (byte) 0xde, (byte) 0x75, (byte) 0x22, (byte) 0x4c,
+ (byte) 0xc4, (byte) 0xd4, (byte) 0x14, (byte) 0x16, (byte) 0x48, (byte) 0x4a, (byte) 0x65, (byte) 0x9d,
+ (byte) 0x5a, (byte) 0x39, (byte) 0x71, (byte) 0x11, (byte) 0x1c, (byte) 0x33, (byte) 0x7e, (byte) 0x7f,
+ (byte) 0xb4, (byte) 0x06, (byte) 0x33, (byte) 0x74, (byte) 0xe6, (byte) 0xf3, (byte) 0xc2, (byte) 0x56,
+ (byte) 0x46, (byte) 0x18, (byte) 0x39, (byte) 0xb9, (byte) 0xc4, (byte) 0x47, (byte) 0x84, (byte) 0xf5,
+ (byte) 0x46, (byte) 0x41, (byte) 0x60, (byte) 0x78, (byte) 0x81, (byte) 0x45, (byte) 0x4a, (byte) 0x0f,
+ (byte) 0x67, (byte) 0x77, (byte) 0x77, (byte) 0xb2, (byte) 0xa3, (byte) 0x82, (byte) 0x02, (byte) 0x33,
+ (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x2f, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x0c, (byte) 0x30, (byte) 0x0a, (byte) 0x80,
+ (byte) 0x08, (byte) 0x46, (byte) 0x06, (byte) 0x9f, (byte) 0x8e, (byte) 0x41, (byte) 0x8e, (byte) 0x15,
+ (byte) 0xbd, (byte) 0x30, (byte) 0x27, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x01, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff,
+ (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x30, (byte) 0x08, (byte) 0x06, (byte) 0x06,
+ (byte) 0x04, (byte) 0x00, (byte) 0x8e, (byte) 0x46, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0a,
+ (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07,
+ (byte) 0x0b, (byte) 0x01, (byte) 0x30, (byte) 0x81, (byte) 0x84, (byte) 0x06, (byte) 0x08, (byte) 0x2b,
+ (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x01, (byte) 0x01, (byte) 0x04,
+ (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x30, (byte) 0x2c, (byte) 0x06, (byte) 0x08, (byte) 0x2b,
+ (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30, (byte) 0x01, (byte) 0x86,
+ (byte) 0x20, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f,
+ (byte) 0x6f, (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x6f, (byte) 0x63, (byte) 0x73,
+ (byte) 0x70, (byte) 0x30, (byte) 0x46, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30, (byte) 0x02, (byte) 0x86, (byte) 0x3a, (byte) 0x68,
+ (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x77, (byte) 0x77,
+ (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73,
+ (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x63, (byte) 0x65, (byte) 0x72,
+ (byte) 0x74, (byte) 0x73, (byte) 0x2f, (byte) 0x61, (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67,
+ (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72, (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75,
+ (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x53,
+ (byte) 0x69, (byte) 0x67, (byte) 0x2d, (byte) 0x30, (byte) 0x32, (byte) 0x2e, (byte) 0x63, (byte) 0x72,
+ (byte) 0x74, (byte) 0x30, (byte) 0x81, (byte) 0x92, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
+ (byte) 0x20, (byte) 0x04, (byte) 0x81, (byte) 0x8a, (byte) 0x30, (byte) 0x81, (byte) 0x87, (byte) 0x30,
+ (byte) 0x7b, (byte) 0x06, (byte) 0x06, (byte) 0x2a, (byte) 0x28, (byte) 0x00, (byte) 0x11, (byte) 0x01,
+ (byte) 0x03, (byte) 0x30, (byte) 0x71, (byte) 0x30, (byte) 0x35, (byte) 0x06, (byte) 0x08, (byte) 0x2b,
+ (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x02, (byte) 0x01, (byte) 0x16,
+ (byte) 0x29, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f,
+ (byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x64,
+ (byte) 0x6f, (byte) 0x63, (byte) 0x73, (byte) 0x2f, (byte) 0x63, (byte) 0x70, (byte) 0x2f, (byte) 0x61,
+ (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x74, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x30, (byte) 0x38, (byte) 0x06, (byte) 0x08, (byte) 0x2b, (byte) 0x06,
+ (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x02, (byte) 0x02, (byte) 0x30, (byte) 0x2c,
+ (byte) 0x1a, (byte) 0x2a, (byte) 0x44, (byte) 0x69, (byte) 0x65, (byte) 0x73, (byte) 0x65, (byte) 0x73,
+ (byte) 0x20, (byte) 0x5a, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69,
+ (byte) 0x6b, (byte) 0x61, (byte) 0x74, (byte) 0x20, (byte) 0x64, (byte) 0x69, (byte) 0x65, (byte) 0x6e,
+ (byte) 0x74, (byte) 0x20, (byte) 0x6e, (byte) 0x75, (byte) 0x72, (byte) 0x20, (byte) 0x7a, (byte) 0x75,
+ (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x7a, (byte) 0x77, (byte) 0x65,
+ (byte) 0x63, (byte) 0x6b, (byte) 0x65, (byte) 0x6e, (byte) 0x30, (byte) 0x08, (byte) 0x06, (byte) 0x06,
+ (byte) 0x04, (byte) 0x00, (byte) 0x8b, (byte) 0x30, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x81,
+ (byte) 0xa4, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x1f, (byte) 0x04, (byte) 0x81,
+ (byte) 0x9c, (byte) 0x30, (byte) 0x81, (byte) 0x99, (byte) 0x30, (byte) 0x81, (byte) 0x96, (byte) 0xa0,
+ (byte) 0x81, (byte) 0x93, (byte) 0xa0, (byte) 0x81, (byte) 0x90, (byte) 0x86, (byte) 0x81, (byte) 0x8d,
+ (byte) 0x6c, (byte) 0x64, (byte) 0x61, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x6c,
+ (byte) 0x64, (byte) 0x61, (byte) 0x70, (byte) 0x2d, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x61, (byte) 0x2d, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x61, (byte) 0x74, (byte) 0x2f, (byte) 0x6f, (byte) 0x75, (byte) 0x3d, (byte) 0x61,
+ (byte) 0x2d, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x2d, (byte) 0x50, (byte) 0x72,
+ (byte) 0x65, (byte) 0x6d, (byte) 0x69, (byte) 0x75, (byte) 0x6d, (byte) 0x2d, (byte) 0x54, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x2d, (byte) 0x53, (byte) 0x69, (byte) 0x67, (byte) 0x2d, (byte) 0x30,
+ (byte) 0x32, (byte) 0x2c, (byte) 0x6f, (byte) 0x3d, (byte) 0x41, (byte) 0x2d, (byte) 0x54, (byte) 0x72,
+ (byte) 0x75, (byte) 0x73, (byte) 0x74, (byte) 0x2c, (byte) 0x63, (byte) 0x3d, (byte) 0x41, (byte) 0x54,
+ (byte) 0x3f, (byte) 0x63, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69,
+ (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x65, (byte) 0x76, (byte) 0x6f,
+ (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x6c, (byte) 0x69,
+ (byte) 0x73, (byte) 0x74, (byte) 0x3f, (byte) 0x62, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x3f,
+ (byte) 0x6f, (byte) 0x62, (byte) 0x6a, (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x63, (byte) 0x6c,
+ (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x3d, (byte) 0x65, (byte) 0x69, (byte) 0x64, (byte) 0x43,
+ (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61,
+ (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x41, (byte) 0x75, (byte) 0x74, (byte) 0x68,
+ (byte) 0x6f, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x79, (byte) 0x30, (byte) 0x11, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x0a, (byte) 0x04, (byte) 0x08,
+ (byte) 0x47, (byte) 0x64, (byte) 0x6e, (byte) 0xbb, (byte) 0x92, (byte) 0xa0, (byte) 0xf6, (byte) 0xf4,
+ (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0f, (byte) 0x01,
+ (byte) 0x01, (byte) 0xff, (byte) 0x04, (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x06, (byte) 0xc0,
+ (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04,
+ (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+ (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x06,
+ (byte) 0x63, (byte) 0x76, (byte) 0x0a, (byte) 0xd5, (byte) 0x54, (byte) 0xfa, (byte) 0x51, (byte) 0x2a,
+ (byte) 0xb0, (byte) 0x41, (byte) 0xdc, (byte) 0xa4, (byte) 0x9b, (byte) 0x52, (byte) 0x1c, (byte) 0x0e,
+ (byte) 0x1d, (byte) 0x65, (byte) 0x46, (byte) 0x2b, (byte) 0xa3, (byte) 0xcd, (byte) 0xd4, (byte) 0x46,
+ (byte) 0x36, (byte) 0x40, (byte) 0xc3, (byte) 0x49, (byte) 0xe8, (byte) 0xa4, (byte) 0xdc, (byte) 0x01,
+ (byte) 0xde, (byte) 0x70, (byte) 0x97, (byte) 0x31, (byte) 0xb0, (byte) 0xcd, (byte) 0xdf, (byte) 0x69,
+ (byte) 0xf8, (byte) 0xc3, (byte) 0x83, (byte) 0xee, (byte) 0xc6, (byte) 0xed, (byte) 0xe3, (byte) 0x18,
+ (byte) 0x1a, (byte) 0x80, (byte) 0xc1, (byte) 0x30, (byte) 0xa9, (byte) 0xd6, (byte) 0xb1, (byte) 0xb8,
+ (byte) 0xa8, (byte) 0xe0, (byte) 0x3d, (byte) 0xb1, (byte) 0x8e, (byte) 0x2c, (byte) 0xc9, (byte) 0xa6,
+ (byte) 0x05, (byte) 0x6e, (byte) 0x4a, (byte) 0xd2, (byte) 0xb2, (byte) 0x03, (byte) 0xa4, (byte) 0x2b,
+ (byte) 0xa2, (byte) 0xad, (byte) 0xad, (byte) 0xe5, (byte) 0xba, (byte) 0x0d, (byte) 0x54, (byte) 0x8d,
+ (byte) 0x92, (byte) 0x51, (byte) 0xda, (byte) 0x58, (byte) 0xed, (byte) 0xd3, (byte) 0x8d, (byte) 0x61,
+ (byte) 0xa1, (byte) 0xfc, (byte) 0x49, (byte) 0xf6, (byte) 0x80, (byte) 0xdb, (byte) 0x65, (byte) 0x92,
+ (byte) 0xe0, (byte) 0xd5, (byte) 0x23, (byte) 0x69, (byte) 0x0f, (byte) 0x38, (byte) 0x11, (byte) 0x61,
+ (byte) 0x1e, (byte) 0xcd, (byte) 0xa2, (byte) 0x8e, (byte) 0x68, (byte) 0xec, (byte) 0x70, (byte) 0xfb,
+ (byte) 0x55, (byte) 0x95, (byte) 0xcb, (byte) 0xb4, (byte) 0x18, (byte) 0x6b, (byte) 0x3a, (byte) 0x25,
+ (byte) 0x4a, (byte) 0x3e, (byte) 0x07, (byte) 0xb0, (byte) 0x18, (byte) 0x26, (byte) 0x51, (byte) 0x39,
+ (byte) 0x46, (byte) 0xfa, (byte) 0xe2, (byte) 0xae, (byte) 0xe6, (byte) 0x1c, (byte) 0xd2, (byte) 0xcb,
+ (byte) 0x28, (byte) 0xa1, (byte) 0x8b, (byte) 0x56, (byte) 0xbb, (byte) 0xe9, (byte) 0x6c, (byte) 0xf7,
+ (byte) 0x0b, (byte) 0x84, (byte) 0xdd, (byte) 0x7f, (byte) 0x64, (byte) 0x8b, (byte) 0x43, (byte) 0x93,
+ (byte) 0x62, (byte) 0x39, (byte) 0xfb, (byte) 0x91, (byte) 0xfa, (byte) 0x3a, (byte) 0x57, (byte) 0x56,
+ (byte) 0x4a, (byte) 0xaa, (byte) 0x99, (byte) 0x1e, (byte) 0x9b, (byte) 0xcc, (byte) 0xa4, (byte) 0xc0,
+ (byte) 0x18, (byte) 0x46, (byte) 0xae, (byte) 0x15, (byte) 0x24, (byte) 0xf5, (byte) 0xf3, (byte) 0xe6,
+ (byte) 0x36, (byte) 0x55, (byte) 0x29, (byte) 0xa8, (byte) 0xa9, (byte) 0xaf, (byte) 0x7b, (byte) 0x44,
+ (byte) 0x19, (byte) 0xda, (byte) 0x66, (byte) 0x4d, (byte) 0x11, (byte) 0x89, (byte) 0x28, (byte) 0x34,
+ (byte) 0x01, (byte) 0x15, (byte) 0x24, (byte) 0x93, (byte) 0x43, (byte) 0x6a, (byte) 0x8f, (byte) 0xe4,
+ (byte) 0x54, (byte) 0x3a, (byte) 0x3d, (byte) 0x9b, (byte) 0x2f, (byte) 0xc3, (byte) 0xdb, (byte) 0x7e,
+ (byte) 0x5e, (byte) 0x12, (byte) 0x00, (byte) 0xaa, (byte) 0xe7, (byte) 0xc1, (byte) 0x82, (byte) 0x1c,
+ (byte) 0x1d, (byte) 0x1d, (byte) 0x23, (byte) 0x1d, (byte) 0xa3, (byte) 0xcc, (byte) 0x59, (byte) 0xe4,
+ (byte) 0x7a, (byte) 0xf0, (byte) 0x14, (byte) 0x17, (byte) 0xfb, (byte) 0x96, (byte) 0x90, (byte) 0xc1,
+ (byte) 0xc0, (byte) 0xde, (byte) 0xdb, (byte) 0x91, (byte) 0xfb, (byte) 0x49, (byte) 0x39, (byte) 0x70,
+ (byte) 0x76, (byte) 0x2f, (byte) 0x7b, (byte) 0x22, (byte) 0xcd, (byte) 0x35, (byte) 0xcb, (byte) 0xed,
+ (byte) 0x8f, (byte) 0xb3, (byte) 0x66, (byte) 0xae, (byte) 0x95, (byte) 0x49, (byte) 0x75
+ };
+
+ protected static final int KID_PIN_SS = 0x81;
+
+ protected byte[] EF_C_X509_CH_DS = new byte[2000];
+
+ public STARCOSApplSichereSignatur(STARCOSCardChannelEmul channel) {
+ super(channel);
+ // Files
+ System.arraycopy(C_X509_CH_DS, 0, EF_C_X509_CH_DS, 0, C_X509_CH_DS.length);
+ putFile(new File(FID_EF_C_X509_CH_DS, EF_C_X509_CH_DS, FCI_EF_C_X509_CH_DS));
+
+ // PINs
+ pins.put(KID_PIN_SS, new PIN(new byte[] { (byte) 0x24, (byte) 0x12,
+ (byte) 0x34, (byte) 0x56, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF }, KID_PIN_SS, 3));
+ }
+
+ @Override
+ public byte[] getAID() {
+ return AID_SichereSignatur;
+ }
+
+ @Override
+ public byte[] getFID() {
+ return FID_SichereSignatur;
+ }
+
+ @Override
+ public byte[] getFCI() {
+ return FCI;
+ }
+
+ @Override
+ public ResponseAPDU cmdPERFORM_SECURITY_OPERATION(CommandAPDU command, CardChannelEmul channel) throws CardException {
+
+ checkINS(command, 0x2A);
+
+ if (command.getP1() == 0x90 && command.getP2() == 0xA0) {
+
+ // HASH
+ byte[] data = command.getData();
+ if (data[0] == (byte) 0x90 && data[1] == (byte) 0x14) {
+ hash = Arrays.copyOfRange(data, 2, data.length);
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ throw new CardException("HASH command only supports complete hash.");
+ }
+
+ } else if (command.getP1() == 0x9E && command.getP2() == 0x9A) {
+
+ // COMPUTE DIGITAL SIGNATURE
+ if (securityEnv == null) {
+ // No security environment
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ if (hash == null) {
+ // Command sequence not correct
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x03});
+ }
+ if (hash.length != 20) {
+ // Invalid hash length
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80});
+ }
+ if (pins.get(KID_PIN_SS).state != PIN.STATE_PIN_VERIFIED) {
+ // Security Status not satisfied
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+
+ byte[] signature = new byte[48];
+
+ // TODO replace by signature creation
+ Random random = new Random();
+ random.nextBytes(signature);
+
+ byte[] response = new byte[signature.length + 2];
+ System.arraycopy(signature, 0, response, 0, signature.length);
+ response[signature.length] = (byte) 0x90;
+ response[signature.length + 1] = (byte) 0x00;
+
+ hash = null;
+ pins.get(KID_PIN_SS).state = PIN.STATE_RESET;
+
+ return new ResponseAPDU(response);
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00});
+ }
+
+ }
+
+ public void clearCert() {
+ Arrays.fill(EF_C_X509_CH_DS, (byte) 0x00);
+ }
+
+ @Override
+ public ResponseAPDU cmdMANAGE_SECURITY_ENVIRONMENT(CommandAPDU command, CardChannelEmul channel) throws CardException {
+
+ checkINS(command, 0x22);
+
+ switch (command.getP2()) {
+ case 0xA4:
+ switch (command.getP1()) {
+ case 0x41:
+ // INTERNAL AUTHENTICATE
+ case 0x81:
+ // EXTERNAL AUTHENTICATE
+ }
+ case 0xB6:
+ switch (command.getP1()) {
+ case 0x41: {
+ // PSO - COMPUTE DIGITAL SIGNATURE
+ byte[] dst = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80,
+ (byte) 0x02, (byte) 0x00, (byte) 0x89, (byte) 0x03, (byte) 0x13, (byte) 0x35, (byte) 0x10};
+ if (Arrays.equals(dst, command.getData())) {
+ securityEnv = command.getData();
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80});
+ }
+ }
+ case 0x81:
+ // PSO - VERIFY DGITAL SIGNATURE
+ }
+ case 0xB8:
+ switch (command.getP1()) {
+ case 0x41:
+ // PSO � DECIPHER
+ case 0x81:
+ // PSO � ENCIPHER
+ }
+ default:
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x81});
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java
new file mode 100644
index 00000000..89030894
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java
@@ -0,0 +1,375 @@
+/*
+* 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.starcos;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CommandAPDU;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.AbstractAppl;
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public class STARCOSCardChannelEmul extends CardChannelEmul {
+
+ public static final int KID_PIN_Glob = 0x01;
+
+ /**
+ *
+ */
+ protected CardEmul cardEmul;
+
+ public final HashMap<Integer, PIN> globalPins = new HashMap<Integer, PIN>();
+
+ public STARCOSCardChannelEmul(CardEmul cardEmul) {
+ this.cardEmul = cardEmul;
+ globalPins.put(KID_PIN_Glob, new PIN(new byte[] { (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF }, KID_PIN_Glob, 10));
+ }
+
+ @Override
+ public Card getCard() {
+ return cardEmul;
+ }
+
+ protected ResponseAPDU cmdSELECT(CommandAPDU command) throws CardException {
+
+ byte[] fid = command.getData();
+
+ switch (command.getP1()) {
+ case 0x00: // MF
+ if (fid.length !=0) {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80});
+ } else {
+ currentFile = null;
+ currentAppl = null;
+ return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+ }
+
+ case 0x01: // Lower-level DF
+ throw new CardException("Not supported.");
+
+ case 0x02: // EF in current DF
+ if (currentAppl != null) {
+ if (command.getP2() != 0x04) {
+ throw new CardException("Not supported.");
+ }
+ for (File file : currentAppl.getFiles()) {
+ if (Arrays.equals(fid, file.fid)) {
+ currentFile = file;
+ byte[] response = new byte[file.fcx.length + 2];
+ System.arraycopy(file.fcx, 0, response, 0, file.fcx.length);
+ response[file.fcx.length] = (byte) 0x90;
+ response[file.fcx.length + 1] = (byte) 0x00;
+ return new ResponseAPDU(response);
+ }
+ }
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82});
+ } else {
+ throw new CardException("Not supported.");
+ }
+
+ case 0x03: // Higher-level DF
+ throw new CardException("Not supported.");
+
+ case 0x04: // Selection by DF name
+ AbstractAppl appl = cardEmul.getApplication(fid);
+ if (appl != null) {
+ if (command.getP2() != 0x00) {
+ throw new CardException("Not supported.");
+ }
+ if (currentAppl != null && currentAppl != appl) {
+ currentAppl.leaveApplContext();
+ currentFile = null;
+ }
+ currentAppl = appl;
+
+ byte[] fci = currentAppl.getFCI();
+ byte[] response = new byte[fci.length + 2];
+ System.arraycopy(fci, 0, response, 0, fci.length);
+ response[fci.length] = (byte) 0x90;
+ response[fci.length + 1] = (byte) 0x00;
+ return new ResponseAPDU(response);
+ }
+
+ default:
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x86});
+ }
+
+ }
+
+ protected ResponseAPDU cmdREAD_BINARY(CommandAPDU command) throws CardException {
+
+ if (command.getINS() != 0xB0) {
+ throw new IllegalArgumentException("INS has to be 0xB0.");
+ }
+
+ if (currentFile == null) {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x86});
+ }
+
+ if ((command.getP1() & 0x80) > 0) {
+ throw new CardException("Not implemented.");
+ }
+
+ int offset = command.getP2() + (command.getP1() << 8);
+ if (offset > currentFile.file.length) {
+ // Wrong length
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ if (command.getNe() == 0) {
+ throw new CardException("Not implemented.");
+ }
+
+ if (currentFile.kid != -1) {
+ PIN pin;
+ if ((currentFile.kid & 0x80) > 0) {
+ if (currentAppl == null
+ || (pin = currentAppl.pins.get(currentFile.kid)) == null
+ || pin.state != PIN.STATE_PIN_VERIFIED) {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+ } else {
+ if ((pin = globalPins.get(currentFile.kid)) == null
+ || pin.state != PIN.STATE_PIN_VERIFIED) {
+ return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82});
+ }
+ }
+ }
+
+ if (command.getNe() == 256 || command.getNe() <= currentFile.file.length - offset) {
+ int len = Math.min(command.getNe(), currentFile.file.length - offset);
+ byte[] response = new byte[len + 2];
+ System.arraycopy(currentFile.file, offset, response, 0, len);
+ response[len] = (byte) 0x90;
+ response[len + 1] = (byte) 0x00;
+ return new ResponseAPDU(response);
+ } else if (command.getNe() >= currentFile.file.length - offset) {
+ return new ResponseAPDU(new byte[] {(byte) 0x62, (byte) 0x82});
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ }
+
+
+ @Override
+ public ResponseAPDU transmit(CommandAPDU command) throws CardException {
+
+ if (command.getCLA() == 0x00) {
+
+ switch (command.getINS()) {
+
+ // SELECT
+ case 0xA4:
+ return cmdSELECT(command);
+
+ // READ BINARY
+ case 0xB0:
+ return cmdREAD_BINARY(command);
+
+ // VERIFY
+ case 0x20:
+ return cmdVERIFY(command);
+
+ // MANAGE SECURITY ENVIRONMENT
+ case 0x22: {
+ if (currentAppl != null) {
+ return currentAppl.cmdMANAGE_SECURITY_ENVIRONMENT(command, this);
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+
+ // CHANGE REFERENCE DATA
+ case 0x24: {
+ return cmdCHANGE_REFERENCE_DATA(command);
+ }
+
+ // PERFORM SECURITY OPERATION
+ case 0x2A: {
+ if (currentAppl != null) {
+ return currentAppl.cmdPERFORM_SECURITY_OPERATION(command, this);
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+
+ // INTERNAL AUTHENTICATE
+ case 0x88: {
+ if (currentAppl != null) {
+ return currentAppl.cmdINTERNAL_AUTHENTICATE(command, this);
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05});
+ }
+ }
+
+ default:
+ return new ResponseAPDU(new byte[] { (byte) 0x6D, (byte) 0x00});
+ }
+
+ } else {
+ return new ResponseAPDU(new byte[] { (byte) 0x6E, (byte) 0x00});
+ }
+
+ }
+
+ protected ResponseAPDU verifyPin(int kid, byte[] reference) {
+
+ PIN pin;
+ if ((kid & 0x80) > 0 && currentAppl != null) {
+ pin = currentAppl.pins.get(kid);
+ } else {
+ pin = globalPins.get(kid);
+ }
+
+ if (pin != null) {
+
+ if (reference.length == 0) {
+ return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)});
+ }
+
+ if (reference.length != 8) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ if (Arrays.equals(reference, pin.pin)) {
+ switch (pin.state) {
+ case PIN.STATE_PIN_BLOCKED:
+ return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 });
+
+ case PIN.STATE_RESET:
+ pin.state = PIN.STATE_PIN_VERIFIED;
+
+ default:
+ pin.kfpc = 10;
+ return new ResponseAPDU(new byte[] { (byte) 0x90, (byte) 0x00 });
+ }
+ } else {
+ switch (pin.state) {
+ case PIN.STATE_PIN_BLOCKED:
+ return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 });
+
+ default:
+ if (--pin.kfpc > 0) {
+ return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)});
+ } else {
+ pin.state = PIN.STATE_PIN_BLOCKED;
+ return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 });
+ }
+ }
+
+ }
+
+ } else {
+ return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00});
+ }
+
+ }
+
+ protected ResponseAPDU cmdVERIFY(CommandAPDU command) throws CardException {
+
+ if (command.getINS() != 0x20) {
+ throw new IllegalArgumentException("INS has to be 0x20.");
+ }
+
+ if (command.getP1() != 00) {
+ return new ResponseAPDU(new byte[] {(byte) 0x6B, (byte) 0x00});
+ }
+
+ return verifyPin(command.getP2(), command.getData());
+
+ }
+
+ protected ResponseAPDU cmdCHANGE_REFERENCE_DATA(CommandAPDU command) {
+
+ if (command.getINS() != 0x24) {
+ throw new IllegalArgumentException("INS has to be 0x24.");
+ }
+
+ byte[] data = command.getData();
+
+ ResponseAPDU response;
+
+ if (command.getP1() == 0x01) {
+
+ if (data.length != 8) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ response = verifyPin(0xFF & command.getP2(), data);
+
+ } else if (command.getP1() == 0x00) {
+
+ if (data.length != 16) {
+ return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
+ }
+
+ response = verifyPin(0xFF & command.getP2(), Arrays.copyOf(data, 8));
+
+ } else {
+ return new ResponseAPDU(new byte[] { (byte) 0x6A, (byte) 0x81 });
+ }
+
+ if (response.getSW() == 0x9000) {
+ PIN pin;
+ if (currentAppl != null) {
+ pin = currentAppl.pins.get(command.getP2());
+ } else {
+ pin = globalPins.get(command.getP2());
+ }
+ pin.pin = Arrays.copyOfRange(data, 8, 16);
+ }
+
+ return response;
+
+ }
+
+ public void setPin(int kid, char[] value) {
+ PIN pin = globalPins.get(kid);
+ if (pin != null) {
+ if (value == null) {
+ pin.pin = null;
+ } else {
+ byte[] b = new byte[8];
+ b[0] = (byte) (0x20 | value.length);
+ for(int i = 1, j = 0; i < b.length; i++) {
+ int h = ((j < value.length)
+ ? Character.digit(value[j++], 10)
+ : 0x0F);
+ int l = ((j < value.length)
+ ? Character.digit(value[j++], 10)
+ : 0x0F);
+ b[i] = (byte) ((h << 4) | l);
+ }
+ pin.pin = b;
+ }
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java
new file mode 100644
index 00000000..7b2f3fbe
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java
@@ -0,0 +1,50 @@
+/*
+* 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.starcos;
+
+
+import javax.smartcardio.ATR;
+
+import at.gv.egiz.smcc.CardChannelEmul;
+import at.gv.egiz.smcc.CardEmul;
+
+@SuppressWarnings("restriction")
+public class STARCOSCardEmul extends CardEmul {
+
+ protected static ATR ATR = new ATR(new byte[] {
+ (byte) 0x3b, (byte) 0xbd, (byte) 0x18, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45,
+ (byte) 0x80, (byte) 0x51, (byte) 0x02, (byte) 0x67, (byte) 0x05, (byte) 0x18, (byte) 0xb1, (byte) 0x02,
+ (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x81, (byte) 0x05, (byte) 0x31
+ });
+
+ public STARCOSCardEmul() {
+ applications.add(new STARCOSApplSichereSignatur((STARCOSCardChannelEmul) channel));
+ applications.add(new STARCOSApplInfobox((STARCOSCardChannelEmul) channel));
+ applications.add(new STARCOSApplGewoehnlicheSignatur((STARCOSCardChannelEmul) channel));
+ }
+
+ @Override
+ public ATR getATR() {
+ return ATR;
+ }
+
+ @Override
+ protected CardChannelEmul newCardChannel(CardEmul cardEmul) {
+ return new STARCOSCardChannelEmul(this);
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java
new file mode 100644
index 00000000..0fb4f62d
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java
@@ -0,0 +1,297 @@
+/*
+* 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.starcos;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import javax.smartcardio.CardChannel;
+
+import org.junit.Test;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.CardNotSupportedException;
+import at.gv.egiz.smcc.CardTerminalEmul;
+import at.gv.egiz.smcc.CardTest;
+import at.gv.egiz.smcc.LockedException;
+import at.gv.egiz.smcc.NotActivatedException;
+import at.gv.egiz.smcc.PINFormatException;
+import at.gv.egiz.smcc.PINMgmtSignatureCard;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.STARCOSCard;
+import at.gv.egiz.smcc.SignatureCard;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.SignatureCardFactory;
+import at.gv.egiz.smcc.CardTest.TestChangePINProvider;
+import at.gv.egiz.smcc.CardTest.TestPINProvider;
+import at.gv.egiz.smcc.SignatureCard.KeyboxName;
+import at.gv.egiz.smcc.acos.A03ApplDEC;
+import at.gv.egiz.smcc.acos.A04ApplDEC;
+import at.gv.egiz.smcc.acos.A04ApplSIG;
+import at.gv.egiz.smcc.acos.ACOSAppl;
+import at.gv.egiz.smcc.acos.ACOSApplDEC;
+import at.gv.egiz.smcc.acos.ACOSApplSIG;
+
+public class STARCOSCardTest extends CardTest {
+
+ @Override
+ protected SignatureCard createSignatureCard()
+ throws CardNotSupportedException {
+ SignatureCardFactory factory = SignatureCardFactory.getInstance();
+ STARCOSCardEmul card = new STARCOSCardEmul();
+ SignatureCard signatureCard = factory.createSignatureCard(card,
+ new CardTerminalEmul(card));
+ assertTrue(signatureCard instanceof PINMgmtSignatureCard);
+ return signatureCard;
+ }
+
+ @Test
+ public void testGetInfoboxIdentityLinkEmpty() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ char[] pin = "0000".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSApplInfobox appl = (STARCOSApplInfobox) card.getApplication(STARCOSAppl.AID_Infobox);
+ appl.clearInfobox();
+
+ byte[] idlink = signatureCard.getInfobox("IdentityLink",
+ new TestPINProvider(pin), null);
+ assertNull(idlink);
+
+ }
+
+ @Test(expected = SignatureCardException.class)
+ public void testGetInfoboxIdentityInvalid() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ char[] pin = "0000".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSApplInfobox appl = (STARCOSApplInfobox) card.getApplication(STARCOSAppl.AID_Infobox);
+ appl.setInfoboxHeader((byte) 0xFF);
+
+ signatureCard.getInfobox("IdentityLink", new TestPINProvider(pin), null);
+
+ }
+
+ @Test
+ public void testGetCerts() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ byte[] cert;
+
+ cert = signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR);
+ assertNotNull(cert);
+ assertTrue(Arrays.equals(cert, STARCOSApplSichereSignatur.C_X509_CH_DS));
+
+ cert = signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR);
+ assertNotNull(cert);
+ assertTrue(Arrays.equals(cert, STARCOSApplGewoehnlicheSignatur.C_X509_CH_AUT));
+
+ }
+
+ @Test(expected = NotActivatedException.class)
+ public void testGetDSCertEmpty() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
+ appl.clearCert();
+
+ signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR);
+
+ }
+
+ @Test(expected = NotActivatedException.class)
+ public void testGetAUTCertEmpty() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSApplGewoehnlicheSignatur appl = (STARCOSApplGewoehnlicheSignatur) card.getApplication(STARCOSApplGewoehnlicheSignatur.AID_GewoehnlicheSignatur);
+ appl.clearCert();
+
+ signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR);
+
+ }
+
+ @Test
+ public void testSignSichereSignatur() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ char[] pin = "123456".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
+ appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, pin);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ byte[] signature = signatureCard.createSignature(hash,
+ KeyboxName.SECURE_SIGNATURE_KEYPAIR, new TestPINProvider(pin));
+
+ assertNotNull(signature);
+
+ }
+
+ @Test
+ public void testSignGewoehnlicheSignatur() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ char[] pin = "1234".toCharArray();
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel();
+ channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, pin);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ byte[] signature = signatureCard.createSignature(hash,
+ KeyboxName.CERITIFIED_KEYPAIR, new TestPINProvider(pin));
+
+ assertNotNull(signature);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignSichereSignaturInvalidPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+
+ signatureCard.createSignature(hash, KeyboxName.SECURE_SIGNATURE_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignGewoehnlicheSignaturInvalidPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("1234".toCharArray());
+
+ signatureCard.createSignature(hash, KeyboxName.CERITIFIED_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignSichereSignaturBlockedPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
+ appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, null);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+ assertTrue(pinProvider.getProvided() <= 0);
+
+ signatureCard.createSignature(hash, KeyboxName.SECURE_SIGNATURE_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test(expected = LockedException.class)
+ public void testSignGewoehnlicheSignaturBlockedPin() throws SignatureCardException,
+ InterruptedException, CardNotSupportedException,
+ NoSuchAlgorithmException, UnsupportedEncodingException {
+
+ SignatureCard signatureCard = createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel();
+ channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, null);
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest("MOCCA".getBytes("ASCII"));
+
+ TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray());
+
+ signatureCard.createSignature(hash, KeyboxName.CERITIFIED_KEYPAIR,
+ pinProvider);
+
+ }
+
+ @Test
+ public void testChangePin() throws CardNotSupportedException,
+ LockedException, NotActivatedException, CancelledException,
+ PINFormatException, SignatureCardException, InterruptedException {
+
+ char[] defaultPin = "123456".toCharArray();
+
+ PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
+ CardEmul card = (CardEmul) signatureCard.getCard();
+ STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel();
+ channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, defaultPin);
+ STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
+ appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, defaultPin);
+
+ for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
+
+ char[] pin = defaultPin;
+
+ for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) {
+ signatureCard.verifyPIN(pinSpec, new TestPINProvider(pin));
+ char[] newPin = new char[i];
+ Arrays.fill(newPin, '0');
+ signatureCard
+ .changePIN(pinSpec, new TestChangePINProvider(pin, newPin));
+ signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin));
+ pin = newPin;
+ }
+
+ }
+
+ }
+
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/util/ISO7816UtilsTest.java b/smcc/src/test/java/at/gv/egiz/smcc/util/ISO7816UtilsTest.java
new file mode 100644
index 00000000..679f2c02
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/util/ISO7816UtilsTest.java
@@ -0,0 +1,175 @@
+/*
+* 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.util.Arrays;
+
+import javax.smartcardio.CommandAPDU;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import at.gv.egiz.smcc.VerifyAPDUSpec;
+import at.gv.egiz.smcc.util.ISO7816Utils;
+import static org.junit.Assert.*;
+
+public class ISO7816UtilsTest {
+
+ @Test
+ public void testFormatPIN() {
+
+ formatPIN(VerifyAPDUSpec.PIN_FORMAT_BINARY,
+ VerifyAPDUSpec.PIN_JUSTIFICATION_LEFT, 7, "1234",
+ new byte[] {
+ (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ },
+ new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ }
+ );
+
+ formatPIN(VerifyAPDUSpec.PIN_FORMAT_BINARY,
+ VerifyAPDUSpec.PIN_JUSTIFICATION_RIGHT, 7, "12345",
+ new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x01
+ },
+ new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
+ }
+ );
+
+ formatPIN(VerifyAPDUSpec.PIN_FORMAT_BCD,
+ VerifyAPDUSpec.PIN_JUSTIFICATION_LEFT, 7, "12345",
+ new byte[] {
+ (byte) 0x12, (byte) 0x34, (byte) 0x50, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ },
+ new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xf0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ }
+ );
+
+ formatPIN(VerifyAPDUSpec.PIN_FORMAT_BCD,
+ VerifyAPDUSpec.PIN_JUSTIFICATION_RIGHT, 7, "1234567",
+ new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x65, (byte) 0x43, (byte) 0x21
+ },
+ new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0f, (byte) 0xff, (byte) 0xff, (byte) 0xff
+ }
+ );
+
+ formatPIN(VerifyAPDUSpec.PIN_FORMAT_ASCII,
+ VerifyAPDUSpec.PIN_JUSTIFICATION_LEFT, 7, "1234",
+ new byte[] {
+ (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ },
+ new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ }
+ );
+
+ formatPIN(VerifyAPDUSpec.PIN_FORMAT_ASCII,
+ VerifyAPDUSpec.PIN_JUSTIFICATION_RIGHT, 7, "12345",
+ new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x34, (byte) 0x33, (byte) 0x32, (byte) 0x31
+ },
+ new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
+ }
+ );
+
+
+ }
+
+ private void formatPIN(int pinFormat, int pinJusitification, int pinLength, String pin, byte[] rfpin, byte[] rmask) {
+
+ byte[] fpin = new byte[pinLength];
+ byte[] mask = new byte[pinLength];
+
+ ISO7816Utils.formatPIN(pinFormat, pinJusitification, fpin, mask, pin.toCharArray());
+
+// System.out.println(toString(fpin));
+// System.out.println(toString(mask));
+
+ assertTrue(Arrays.equals(fpin, rfpin));
+ assertTrue(Arrays.equals(mask, rmask));
+
+ }
+
+ @Test
+ public void testCreateVerifyAPDU() {
+
+ VerifyAPDUSpec verifyAPDUSpec;
+ CommandAPDU apdu;
+ byte[] ref;
+
+ verifyAPDUSpec = new VerifyAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x80, (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);
+
+ apdu = ISO7816Utils.createVerifyAPDU(verifyAPDUSpec, "1234".toCharArray());
+
+// System.out.println(toString(apdu.getBytes()));
+
+ ref = new byte[] { (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x80,
+ (byte) 0x08, (byte) 0x24, (byte) 0x12, (byte) 0x34, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+
+ assertTrue(Arrays.equals(apdu.getBytes(), ref));
+
+ ref = new byte[] { (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x80,
+ (byte) 0x08, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
+
+ verifyAPDUSpec = new VerifyAPDUSpec(
+ new byte[] {
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x80, (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 },
+ 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
+
+ apdu = ISO7816Utils.createVerifyAPDU(verifyAPDUSpec, "1234".toCharArray());
+
+// System.out.println(toString(apdu.getBytes()));
+
+ assertTrue(Arrays.equals(apdu.getBytes(), ref));
+
+ }
+
+ 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();
+ }
+
+
+}