summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BKULocal/src/main/webapp/WEB-INF/applicationContext.xml3
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java1
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java3
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java96
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java323
-rw-r--r--bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java147
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java320
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java214
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java386
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java38
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/VerificationFailedException.java65
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java40
-rw-r--r--smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java3
13 files changed, 1219 insertions, 420 deletions
diff --git a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml
index eb7d5b7a..2ddd46a1 100644
--- a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml
@@ -82,6 +82,9 @@
<entry
key="CardChannel"
value="at.gv.egiz.bku.slcommands.impl.CardChannelInfoboxImpl" />
+ <entry
+ key="SV-Personendaten"
+ value="at.gv.egiz.bku.slcommands.impl.SVPersonendatenInfoboxImpl" />
</map>
</property>
</bean>
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java
index 408330cc..57d89c89 100644
--- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java
@@ -100,6 +100,7 @@ public class DataUrlConnectionImpl implements DataUrlConnectionSPI {
}
if (hostnameVerifier != null) {
log.debug("Setting custom hostname verifier");
+ https.setHostnameVerifier(hostnameVerifier);
}
} else {
log.trace("No secure connection with: "+url+ " class="+connection.getClass());
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java
index ef8034aa..452c45e5 100644
--- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java
@@ -80,6 +80,7 @@ public class LegacyDataUrlConnectionImpl implements DataUrlConnectionSPI {
}
if (hostnameVerifier != null) {
log.debug("Setting custom hostname verifier");
+ https.setHostnameVerifier(hostnameVerifier);
}
}
connection.setDoOutput(true);
@@ -229,6 +230,8 @@ public class LegacyDataUrlConnectionImpl implements DataUrlConnectionSPI {
public DataUrlConnectionSPI newInstance() {
DataUrlConnectionSPI uc = new LegacyDataUrlConnectionImpl();
uc.setConfiguration(config);
+ uc.setSSLSocketFactory(sslSocketFactory);
+ uc.setHostnameVerifier(hostnameVerifier);
return uc;
}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java
index e49ed6c0..e7f96c06 100644
--- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java
@@ -16,12 +16,17 @@
*/
package at.gv.egiz.bku.slcommands.impl;
+import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -36,6 +41,7 @@ import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayTy
import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType.ReadValue;
import at.gv.egiz.bku.slcommands.InfoboxReadResult;
import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slcommands.SLCommandFactory;
import at.gv.egiz.bku.slexceptions.SLCommandException;
/**
@@ -54,7 +60,7 @@ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl
/**
* The search string pattern.
*/
- public static final String SEARCH_STRING_PATTERN = ".&&[^/](/.&&[^/])*";
+ public static final String SEARCH_STRING_PATTERN = "(.&&[^/])+(/.&&[^/])*";
/**
* @return the keys available in this infobox.
@@ -93,6 +99,11 @@ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl
return Arrays.asList(getKeys());
}
+ if (!searchString.contains("*")) {
+ Arrays.asList(getKeys()).contains(searchString);
+ return Collections.singletonList(searchString);
+ }
+
if (Pattern.matches(SEARCH_STRING_PATTERN, searchString)) {
// for (int i = 0; i < searchString.length(); i++) {
@@ -160,15 +171,10 @@ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl
protected InfoboxReadResult readPairs(ReadPairs readPairs, SLCommandContext cmdCtx) throws SLCommandException {
if (readPairs.isValuesAreXMLEntities() && !isValuesAreXMLEntities()) {
- log.info("Got valuesAreXMLEntities=" + readPairs + " but infobox type is binary.");
+ log.info("Got valuesAreXMLEntities=" + readPairs.isValuesAreXMLEntities() + " but infobox type is binary.");
throw new SLCommandException(4010);
}
- if (!readPairs.isValuesAreXMLEntities() && isValuesAreXMLEntities()) {
- log.info("Got valuesAreXMLEntities=" + readPairs + " but infobox type is XML.");
- throw new SLCommandException(4010);
- }
-
List<String> selectedKeys = selectKeys(readPairs.getSearchString());
if (readPairs.isUserMakesUnique() && selectedKeys.size() > 1) {
@@ -177,26 +183,10 @@ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl
throw new SLCommandException(4010);
}
- ObjectFactory objectFactory = new ObjectFactory();
-
- InfoboxReadDataAssocArrayType infoboxReadDataAssocArrayType = objectFactory.createInfoboxReadDataAssocArrayType();
-
- Map<String, Object> values = getValues(selectedKeys, cmdCtx);
- for (String key : selectedKeys) {
- InfoboxAssocArrayPairType infoboxAssocArrayPairType = objectFactory.createInfoboxAssocArrayPairType();
- infoboxAssocArrayPairType.setKey(key);
- Object value = values.get(key);
- if (value instanceof byte[]) {
- infoboxAssocArrayPairType.setBase64Content((byte[]) value);
- } else {
- infoboxAssocArrayPairType.setXMLContent((XMLContentType) value);
- }
- infoboxReadDataAssocArrayType.getPair().add(infoboxAssocArrayPairType);
- }
-
- return new InfoboxReadResultImpl(infoboxReadDataAssocArrayType);
+ return new InfoboxReadResultImpl(marshallPairs(selectedKeys, getValues(
+ selectedKeys, cmdCtx), readPairs.isValuesAreXMLEntities()));
}
-
+
/**
* Read the value specified by <code>readPairs</code>.
*
@@ -213,12 +203,7 @@ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl
protected InfoboxReadResult readValue(ReadValue readValue, SLCommandContext cmdCtx) throws SLCommandException {
if (readValue.isValueIsXMLEntity() && !isValuesAreXMLEntities()) {
- log.info("Got valuesAreXMLEntities=" + readValue + " but infobox type is binary.");
- throw new SLCommandException(4010);
- }
-
- if (!readValue.isValueIsXMLEntity() && isValuesAreXMLEntities()) {
- log.info("Got valuesAreXMLEntities=" + readValue + " but infobox type is XML.");
+ log.info("Got valuesAreXMLEntities=" + readValue.isValueIsXMLEntity() + " but infobox type is binary.");
throw new SLCommandException(4010);
}
@@ -230,24 +215,59 @@ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl
selectedKeys = Collections.emptyList();
}
+ return new InfoboxReadResultImpl(marshallPairs(selectedKeys, getValues(
+ selectedKeys, cmdCtx), readValue.isValueIsXMLEntity()));
+
+ }
+
+ protected InfoboxReadDataAssocArrayType marshallPairs(List<String> selectedKeys, Map<String, Object> values, boolean areXMLEntities) throws SLCommandException {
+
ObjectFactory objectFactory = new ObjectFactory();
-
+
InfoboxReadDataAssocArrayType infoboxReadDataAssocArrayType = objectFactory.createInfoboxReadDataAssocArrayType();
- Map<String, Object> values = getValues(selectedKeys, cmdCtx);
for (String key : selectedKeys) {
InfoboxAssocArrayPairType infoboxAssocArrayPairType = objectFactory.createInfoboxAssocArrayPairType();
infoboxAssocArrayPairType.setKey(key);
+
Object value = values.get(key);
- if (value instanceof byte[]) {
- infoboxAssocArrayPairType.setBase64Content((byte[]) value);
+ if (areXMLEntities) {
+ if (value instanceof byte[]) {
+ log.info("Got valuesAreXMLEntities=" + areXMLEntities + " but infobox type is binary.");
+ throw new SLCommandException(4122);
+ } else {
+ XMLContentType contentType = objectFactory.createXMLContentType();
+ contentType.getContent().add(value);
+ infoboxAssocArrayPairType.setXMLContent(contentType);
+ }
} else {
- infoboxAssocArrayPairType.setXMLContent((XMLContentType) value);
+ infoboxAssocArrayPairType.setBase64Content((value instanceof byte[]) ? (byte[]) value : marshallValue(value));
}
+
infoboxReadDataAssocArrayType.getPair().add(infoboxAssocArrayPairType);
}
+
+ return infoboxReadDataAssocArrayType;
- return new InfoboxReadResultImpl(infoboxReadDataAssocArrayType);
+ }
+
+ protected byte[] marshallValue(Object jaxbElement) throws SLCommandException {
+ SLCommandFactory commandFactory = SLCommandFactory.getInstance();
+ JAXBContext jaxbContext = commandFactory.getJaxbContext();
+
+ ByteArrayOutputStream result;
+ try {
+ Marshaller marshaller = jaxbContext.createMarshaller();
+
+ result = new ByteArrayOutputStream();
+ marshaller.marshal(jaxbElement, result);
+ } catch (JAXBException e) {
+ log.info("Failed to marshall infobox content.", e);
+ throw new SLCommandException(4122);
+ }
+
+ return result.toByteArray();
+
}
@Override
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java
new file mode 100644
index 00000000..7e204632
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java
@@ -0,0 +1,323 @@
+/*
+* 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.bku.slcommands.impl;
+
+import iaik.asn1.ASN;
+import iaik.asn1.ASN1Object;
+import iaik.asn1.CodingException;
+import iaik.asn1.DerCoder;
+import iaik.asn1.NumericString;
+import iaik.asn1.OCTET_STRING;
+import iaik.asn1.ObjectID;
+import iaik.asn1.SEQUENCE;
+import iaik.asn1.SET;
+import iaik.asn1.UNKNOWN;
+import iaik.asn1.structures.ChoiceOfTime;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.buergerkarte.namespaces.cardchannel.AttributeList;
+import at.buergerkarte.namespaces.cardchannel.AttributeType;
+import at.buergerkarte.namespaces.cardchannel.ObjectFactory;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLExceptionMessages;
+import at.gv.egiz.stal.InfoboxReadRequest;
+import at.gv.egiz.stal.InfoboxReadResponse;
+import at.gv.egiz.stal.STALRequest;
+
+/**
+ * An implementation of the {@link Infobox} <em>Certificates</em> as
+ * specified in Security Layer 1.2.
+ *
+ * @author mcentner
+ */
+public class SVPersonendatenInfoboxImpl extends AbstractAssocArrayInfobox {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(SVPersonendatenInfoboxImpl.class);
+
+ public static final String EHIC = "EHIC";
+
+ public static final String GRUNDDATEN = "Grunddaten";
+
+ public static final String STATUS = "Status";
+
+ public static final String SV_PERSONENBINDUNG = "SV-Personenbindung";
+
+ /**
+ * The valid keys.
+ */
+ public static final String[] KEYS = new String[] {
+ GRUNDDATEN, EHIC, STATUS, SV_PERSONENBINDUNG
+ };
+
+ @Override
+ public String getIdentifier() {
+ return "SV-Personendaten";
+ }
+
+ @Override
+ public String[] getKeys() {
+ return KEYS;
+ }
+
+ @Override
+ public boolean isValuesAreXMLEntities() {
+ return true;
+ }
+
+ @Override
+ public Map<String, Object> getValues(List<String> keys, SLCommandContext cmdCtx) throws SLCommandException {
+
+ STALHelper stalHelper = new STALHelper(cmdCtx.getSTAL());
+
+ if (keys != null && !keys.isEmpty()) {
+
+ List<STALRequest> stalRequests = new ArrayList<STALRequest>();
+
+ // get values
+ InfoboxReadRequest infoboxReadRequest;
+ for (int i = 0; i < keys.size(); i++) {
+ infoboxReadRequest = new InfoboxReadRequest();
+ infoboxReadRequest.setInfoboxIdentifier(keys.get(i));
+ stalRequests.add(infoboxReadRequest);
+ }
+
+ stalHelper.transmitSTALRequest(stalRequests);
+
+ Map<String, Object> values = new HashMap<String, Object>();
+
+ try {
+ for (int i = 0; i < keys.size(); i++) {
+
+ String key = keys.get(i);
+ InfoboxReadResponse nextResponse = (InfoboxReadResponse) stalHelper.nextResponse(InfoboxReadResponse.class);
+
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ if (EHIC.equals(key)) {
+ AttributeList attributeList = createAttributeList(nextResponse.getInfoboxValue());
+ values.put(key, objectFactory.createEHIC(attributeList));
+ } else if (GRUNDDATEN.equals(key)) {
+ AttributeList attributeList = createAttributeList(nextResponse.getInfoboxValue());
+ values.put(key, objectFactory.createGrunddaten(attributeList));
+ } else if (SV_PERSONENBINDUNG.equals(key)) {
+ values.put(key, objectFactory.createSVPersonenbindung(nextResponse.getInfoboxValue()));
+ } else if (STATUS.equals(key)) {
+ AttributeList attributeList = createAttributeListFromRecords(nextResponse.getInfoboxValue());
+ values.put(key, objectFactory.createStatus(attributeList));
+ }
+
+ }
+ } catch (CodingException e) {
+ log.info("Failed to decode '" + getIdentifier() + "' infobox.", e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_INFOBOX_INVALID,
+ new Object[] { "IdentityLink" });
+
+ }
+
+ return values;
+
+ } else {
+
+ return new HashMap<String, Object>();
+
+ }
+
+
+ }
+
+ public static AttributeList createAttributeList(byte[] infoboxValue) throws CodingException {
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ ASN1Object asn1 = DerCoder.decode(infoboxValue);
+
+ AttributeList attributeList = objectFactory.createAttributeList();
+ List<AttributeType> attributes = attributeList.getAttribute();
+
+ if (asn1.isA(ASN.SEQUENCE)) {
+ for (int i = 0; i < ((SEQUENCE) asn1).countComponents(); i++) {
+
+ AttributeType attributeType = objectFactory.createAttributeType();
+
+ if (asn1.getComponentAt(i).isA(ASN.SEQUENCE)) {
+ SEQUENCE attribute = (SEQUENCE) asn1.getComponentAt(i);
+ if (attribute.getComponentAt(0).isA(ASN.ObjectID)) {
+ ObjectID objectId = (ObjectID) attribute.getComponentAt(0);
+ attributeType.setOid("urn:oid:" + objectId.getID());
+ }
+ if (attribute.getComponentAt(1).isA(ASN.SET)) {
+ SET values = (SET) attribute.getComponentAt(1);
+ for (int j = 0; j < values.countComponents(); j++) {
+ setAttributeValue(attributeType, values.getComponentAt(j));
+ }
+ }
+ }
+
+ attributes.add(attributeType);
+
+ }
+
+ }
+
+ return attributeList;
+
+ }
+
+ public static AttributeList createAttributeListFromRecords(byte[] infoboxValue) throws CodingException {
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ AttributeList attributeList = objectFactory.createAttributeList();
+ List<AttributeType> attributes = attributeList.getAttribute();
+
+ byte[] records = infoboxValue;
+
+ while (records != null && records.length > 0) {
+
+ int length;
+
+ if (records[0] != 0x00) {
+
+ ASN1Object asn1 = DerCoder.decode(records);
+
+ AttributeType attributeType = objectFactory.createAttributeType();
+
+ if (asn1.isA(ASN.SEQUENCE)) {
+ SEQUENCE attribute = (SEQUENCE) asn1;
+ if (attribute.getComponentAt(0).isA(ASN.ObjectID)) {
+ ObjectID objectId = (ObjectID) attribute.getComponentAt(0);
+ attributeType.setOid("urn:oid:" + objectId.getID());
+ }
+ if (attribute.getComponentAt(1).isA(ASN.SET)) {
+ SET values = (SET) attribute.getComponentAt(1);
+ for (int j = 0; j < values.countComponents(); j++) {
+ setAttributeValue(attributeType, values.getComponentAt(j));
+ }
+ }
+ }
+
+ attributes.add(attributeType);
+
+ length = DerCoder.encode(asn1).length;
+
+ } else {
+ length = 1;
+ }
+
+ if (length < records.length) {
+ records = Arrays.copyOfRange(records, length + 1, records.length);
+ } else {
+ records = null;
+ }
+
+ }
+
+ return attributeList;
+
+ }
+
+ private static void setAttributeValue(AttributeType attributeType, ASN1Object value) {
+
+ if (value.isA(ASN.OCTET_STRING)) {
+
+ try {
+ byte[] octets = ((OCTET_STRING) value).getWholeValue();
+ attributeType.setLatin1String(new String(octets, Charset.forName("ISO-8859-1")));
+ } catch (IOException e) {
+ log.info("Failed to set Latin1String.", e);
+ }
+
+ } else if (value.isA(ASN.NumericString)) {
+
+ attributeType.setNumericString((String) ((NumericString) value).getValue());
+
+ } else if (value.isA(ASN.GeneralizedTime)) {
+
+ try {
+ ChoiceOfTime choiceOfTime = new ChoiceOfTime(value);
+
+ GregorianCalendar gregorianCalendar = new GregorianCalendar();
+ gregorianCalendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ gregorianCalendar.setTime(choiceOfTime.getDate());
+
+ DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
+ XMLGregorianCalendar xmlGregorianCalendar = datatypeFactory.newXMLGregorianCalendar(gregorianCalendar);
+ xmlGregorianCalendar.setTimezone(0);
+
+ attributeType.setGeneralizedTime(xmlGregorianCalendar);
+ } catch (Exception e) {
+ log.info("Failed to set GeneralizedTime.", e);
+ }
+
+ } else if (value.isA(ASN.INTEGER)) {
+
+ attributeType.setInteger((BigInteger) value.getValue());
+
+ } else if (value.isA(ASN.UTF8String)) {
+
+ attributeType.setUTF8String((String) value.getValue());
+
+ } else if (value.isA(ASN.PrintableString)) {
+
+ attributeType.setPrintableString((String) value.getValue());
+
+ } else if (value.isA(ASN.UNKNOWN)) {
+
+ byte[] bytes = (byte[]) ((UNKNOWN) value).getValue();
+
+ try {
+ BigInteger bigInteger = new BigInteger(bytes);
+ String string = bigInteger.toString(16);
+
+ Date date = new SimpleDateFormat("yyyyMMdd").parse(string);
+ attributeType.setDate(new SimpleDateFormat("yyyy-MM-dd").format(date));
+ } catch (Exception e) {
+ log.info("Failed to set Date.", e);
+ }
+ }
+
+ }
+
+
+
+
+
+}
diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java
new file mode 100644
index 00000000..f9c60b86
--- /dev/null
+++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java
@@ -0,0 +1,147 @@
+/*
+* 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.bku.slcommands.impl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import iaik.asn1.CodingException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import at.buergerkarte.namespaces.cardchannel.AttributeList;
+import at.buergerkarte.namespaces.cardchannel.ObjectFactory;
+import at.gv.egiz.bku.slcommands.ErrorResult;
+import at.gv.egiz.bku.slcommands.InfoboxReadCommand;
+import at.gv.egiz.bku.slcommands.SLCommand;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slcommands.SLCommandFactory;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLRequestException;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.stal.dummy.DummySTAL;
+
+//@Ignore
+public class SVPersonendatenInfoboxImplTest {
+
+ private byte[] EHIC = new byte[] {
+ (byte) 0x30, (byte) 0x6b, (byte) 0x30, (byte) 0x12, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x28,
+ (byte) 0x00, (byte) 0x0a, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0x14, (byte) 0x31, (byte) 0x06,
+ (byte) 0x04, (byte) 0x04, (byte) 0x42, (byte) 0x47, (byte) 0x4b, (byte) 0x4b, (byte) 0x30, (byte) 0x12,
+ (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x28, (byte) 0x00, (byte) 0x0a, (byte) 0x01, (byte) 0x04,
+ (byte) 0x01, (byte) 0x15, (byte) 0x31, (byte) 0x06, (byte) 0x12, (byte) 0x04, (byte) 0x31, (byte) 0x33,
+ (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x22, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x28,
+ (byte) 0x00, (byte) 0x0a, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0x16, (byte) 0x31, (byte) 0x16,
+ (byte) 0x12, (byte) 0x14, (byte) 0x38, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x30, (byte) 0x30,
+ (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x32, (byte) 0x33, (byte) 0x30, (byte) 0x30,
+ (byte) 0x34, (byte) 0x37, (byte) 0x30, (byte) 0x37, (byte) 0x35, (byte) 0x39, (byte) 0x30, (byte) 0x1d,
+ (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x28, (byte) 0x00, (byte) 0x0a, (byte) 0x01, (byte) 0x04,
+ (byte) 0x01, (byte) 0x17, (byte) 0x31, (byte) 0x11, (byte) 0x18, (byte) 0x0f, (byte) 0x32, (byte) 0x30,
+ (byte) 0x30, (byte) 0x35, (byte) 0x30, (byte) 0x37, (byte) 0x30, (byte) 0x31, (byte) 0x31, (byte) 0x32,
+ (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x5a
+ };
+
+ private static ApplicationContext appCtx;
+
+ private SLCommandFactory factory;
+
+ private STAL stal;
+
+// @BeforeClass
+ public static void setUpClass() {
+ appCtx = new ClassPathXmlApplicationContext("at/gv/egiz/bku/slcommands/testApplicationContext.xml");
+ }
+
+// @Before
+ public void setUp() {
+ factory = SLCommandFactory.getInstance();
+ stal = new DummySTAL();
+ }
+
+ @Test
+ public void testEHIC() throws SLCommandException, JAXBException, CodingException, IOException {
+
+ AttributeList attributeList = SVPersonendatenInfoboxImpl.createAttributeList(EHIC);
+
+ JAXBElement<AttributeList> ehic = new ObjectFactory().createEHIC(attributeList);
+
+ JAXBContext jaxbContext = SLCommandFactory.getInstance().getJaxbContext();
+
+ Marshaller marshaller = jaxbContext.createMarshaller();
+
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+ marshaller.marshal(ehic, System.out);
+
+ }
+
+ @Ignore
+ @Test
+ public void testInfboxReadRequest() throws SLCommandException, SLRuntimeException, SLRequestException {
+ InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.xml");
+ assertNotNull(inputStream);
+
+ SLCommandContext context = new SLCommandContext();
+ context.setSTAL(stal);
+ SLCommand command = factory.createSLCommand(new StreamSource(inputStream), context);
+ assertTrue(command instanceof InfoboxReadCommand);
+
+ SLResult result = command.execute();
+ result.writeTo(new StreamResult(System.out));
+ }
+
+ @Ignore
+ @Test(expected=SLCommandException.class)
+ public void testInfboxReadRequestInvalid1() throws SLCommandException, SLRuntimeException, SLRequestException {
+ InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-1.xml");
+ assertNotNull(inputStream);
+
+ SLCommandContext context = new SLCommandContext();
+ context.setSTAL(stal);
+ SLCommand command = factory.createSLCommand(new StreamSource(inputStream), context);
+ assertTrue(command instanceof InfoboxReadCommand);
+ }
+
+ @Ignore
+ public void testInfboxReadRequestInvalid2() throws SLCommandException, SLRuntimeException, SLRequestException {
+ InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-2.xml");
+ assertNotNull(inputStream);
+
+ SLCommandContext context = new SLCommandContext();
+ context.setSTAL(stal);
+ SLCommand command = factory.createSLCommand(new StreamSource(inputStream), context);
+ assertTrue(command instanceof InfoboxReadCommand);
+
+ SLResult result = command.execute();
+ assertTrue(result instanceof ErrorResult);
+ }
+
+}
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 2baff834..6d96599c 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
@@ -30,7 +30,6 @@ package at.gv.egiz.smcc;
import java.nio.charset.Charset;
-import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
@@ -110,41 +109,47 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
public byte[] getCertificate(KeyboxName keyboxName)
throws SignatureCardException, InterruptedException {
- byte[] aid;
- byte[] efc;
- int maxsize;
- if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
- aid = AID_SIG;
- efc = EF_C_CH_DS;
- maxsize = EF_C_CH_DS_MAX_SIZE;
- } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
- aid = AID_DEC;
- efc = EF_C_CH_EKEY;
- maxsize = EF_C_CH_EKEY_MAX_SIZE;
- } else {
- throw new IllegalArgumentException("Keybox " + keyboxName
- + " not supported.");
- }
-
- log.debug("Get certificate for keybox '" + keyboxName.getKeyboxName() + "'" +
- " (AID=" + toString(aid) + " EF=" + toString(efc) + ").");
-
try {
- Card card = getCardChannel().getCard();
- try {
- card.beginExclusive();
- return readTLVFile(aid, efc, maxsize + 15000);
- } catch (FileNotFoundException e) {
- // if certificate is not present,
- // the citizen card application has not been activated
- throw new NotActivatedException();
- } finally {
- card.endExclusive();
+
+ 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();
+ }
+
+ } 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();
+ }
+
+ } else {
+ throw new IllegalArgumentException("Keybox " + keyboxName
+ + " not supported.");
}
+
} catch (CardException e) {
- throw new SignatureCardException("Failed to get exclusive card access.");
+ log.warn(e);
+ throw new SignatureCardException("Failed to access card.", e);
}
-
}
@@ -155,30 +160,47 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
throws SignatureCardException, InterruptedException {
- if ("IdentityLink".equals(infobox)) {
-
- PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"));
-
- try {
- Card card = getCardChannel().getCard();
- try {
- card.beginExclusive();
- return readTLVFilePIN(AID_DEC, EF_INFOBOX, KID_PIN_INF, provider,
- spec, EF_INFOBOX_MAX_SIZE);
- } catch (FileNotFoundException e) {
- // if certificate is not present,
- // the citizen card application has not been activated
- throw new NotActivatedException();
- } finally {
- card.endExclusive();
- }
- } catch (CardException e) {
- throw new SignatureCardException("Failed to get exclusive card access.");
+ try {
+ if ("IdentityLink".equals(infobox)) {
+
+ PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"));
+
+ int retries = -1;
+ String pin = null;
+ boolean pinRequiered = false;
+
+ do {
+ if (pinRequiered) {
+ pin = provider.providePIN(spec, retries);
+ if (pin == null) {
+ throw new CancelledException();
+ }
+ }
+ try {
+ getCard().beginExclusive();
+ return readTLVFile(AID_DEC, EF_INFOBOX, pin, KID_PIN_INF, EF_INFOBOX_MAX_SIZE);
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
+ } catch (SecurityStatusNotSatisfiedException e) {
+ pinRequiered = true;
+ } catch (VerificationFailedException e) {
+ pinRequiered = true;
+ retries = e.getRetries();
+ } finally {
+ getCard().endExclusive();
+ }
+ } while (retries != 0);
+
+ throw new LockedException();
+
+ } else {
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
}
-
- } else {
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
+
+ } catch (CardException e) {
+ log.warn(e);
+ throw new SignatureCardException("Failed to access card.", e);
}
}
@@ -192,68 +214,103 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
try {
- Card card = getCardChannel().getCard();
- try {
- card.beginExclusive();
-
- if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
-
- // SELECT DF
- selectFileFID(DF_SIG);
- // VERIFY
- verifyPIN(provider, new PINSpec(6, 10, "[0-9]", getResourceBundle()
- .getString("sig.pin.name")), KID_PIN_SIG);
- // MSE: SET DST
- mseSetDST(0x81, 0xb6, DST_SIG);
- // PSO: HASH
- psoHash(hash);
- // PSO: COMPUTE DIGITAL SIGNATURE
- return psoComputDigitalSiganture();
- } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
-
- // SELECT DF
- selectFileFID(DF_DEC);
- // VERIFY
- verifyPIN(provider, new PINSpec(4, 4, "[0-9]", getResourceBundle()
- .getString("dec.pin.name")), KID_PIN_DEC);
- // MSE: SET DST
- mseSetDST(0x41, 0xa4, DST_DEC);
- // INTERNAL AUTHENTICATE
- return internalAuthenticate(hash);
-
-
- // 00 88 10 00 23 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 54 26 F0 EA AF EA F0 4E D4 A1 AD BF 66 D4 A5 9B 45 6F AF 79 00
- // 00 88 10 00 23 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 DF 8C AB 8F E2 AD AC 7B 5A AF BE E9 44 5E 95 99 FA AF 2F 48 00
-
- } else {
- throw new IllegalArgumentException("KeyboxName '" + keyboxName
- + "' not supported.");
- }
+ if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
+
+ PINSpec spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));
+
+ int retries = -1;
+ String pin = null;
+
+ do {
+ pin = provider.providePIN(spec, retries);
+ if (pin == null) {
+ throw new CancelledException();
+ }
+ try {
+ getCard().beginExclusive();
+
+ // SELECT DF
+ selectFileFID(DF_SIG);
+ // VERIFY
+ retries = verifyPIN(pin, KID_PIN_SIG);
+ 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();
+
+ } catch (SecurityStatusNotSatisfiedException e) {
+ retries = verifyPIN(null, KID_PIN_SIG);
+ } catch (VerificationFailedException e) {
+ retries = e.getRetries();
+ } finally {
+ getCard().endExclusive();
+ }
+ } while (retries != 0);
+
+ throw new LockedException();
+
+
+ } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
- } catch (FileNotFoundException e) {
- // if certificate is not present,
- // the citizen card application has not been activated
- throw new NotActivatedException();
- } finally {
- card.endExclusive();
+ PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name"));
+
+ int retries = -1;
+ String pin = null;
+ boolean pinRequiered = false;
+
+ do {
+ if (pinRequiered) {
+ pin = provider.providePIN(spec, retries);
+ if (pin == null) {
+ throw new CancelledException();
+ }
+ }
+ try {
+ getCard().beginExclusive();
+
+ // SELECT DF
+ selectFileFID(DF_DEC);
+ // VERIFY
+ retries = verifyPIN(pin, KID_PIN_DEC);
+ 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();
+ } catch (SecurityStatusNotSatisfiedException e) {
+ pinRequiered = true;
+ retries = verifyPIN(null, KID_PIN_DEC);
+ } catch (VerificationFailedException e) {
+ pinRequiered = true;
+ retries = e.getRetries();
+ } finally {
+ getCard().endExclusive();
+ }
+ } while (retries != 0);
+
+ throw new LockedException();
+
+ } else {
+ throw new IllegalArgumentException("KeyboxName '" + keyboxName
+ + "' not supported.");
}
+
} catch (CardException e) {
- throw new SignatureCardException("Failed to get exclusive card access.");
- }
-
- }
-
- protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException {
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04,
- 0x00, fid, 256));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("Failed to select file (AID="
- + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + ".");
- } else {
- return resp.getBytes();
- }
+ log.warn(e);
+ throw new SignatureCardException("Failed to access card.", e);
+ }
+
}
protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
@@ -262,6 +319,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
0x00, fid, 256));
}
+ @Override
protected int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
@@ -290,35 +348,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
- /**
- *
- * @param pinProvider
- * @param spec
- * the PIN spec to be given to the pinProvider
- * @param kid
- * the KID (key identifier) of the PIN to be verified
- * @throws CancelledException
- * if the user canceld the operation
- * @throws javax.smartcardio.CardException
- * @throws at.gv.egiz.smcc.SignatureCardException
- */
- @Override
- protected void verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid)
- throws CardException, CancelledException, SignatureCardException, InterruptedException {
-
- int retries = -1;
- do {
- String pin = pinProvider.providePIN(spec, retries);
- if (pin == null) {
- // user canceled operation
- throw new CancelledException("User canceled operation");
- }
- retries = verifyPIN(pin, kid);
- } while (retries > 0);
-
- }
-
- void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException {
+ 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));
@@ -328,7 +358,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
}
- void psoHash(byte[] hash) throws CardException, SignatureCardException {
+ private void psoHash(byte[] hash) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x90,
0x81, hash));
@@ -338,7 +368,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
}
- byte[] psoComputDigitalSiganture() throws CardException,
+ private byte[] psoComputDigitalSiganture() throws CardException,
SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x9E,
@@ -352,7 +382,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
}
- byte[] internalAuthenticate(byte[] hash) throws CardException, SignatureCardException {
+ 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
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 e34c4899..633cc90d 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
@@ -28,6 +28,8 @@
//
package at.gv.egiz.smcc;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.ResourceBundle;
@@ -79,45 +81,56 @@ public abstract class AbstractSignatureCard implements SignatureCard {
return sb.toString();
}
- protected abstract byte[] selectFileAID(byte[] fid) throws CardException,
- SignatureCardException;
-
- protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException,
- SignatureCardException;
-
/**
- * VERIFY PIN
+ * Select an application using AID as DF name according to ISO/IEC 7816-4
+ * section 8.2.2.2.
*
- * <p>
- * Implementations of this method should call
- * {@link PINProvider#providePIN(PINSpec, int)} to retrieve the PIN entered by
- * the user and VERIFY PIN on the smart card until the PIN has been
- * successfully verified.
- * </p>
+ * @param dfName
+ * AID of the application to be selected
*
- * @param pinProvider
- * the PINProvider
- * @param spec
- * the PINSpec
- * @param kid
- * the key ID (KID) of the PIN to verify
+ * @return the response data of the response APDU if SW=0x9000
*
* @throws CardException
- * if smart card communication fails
- *
- * @throws CancelledException
- * if the PINProvider indicated that the user canceled the PIN entry
- * @throws NotActivatedException
- * if the card application has not been activated
- * @throws LockedException
- * if the card application is locked
+ * if card communication fails
*
* @throws SignatureCardException
- * if VERIFY PIN fails
+ * if application selection fails (e.g. an application with the
+ * given AID is not present on the card)
*/
- protected abstract void verifyPIN(PINProvider pinProvider, PINSpec spec,
- byte kid) throws CardException, SignatureCardException, InterruptedException;
+ protected byte[] selectFileAID(byte[] dfName) throws CardException, SignatureCardException {
+ CardChannel channel = getCardChannel();
+ ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04,
+ 0x00, dfName, 256));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("Failed to select application AID="
+ + toString(dfName) + ": SW=" + Integer.toHexString(resp.getSW()) + ".");
+ } else {
+ return resp.getBytes();
+ }
+ }
+
+ protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException,
+ SignatureCardException;
+ protected abstract int verifyPIN(String pin, byte kid) throws CardException, 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 {
@@ -125,6 +138,8 @@ public abstract class AbstractSignatureCard implements SignatureCard {
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()));
@@ -188,43 +203,10 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
- /**
- * 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
- */
- protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength)
- throws SignatureCardException, InterruptedException {
- return readTLVFilePIN(aid, ef, (byte) 0, null, null, maxLength);
- }
-
-
- /**
- * Read the content of a TLV file wich may require 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 provider the PINProvider
- * @param spec the PINSpec
- * @param maxLength the maximum length of the file
- *
- * @return the content of the file
- *
- * @throws SignatureCardException
- */
- protected byte[] readTLVFilePIN(byte[] aid, byte[] ef, byte kid,
- PINProvider provider, PINSpec spec, int maxLength)
- throws SignatureCardException, InterruptedException {
-
+ 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) {
@@ -256,38 +238,90 @@ public abstract class AbstractSignatureCard implements SignatureCard {
+ Integer.toHexString(resp.getSW()) + ").");
}
-
- // try to READ BINARY
- byte[] b = new byte[1];
- int sw = readBinary(0, 1, b);
- if (provider != null && sw == 0x6982) {
-
- // VERIFY
- verifyPIN(provider, spec, kid);
-
- } else if (sw == 0x9000) {
- // not expected type
- if (b[0] != 0x30) {
- throw new NotActivatedException();
- }
- } else {
- throw new SignatureCardException("READ BINARY failed (SW="
- + Integer.toHexString(sw) + ").");
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+
+ for (int i = start; i <= end; i++) {
+ bytes.write(readRecord(i));
}
-
- // READ BINARY
- byte[] data = readBinaryTLV(maxLength, (byte) 0x30);
-
- return data;
-
+
+ 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 {
+ return readTLVFile(aid, ef, null, (byte) 0, maxLength);
}
/**
+ * Read the content of a TLV file wich may require 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 provider the PINProvider
+ * @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, String 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
+ if (pin != null) {
+ int retries = verifyPIN(pin, kid);
+ if (retries != -1) {
+ throw new VerificationFailedException(retries);
+ }
+ }
+
+ return readBinaryTLV(maxLength, (byte) 0x30);
+
+
+ }
+
+ /**
* Transmit the given command APDU using the given card channel.
*
* @param channel
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 d6d02475..2a6e90bf 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
@@ -31,7 +31,6 @@ package at.gv.egiz.smcc;
import java.math.BigInteger;
import java.util.Arrays;
-import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
@@ -49,6 +48,42 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 };
+ /**
+ * Application ID <em>SV-Personendaten</em>.
+ */
+ public static final byte[] AID_SV_PERSONENDATEN = new byte[] {
+ (byte) 0xD0, (byte) 0x40, (byte) 0x00, (byte) 0x00,
+ (byte) 0x17, (byte) 0x01, (byte) 0x01, (byte) 0x01
+ };
+
+ /**
+ * File ID <em>Grunddaten</em> ({@link #AID_SV_PERSONENDATEN}).
+ */
+ public static final byte[] FID_GRUNDDATEN = new byte[] {
+ (byte) 0xEF, (byte) 0x01
+ };
+
+ /**
+ * File ID <em>EHIC</em> ({@link #AID_SV_PERSONENDATEN}).
+ */
+ public static final byte[] FID_EHIC = new byte[] {
+ (byte) 0xEF, (byte) 0x02
+ };
+
+ /**
+ * File ID <em>Status</em> ({@link #AID_SV_PERSONENDATEN}).
+ */
+ public static final byte[] FID_SV_PERSONENBINDUNG = new byte[] {
+ (byte) 0xEF, (byte) 0x03
+ };
+
+ /**
+ * File ID <em>Status</em> ({@link #AID_SV_PERSONENDATEN}).
+ */
+ public static final byte[] FID_STATUS = new byte[] {
+ (byte) 0xEF, (byte) 0x04
+ };
+
public static final byte[] AID_INFOBOX = new byte[] { (byte) 0xd0,
(byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00,
(byte) 0x18, (byte) 0x01 };
@@ -126,85 +161,134 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
super("at/gv/egiz/smcc/STARCOSCard");
}
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.SignatureCard#getCertificate(at.gv.egiz.smcc.SignatureCard.KeyboxName)
- */
@Override
public byte[] getCertificate(KeyboxName keyboxName)
throws SignatureCardException, InterruptedException {
- byte[] aid;
- byte[] efc;
- if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
- aid = AID_DF_SS;
- efc = EF_C_X509_CH_DS;
- } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
- aid = AID_DF_GS;
- efc = EF_C_X509_CH_AUT;
- } else {
- throw new IllegalArgumentException("Keybox " + keyboxName
- + " not supported.");
- }
+ 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) {
- log.debug("Get certificate for keybox '" + keyboxName.getKeyboxName() + "'" +
- " (AID=" + toString(aid) + " EF=" + toString(efc) + ").");
+ try {
+ getCard().beginExclusive();
+ return readTLVFile(AID_DF_GS, EF_C_X509_CH_AUT, 2000);
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
+ } finally {
+ getCard().endExclusive();
+ }
- try {
- Card card = getCardChannel().getCard();
- try {
- card.beginExclusive();
- return readTLVFile(aid, efc, 2000);
- } catch (FileNotFoundException e) {
- // if certificate is not present,
- // the citizen card application has not been activated
- throw new NotActivatedException();
- } finally {
- card.endExclusive();
+ } else {
+ throw new IllegalArgumentException("Keybox " + keyboxName
+ + " not supported.");
}
+
} catch (CardException e) {
- throw new SignatureCardException("Failed to get exclusive card access.");
+ log.warn(e);
+ throw new SignatureCardException("Failed to access card.", e);
}
-
- }
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.SignatureCard#getInfobox(java.lang.String, at.gv.egiz.smcc.PINProvider, java.lang.String)
- */
+ }
+
@Override
public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
throws SignatureCardException, InterruptedException {
- if ("IdentityLink".equals(infobox)) {
-
- PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
-
- try {
- Card card = getCardChannel().getCard();
+ try {
+ if ("IdentityLink".equals(infobox)) {
+
+ PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
+
+ int retries = -1;
+ String pin = null;
+ boolean pinRequiered = false;
+
+ do {
+ if (pinRequiered) {
+ pin = provider.providePIN(spec, retries);
+ if (pin == null) {
+ throw new CancelledException();
+ }
+ }
+ try {
+ getCard().beginExclusive();
+ return readTLVFile(AID_INFOBOX, EF_INFOBOX, pin, KID_PIN_CARD, 2000);
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
+ } catch (SecurityStatusNotSatisfiedException e) {
+ pinRequiered = true;
+ retries = verifyPIN(null, KID_PIN_CARD);
+ } catch (VerificationFailedException e) {
+ pinRequiered = true;
+ retries = e.getRetries();
+ } finally {
+ getCard().endExclusive();
+ }
+ } while (retries != 0);
+
+ throw new LockedException();
+
+
+ } else if ("EHIC".equals(infobox)) {
+
try {
- card.beginExclusive();
- return readTLVFilePIN(AID_INFOBOX, EF_INFOBOX, KID_PIN_CARD,
- provider, spec, 2000);
- } catch (FileNotFoundException e) {
- // if certificate is not present,
- // the citizen card application has not been activated
- throw new NotActivatedException();
+ getCard().beginExclusive();
+ return readTLVFile(AID_SV_PERSONENDATEN, FID_EHIC, 126);
} finally {
- card.endExclusive();
+ getCard().endExclusive();
}
- } catch (CardException e) {
- throw new SignatureCardException("Failed to get exclusive card access.");
+
+ } 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)) {
+
+ try {
+ getCard().beginExclusive();
+ return readRecords(AID_SV_PERSONENDATEN, FID_STATUS, 1, 5);
+ } finally {
+ getCard().endExclusive();
+ }
+
+ } else {
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
}
- } else {
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
+ } catch (CardException e) {
+ log.warn(e);
+ throw new SignatureCardException("Failed to access card.", e);
}
}
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.SignatureCard#createSignature(byte[], at.gv.egiz.smcc.SignatureCard.KeyboxName, at.gv.egiz.smcc.PINProvider)
- */
+ @Override
public byte[] createSignature(byte[] hash, KeyboxName keyboxName,
PINProvider provider) throws SignatureCardException, InterruptedException {
@@ -212,72 +296,115 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
throw new IllegalArgumentException("Hash value must be of length 20.");
}
- byte[] aid;
- byte kid;
- byte[] dst;
- PINSpec spec;
- if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
- aid = AID_DF_SS;
- kid = KID_PIN_SS;
- dst = DST_SS;
- spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));
-
- } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
- aid = AID_DF_GS;
- kid = KID_PIN_CARD;
- dst = DST_GS;
- spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
-
- } else {
- throw new IllegalArgumentException("KeyboxName '" + keyboxName
- + "' not supported.");
- }
-
try {
- Card card = getCardChannel().getCard();
- try {
- card.beginExclusive();
-
- // SELECT MF
- selectMF();
- // SELECT DF
- selectFileAID(aid);
- // VERIFY
- verifyPIN(provider, spec, kid);
- // MSE: SET DST
- mseSetDST(dst);
- // PSO: HASH
- psoHash(hash);
- // PSO: COMPUTE DIGITAL SIGNATURE
- return psoComputDigitalSiganture();
-
-
- } catch (FileNotFoundException e) {
- // if certificate is not present,
- // the citizen card application has not been activated
- throw new NotActivatedException();
- } finally {
- card.endExclusive();
+
+ if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
+
+ PINSpec spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));
+
+ int retries = -1;
+ String pin = null;
+
+ do {
+ try {
+ getCard().beginExclusive();
+ selectFileAID(AID_DF_SS);
+ retries = verifyPIN(null, KID_PIN_SS);
+ } finally {
+ getCard().endExclusive();
+ }
+ pin = provider.providePIN(spec, retries);
+ if (pin == null) {
+ throw new CancelledException();
+ }
+ try {
+ getCard().beginExclusive();
+ return createSignature(hash, AID_DF_SS, pin, KID_PIN_SS, DST_SS);
+ } catch (VerificationFailedException e) {
+ retries = e.getRetries();
+ } finally {
+ getCard().endExclusive();
+ }
+ } while (retries != 0);
+
+ throw new LockedException();
+
+
+ } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
+
+ PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
+
+ int retries = -1;
+ String pin = null;
+ boolean pinRequiered = false;
+
+ do {
+ if (pinRequiered) {
+ pin = provider.providePIN(spec, retries);
+ if (pin == null) {
+ throw new CancelledException();
+ }
+ }
+ try {
+ getCard().beginExclusive();
+ return createSignature(hash, AID_DF_GS, pin, KID_PIN_CARD, DST_GS);
+ } catch (FileNotFoundException e) {
+ throw new NotActivatedException();
+ } catch (SecurityStatusNotSatisfiedException e) {
+ pinRequiered = true;
+ retries = verifyPIN(null, KID_PIN_CARD);
+ } catch (VerificationFailedException e) {
+ pinRequiered = true;
+ retries = e.getRetries();
+ } finally {
+ getCard().endExclusive();
+ }
+ } while (retries != 0);
+
+ throw new LockedException();
+
+ } else {
+ throw new IllegalArgumentException("KeyboxName '" + keyboxName
+ + "' not supported.");
}
+
} catch (CardException e) {
- throw new SignatureCardException("Failed to get exclusive card access.");
+ log.warn(e);
+ throw new SignatureCardException("Failed to access card.", e);
}
}
- protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException {
+ protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04,
+ return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02,
0x04, fid, 256));
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("Failed to select file (AID="
- + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + ".");
- } else {
- return resp.getBytes();
+ }
+
+ private byte[] createSignature(byte[] hash, byte[] aid, String pin, byte kid,
+ byte[] dst) throws CardException, SignatureCardException {
+
+ // SELECT MF
+ selectMF();
+ // SELECT DF
+ selectFileAID(aid);
+ // VERIFY
+ int retries = verifyPIN(pin, kid);
+ if (retries != -1) {
+ throw new VerificationFailedException(retries);
}
+ // MSE: SET DST
+ mseSetDST(dst);
+ // PSO: HASH
+ psoHash(hash);
+ // PSO: COMPUTE DIGITAL SIGNATURE
+ return psoComputDigitalSiganture();
+
+
}
- void selectMF() throws CardException, SignatureCardException {
+
+ private void selectMF() throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,
0x0C));
@@ -287,13 +414,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
}
- protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
- CardChannel channel = getCardChannel();
- return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02,
- 0x04, fid, 256));
- }
-
- void mseSetDST(byte[] dst) throws CardException, SignatureCardException {
+ private void mseSetDST(byte[] dst) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, 0x41,
0xB6, dst));
@@ -303,7 +424,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
}
- void psoHash(byte[] hash) throws CardException, SignatureCardException {
+ 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
@@ -318,7 +439,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
}
- byte[] psoComputDigitalSiganture() throws CardException,
+ private byte[] psoComputDigitalSiganture() throws CardException,
SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x9E,
@@ -353,7 +474,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
* @throws SignatureCardException
* if VERIFY PIN fails
*/
- private int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException {
+ @Override
+ protected int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
@@ -385,6 +507,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
} else if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) {
// return number of possible retries
return resp.getSW2() & 0x0f;
+ } else if (resp.getSW() == 0x6983) {
+ throw new LockedException();
} else if (resp.getSW() == 0x6984) {
// PIN LCS = "Initialized" (-> not activated)
throw new NotActivatedException("PIN not set.");
@@ -397,26 +521,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
- /* (non-Javadoc)
- * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINProvider, at.gv.egiz.smcc.PINSpec, byte, int)
- */
- protected void verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid)
- throws CardException, SignatureCardException, InterruptedException {
-
- int retries = verifyPIN(null, kid);
- do {
- String pin = pinProvider.providePIN(spec, retries);
- if (pin == null) {
- // user canceled operation
- throw new CancelledException("User canceld operation.");
- }
- retries = verifyPIN(pin, kid);
- } while (retries > 0);
-
- }
-
public String toString() {
- return "eCard";
+ return "e-card";
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java b/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java
new file mode 100644
index 00000000..bf0af76c
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.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 SecurityStatusNotSatisfiedException extends SignatureCardException {
+
+ private static final long serialVersionUID = 1L;
+
+ public SecurityStatusNotSatisfiedException() {
+ }
+
+ public SecurityStatusNotSatisfiedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SecurityStatusNotSatisfiedException(String message) {
+ super(message);
+ }
+
+ public SecurityStatusNotSatisfiedException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/VerificationFailedException.java b/smcc/src/main/java/at/gv/egiz/smcc/VerificationFailedException.java
new file mode 100644
index 00000000..fa066ff9
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/VerificationFailedException.java
@@ -0,0 +1,65 @@
+/*
+* 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 VerificationFailedException extends SignatureCardException {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final int UNKNOWN = -1;
+
+ private int retries = UNKNOWN;
+
+ public VerificationFailedException() {
+ }
+
+ public VerificationFailedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public VerificationFailedException(String message) {
+ super(message);
+ }
+
+ public VerificationFailedException(Throwable cause) {
+ super(cause);
+ }
+
+ public VerificationFailedException(int retries) {
+ this.retries = retries;
+ }
+
+ public VerificationFailedException(int retries, String message, Throwable cause) {
+ super(message, cause);
+ this.retries = retries;
+ }
+
+ public VerificationFailedException(int retries, String message) {
+ super(message);
+ this.retries = retries;
+ }
+
+ public VerificationFailedException(int retries, Throwable cause) {
+ super(cause);
+ this.retries = retries;
+ }
+
+ public int getRetries() {
+ return retries;
+ }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
index 13210540..090e1181 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
@@ -19,6 +19,8 @@ package at.gv.egiz.smcc;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
@@ -27,6 +29,8 @@ import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
+import sun.misc.HexDumpEncoder;
+
import at.gv.egiz.smcc.SignatureCard.KeyboxName;
import at.gv.egiz.smcc.util.SMCCHelper;
@@ -34,10 +38,9 @@ public class STARCOSCardTest {
/**
* @param args
- * @throws CardException
- * @throws NoSuchAlgorithmException
+ * @throws Exception
*/
- public static void main(String[] args) throws CardException, NoSuchAlgorithmException, InterruptedException {
+ public static void main(String[] args) throws Exception {
SMCCHelper helper = new SMCCHelper();
while (helper.getResultCode() != SMCCHelper.CARD_FOUND) {
@@ -55,18 +58,41 @@ public class STARCOSCardTest {
System.out.println("Found '" + signatureCard + "'.");
try {
-// signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR);
-// signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR);
-// signatureCard.getInfobox("IdentityLink", new CommandLinePINProvider(), null);
+// printJavaByteArray(
+// signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR), System.out);
+// printJavaByteArray(
+// signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR), System.out);
+// System.out. println(new String(signatureCard.getInfobox("IdentityLink", new CommandLinePINProvider(), null)));
+// byte[] infobox = signatureCard.getInfobox("Status", new CommandLinePINProvider(), null);
+// printJavaByteArray(infobox, System.out);
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
byte[] digest = messageDigest.digest("test".getBytes());
- signatureCard.createSignature(digest, KeyboxName.CERITIFIED_KEYPAIR, new CommandLinePINProvider());
+ byte[] signature = signatureCard.createSignature(digest, KeyboxName.SECURE_SIGNATURE_KEYPAIR, new CommandLinePINProvider());
+ printJavaByteArray(signature, System.out);
} catch (SignatureCardException e) {
e.printStackTrace();
}
}
+ public static void printJavaByteArray(byte[] bytes, OutputStream os) {
+
+ PrintWriter w = new PrintWriter(os);
+
+ w.write("new byte[] {");
+ for (int i = 0; i < bytes.length;) {
+ if (i % 8 == 0) {
+ w.write("\n ");
+ }
+ w.write("(byte) 0x" + Integer.toHexString(0x0F & (bytes[i] >> 4)) + Integer.toHexString(0x0F & bytes[i]));
+ if (++i < bytes.length) {
+ w.write(", ");
+ }
+ }
+ w.write("\n};");
+ w.flush();
+ }
+
private static class CommandLinePINProvider implements PINProvider {
@Override
diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java
index 04f179e7..5a54e97f 100644
--- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java
+++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java
@@ -103,6 +103,9 @@ public class InfoBoxReadRequestHandler extends AbstractRequestHandler implements
stalResp.setInfoboxValue(resp);
return stalResp;
}
+ } catch (IllegalArgumentException e) {
+ log.info("Infobox " + infoBox.getInfoboxIdentifier() + " not supported.");
+ return new ErrorResponse(4002);
} catch (NotActivatedException e) {
log.info("Citizen card not activated.", e);
gui.showErrorDialog(BKUGUIFacade.ERR_CARD_NOTACTIVATED, null, this, null);