From ea1407ba9756252666e5d67f2397d7cb44ba0232 Mon Sep 17 00:00:00 2001 From: tkellner Date: Wed, 22 Jun 2011 14:30:14 +0000 Subject: License change copyright headers changed/added License text added NOTICE modified git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@940 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java | 38 +- .../main/java/at/gv/egiz/smcc/AbstractISCard.java | 296 +-- .../at/gv/egiz/smcc/AbstractSignatureCard.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java | 38 +- .../at/gv/egiz/smcc/CIOCertificateDirectory.java | 38 +- .../java/at/gv/egiz/smcc/CancelledException.java | 84 +- .../at/gv/egiz/smcc/CardNotSupportedException.java | 38 +- .../gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java | 38 +- .../gv/egiz/smcc/DNIeCIOCertificateDirectory.java | 140 +- .../main/java/at/gv/egiz/smcc/DNIeCryptoUtil.java | 696 +++--- .../java/at/gv/egiz/smcc/DNIeSecuredChannel.java | 2288 ++++++++++---------- smcc/src/main/java/at/gv/egiz/smcc/ESDNIeCard.java | 1016 ++++----- smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java | 37 +- .../at/gv/egiz/smcc/ExclSignatureCardProxy.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java | 38 +- .../java/at/gv/egiz/smcc/FINEIDAODirectory.java | 294 +-- .../gv/egiz/smcc/FINEIDAuthenticationObject.java | 122 +- .../egiz/smcc/FINEIDCIOCertificateDirectory.java | 101 +- .../at/gv/egiz/smcc/FINEIDCIOKeyDirectory.java | 73 +- smcc/src/main/java/at/gv/egiz/smcc/FINEIDCard.java | 737 +++---- .../at/gv/egiz/smcc/FINEIDEFObjectDirectory.java | 63 +- smcc/src/main/java/at/gv/egiz/smcc/FINEIDUtil.java | 82 +- .../at/gv/egiz/smcc/FileNotFoundException.java | 38 +- .../main/java/at/gv/egiz/smcc/ISMAESTROCard.java | 824 +++---- .../java/at/gv/egiz/smcc/ISVISAElectronCard.java | 828 +++---- smcc/src/main/java/at/gv/egiz/smcc/ITCard.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/Infobox.java | 38 +- .../java/at/gv/egiz/smcc/InfoboxContainer.java | 38 +- .../java/at/gv/egiz/smcc/InfoboxException.java | 38 +- .../java/at/gv/egiz/smcc/LIEZertifikatCard.java | 38 +- .../main/java/at/gv/egiz/smcc/LockedException.java | 38 +- .../main/java/at/gv/egiz/smcc/LogCardChannel.java | 38 +- .../java/at/gv/egiz/smcc/LtEIDCIOCertificate.java | 165 +- .../gv/egiz/smcc/LtEIDCIOCertificateDirectory.java | 173 +- .../src/main/java/at/gv/egiz/smcc/LtEIDCIOKey.java | 113 +- .../java/at/gv/egiz/smcc/LtEIDCIOKeyDirectory.java | 99 +- smcc/src/main/java/at/gv/egiz/smcc/LtEIDCard.java | 1059 ++++----- .../java/at/gv/egiz/smcc/LtEIDObjectDirectory.java | 65 +- .../at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java | 38 +- .../at/gv/egiz/smcc/NotActivatedException.java | 38 +- .../at/gv/egiz/smcc/PINConfirmationException.java | 38 +- .../java/at/gv/egiz/smcc/PINFormatException.java | 38 +- .../java/at/gv/egiz/smcc/PINMgmtSignatureCard.java | 38 +- .../gv/egiz/smcc/PINOperationAbortedException.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/PinInfo.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java | 38 +- .../at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java | 38 +- .../main/java/at/gv/egiz/smcc/SEIdentityCard.java | 662 +++--- .../src/main/java/at/gv/egiz/smcc/STARCOSCard.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/SWCard.java | 38 +- .../smcc/SecurityStatusNotSatisfiedException.java | 38 +- .../main/java/at/gv/egiz/smcc/SignatureCard.java | 38 +- .../at/gv/egiz/smcc/SignatureCardException.java | 38 +- .../java/at/gv/egiz/smcc/SignatureCardFactory.java | 28 +- .../main/java/at/gv/egiz/smcc/SuisseIDCard.java | 38 +- .../main/java/at/gv/egiz/smcc/T0CardChannel.java | 196 +- .../java/at/gv/egiz/smcc/TimeoutException.java | 38 +- .../main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/cio/CIO.java | 38 +- .../java/at/gv/egiz/smcc/cio/CIOCertificate.java | 38 +- .../gv/egiz/smcc/cio/CIOCertificateDirectory.java | 28 +- .../java/at/gv/egiz/smcc/cio/CIODirectoryFile.java | 28 +- .../cio/LIEZertifikatCertificateDirectory.java | 28 +- .../java/at/gv/egiz/smcc/cio/ObjectDirectory.java | 28 +- .../at/gv/egiz/smcc/conf/SMCCConfiguration.java | 32 +- .../java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java | 38 +- .../at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java | 38 +- .../main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java | 38 +- .../java/at/gv/egiz/smcc/pin/gui/PINProvider.java | 38 +- .../java/at/gv/egiz/smcc/reader/CardReader.java | 28 +- .../at/gv/egiz/smcc/reader/DefaultCardReader.java | 28 +- .../at/gv/egiz/smcc/reader/PinpadCardReader.java | 28 +- .../java/at/gv/egiz/smcc/reader/ReaderFactory.java | 28 +- .../java/at/gv/egiz/smcc/util/ISO7816Utils.java | 28 +- .../main/java/at/gv/egiz/smcc/util/SMCCHelper.java | 38 +- .../java/at/gv/egiz/smcc/util/SmartCardIO.java | 38 +- smcc/src/main/java/at/gv/egiz/smcc/util/TLV.java | 33 +- .../java/at/gv/egiz/smcc/util/TLVSequence.java | 28 +- .../egiz/smcc/util/TransparentFileInputStream.java | 28 +- 79 files changed, 6462 insertions(+), 5710 deletions(-) (limited to 'smcc/src/main/java/at/gv/egiz') 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 b2e21707..33ae00d4 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractISCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractISCard.java index bc1a342f..7a1c6a66 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractISCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractISCard.java @@ -1,136 +1,160 @@ -package at.gv.egiz.smcc; - -import iaik.me.asn1.ASN1; - -import java.io.IOException; -import java.util.Arrays; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.util.TLV; - -public abstract class AbstractISCard extends AbstractSignatureCard implements - SignatureCard { - - private final Logger log = LoggerFactory.getLogger(AbstractISCard.class); - - protected static final byte[] OID = 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 }; - - protected abstract byte[] getAppletID(); - - protected void selectApplet(CardChannel channel) throws CardException, - SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x04, (byte) 0x00, getAppletID()); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Error selecting card applet. Unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - } - - protected int toInt(byte[] array) { - - int len = array.length; - int result = 0; - - for (int i = len - 1; i >= 0; i--) { - - int currentByte = (int)array[i]; - currentByte = currentByte < 0 ? currentByte+256 : currentByte; - - result = result + (int)(currentByte * Math.pow(256, len - i - 1)); - } - - return result; - } - - protected byte[] retrieveSigningCertificate(byte[] certData, byte[] certsMetaInfo, String identifier) throws SignatureCardException, IOException { - - byte[] cert = null; - - ASN1 meta1 = new ASN1(certsMetaInfo); - int meta1Length = meta1.getEncoded().length; - - byte[] meta2Data = new byte[certsMetaInfo.length - meta1Length]; - System.arraycopy(certsMetaInfo, meta1Length, meta2Data, 0, - meta2Data.length); - ASN1 meta2 = new ASN1(meta2Data); - - if (meta1.getElementAt(0).getElementAt(0).gvString() - .contains(identifier)) { - - cert = retrieveCertFromFile(certData, meta1); - } else if (meta2.getElementAt(0).getElementAt(0).gvString() - .contains(identifier)) { - - cert = retrieveCertFromFile(certData, meta2); - } else { - - throw new SignatureCardException( - "Cannot find certificate meta information."); - } - - return cert; - } - - protected byte[] retrieveCertFromFile(byte[] certsData, ASN1 metaInfo) - throws SignatureCardException { - - byte[] cert = null; - - byte[] contextSpecificData; - try { - contextSpecificData = metaInfo.getElementAt(metaInfo.getSize() - 1) - .getEncoded(); - - if ((contextSpecificData[0] & 0xff) == 0xa1) { - int ll = ((contextSpecificData[1] & 0xf0) == 0x80) ? (contextSpecificData[1] & 0x0f) + 2 - : 2; - ASN1 info = new ASN1(Arrays.copyOfRange(contextSpecificData, - ll, contextSpecificData.length)); - - int offset = info.getElementAt(0).getElementAt(1).gvInt(); - byte[] contextSpecific = info.getElementAt(0).getElementAt(2) - .getEncoded(); - int length = toInt(new TLV(contextSpecific, 0).getValue()); - - cert = new byte[length]; - - System.arraycopy(certsData, offset, cert, 0, length); - } else { - - throw new SignatureCardException( - "Cannot retrieve enduser certificate."); - } - - } catch (IOException e) { - - throw new SignatureCardException( - "Cannot retrieve enduser certificate.", e); - } - - if (cert == null) { - - log.error("Retrieved certificate is null."); - throw new SignatureCardException( - "Cannot retrieve enduser certificate."); - } - - return cert; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import iaik.me.asn1.ASN1; + +import java.io.IOException; +import java.util.Arrays; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.util.TLV; + +public abstract class AbstractISCard extends AbstractSignatureCard implements + SignatureCard { + + private final Logger log = LoggerFactory.getLogger(AbstractISCard.class); + + protected static final byte[] OID = 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 }; + + protected abstract byte[] getAppletID(); + + protected void selectApplet(CardChannel channel) throws CardException, + SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x04, (byte) 0x00, getAppletID()); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Error selecting card applet. Unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + } + + protected int toInt(byte[] array) { + + int len = array.length; + int result = 0; + + for (int i = len - 1; i >= 0; i--) { + + int currentByte = (int)array[i]; + currentByte = currentByte < 0 ? currentByte+256 : currentByte; + + result = result + (int)(currentByte * Math.pow(256, len - i - 1)); + } + + return result; + } + + protected byte[] retrieveSigningCertificate(byte[] certData, byte[] certsMetaInfo, String identifier) throws SignatureCardException, IOException { + + byte[] cert = null; + + ASN1 meta1 = new ASN1(certsMetaInfo); + int meta1Length = meta1.getEncoded().length; + + byte[] meta2Data = new byte[certsMetaInfo.length - meta1Length]; + System.arraycopy(certsMetaInfo, meta1Length, meta2Data, 0, + meta2Data.length); + ASN1 meta2 = new ASN1(meta2Data); + + if (meta1.getElementAt(0).getElementAt(0).gvString() + .contains(identifier)) { + + cert = retrieveCertFromFile(certData, meta1); + } else if (meta2.getElementAt(0).getElementAt(0).gvString() + .contains(identifier)) { + + cert = retrieveCertFromFile(certData, meta2); + } else { + + throw new SignatureCardException( + "Cannot find certificate meta information."); + } + + return cert; + } + + protected byte[] retrieveCertFromFile(byte[] certsData, ASN1 metaInfo) + throws SignatureCardException { + + byte[] cert = null; + + byte[] contextSpecificData; + try { + contextSpecificData = metaInfo.getElementAt(metaInfo.getSize() - 1) + .getEncoded(); + + if ((contextSpecificData[0] & 0xff) == 0xa1) { + int ll = ((contextSpecificData[1] & 0xf0) == 0x80) ? (contextSpecificData[1] & 0x0f) + 2 + : 2; + ASN1 info = new ASN1(Arrays.copyOfRange(contextSpecificData, + ll, contextSpecificData.length)); + + int offset = info.getElementAt(0).getElementAt(1).gvInt(); + byte[] contextSpecific = info.getElementAt(0).getElementAt(2) + .getEncoded(); + int length = toInt(new TLV(contextSpecific, 0).getValue()); + + cert = new byte[length]; + + System.arraycopy(certsData, offset, cert, 0, length); + } else { + + throw new SignatureCardException( + "Cannot retrieve enduser certificate."); + } + + } catch (IOException e) { + + throw new SignatureCardException( + "Cannot retrieve enduser certificate.", e); + } + + if (cert == null) { + + log.error("Retrieved certificate is null."); + throw new SignatureCardException( + "Cannot retrieve enduser certificate."); + } + + return cert; + } +} 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 a31e746f..cad7ecf0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import at.gv.egiz.smcc.reader.CardReader; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java b/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java index 76569305..9aa170ee 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificateDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificateDirectory.java index 40471e4e..e7a39f0e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificateDirectory.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/CancelledException.java b/smcc/src/main/java/at/gv/egiz/smcc/CancelledException.java index 347d74c9..5abf14b7 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/CancelledException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/CancelledException.java @@ -1,39 +1,47 @@ /* -* 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 CancelledException extends SignatureCardException { - - private static final long serialVersionUID = 1L; - - public CancelledException() { - super(); - } - - public CancelledException(String message, Throwable cause) { - super(message, cause); - } - - public CancelledException(String message) { - super(message); - } - - public CancelledException(Throwable cause) { - super(cause); - } - -} + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +public class CancelledException extends SignatureCardException { + + private static final long serialVersionUID = 1L; + + public CancelledException() { + super(); + } + + public CancelledException(String message, Throwable cause) { + super(message, cause); + } + + public CancelledException(String message) { + super(message); + } + + public CancelledException(Throwable cause) { + super(cause); + } + +} 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 1cde093d..a8169604 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/CardNotSupportedException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/CardNotSupportedException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class CardNotSupportedException extends Exception { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java index 0b10d88f..f7cf5c19 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ChangeReferenceDataAPDUSpec.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class ChangeReferenceDataAPDUSpec extends VerifyAPDUSpec { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/DNIeCIOCertificateDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/DNIeCIOCertificateDirectory.java index 1c16797f..bbfdecac 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/DNIeCIOCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/DNIeCIOCertificateDirectory.java @@ -1,58 +1,82 @@ -package at.gv.egiz.smcc; - -import java.io.IOException; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.SMCCHelper; -import at.gv.egiz.smcc.util.TLVSequence; - -public class DNIeCIOCertificateDirectory extends CIOCertificateDirectory { - - protected static final boolean RETRIEVE_AUTH_ID_FROM_ASN1 = Boolean.FALSE; - - public DNIeCIOCertificateDirectory(byte[] fid) { - - super(fid); - } - - @Override - public void selectAndRead(CardChannel channel) throws CardException, SignatureCardException, IOException { - - CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x00, 0x00, fid, 256); - ResponseAPDU resp = channel.transmit(cmd); - - if(resp.getSW() != 0x9000) { - - throw new CardException("Error selecting DNIeCIOCertificateDeirectory: " + Integer.toHexString(resp.getSW())); - } - - byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCI); - byte[] fd = new TLVSequence(fcx).getValue(0x85); // proprietary - - if(fd.length < 5 || - fd[0] != (byte)0x01 || - fd[1] != fid[0] || - fd[2] != fid[1]) { - - throw new CardException("Error reading CDF - invalid FCI: " + SMCCHelper.toString(resp.getData())); - } - - readCIOCertificatesFromTransparentFile(channel); - } - - protected byte[] doReadTransparentFile(CardChannel channel) throws CardException, SignatureCardException { - - return ISO7816Utils.readTransparentFile(channel, -1, 0xef); - } - - protected boolean retrieveAuthIdFromASN1() { - - return RETRIEVE_AUTH_ID_FROM_ASN1; - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.IOException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.SMCCHelper; +import at.gv.egiz.smcc.util.TLVSequence; + +public class DNIeCIOCertificateDirectory extends CIOCertificateDirectory { + + protected static final boolean RETRIEVE_AUTH_ID_FROM_ASN1 = Boolean.FALSE; + + public DNIeCIOCertificateDirectory(byte[] fid) { + + super(fid); + } + + @Override + public void selectAndRead(CardChannel channel) throws CardException, SignatureCardException, IOException { + + CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x00, 0x00, fid, 256); + ResponseAPDU resp = channel.transmit(cmd); + + if(resp.getSW() != 0x9000) { + + throw new CardException("Error selecting DNIeCIOCertificateDeirectory: " + Integer.toHexString(resp.getSW())); + } + + byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCI); + byte[] fd = new TLVSequence(fcx).getValue(0x85); // proprietary + + if(fd.length < 5 || + fd[0] != (byte)0x01 || + fd[1] != fid[0] || + fd[2] != fid[1]) { + + throw new CardException("Error reading CDF - invalid FCI: " + SMCCHelper.toString(resp.getData())); + } + + readCIOCertificatesFromTransparentFile(channel); + } + + protected byte[] doReadTransparentFile(CardChannel channel) throws CardException, SignatureCardException { + + return ISO7816Utils.readTransparentFile(channel, -1, 0xef); + } + + protected boolean retrieveAuthIdFromASN1() { + + return RETRIEVE_AUTH_ID_FROM_ASN1; + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/DNIeCryptoUtil.java b/smcc/src/main/java/at/gv/egiz/smcc/DNIeCryptoUtil.java index 0f6cef59..c4e27d08 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/DNIeCryptoUtil.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/DNIeCryptoUtil.java @@ -1,336 +1,360 @@ -package at.gv.egiz.smcc; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.KeySpec; -import java.security.spec.RSAPrivateKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.Arrays; -import java.util.Random; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.smartcardio.CardException; - -public class DNIeCryptoUtil { - - private final static byte[] IV = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 }; - - public static X509Certificate createCertificate(byte[] certData) - throws CardException { - - try { - InputStream inStream = new ByteArrayInputStream(certData); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate certificate = (X509Certificate) cf - .generateCertificate(inStream); - inStream.close(); - - return certificate; - - } catch (Exception e) { - - throw new CardException("Unable to create certificate.", e); - } - } - - public static RSAPrivateKey createRSAPrivateKey(String mod, - String privExponent) throws CardException { - - BigInteger modulus = new BigInteger(mod, 16); - BigInteger privExp = new BigInteger(privExponent, 16); - - KeyFactory fac; - RSAPrivateKey key; - try { - fac = KeyFactory.getInstance("RSA"); - KeySpec spec = new RSAPrivateKeySpec(modulus, privExp); - key = (RSAPrivateKey) fac.generatePrivate(spec); - } catch (Exception e) { - - throw new CardException("Unable to create private key.", e); - } - - return key; - } - - public static RSAPublicKey createRSAPublicKey(String mod, String pubExponent) - throws CardException { - - BigInteger modulus = new BigInteger(mod, 16); - BigInteger pubExp = new BigInteger(pubExponent, 16); - - KeyFactory fac; - RSAPublicKey key; - try { - fac = KeyFactory.getInstance("RSA"); - KeySpec spec = new RSAPublicKeySpec(modulus, pubExp); - key = (RSAPublicKey) fac.generatePublic(spec); - } catch (Exception e) { - - throw new CardException("Unable to create public key.", e); - } - - return key; - } - - public static byte[] getRandomBytes(int length) { - - byte[] result = new byte[length]; - - for (int i = 0; i < length; i++) { - - Random rand = new Random(); - byte current = (byte) rand.nextInt(255); - result[i] = current; - } - - return result; - } - - public static byte[] computeSHA1Hash(byte[] data) throws CardException { - - try { - MessageDigest sha = MessageDigest.getInstance("SHA"); - - sha.update(data); - return sha.digest(); - - } catch (NoSuchAlgorithmException e) { - throw new CardException("Error computing SHA1 hash.", e); - } - - } - - public static byte[] rsaEncrypt(Key key, byte[] data) - throws NoSuchAlgorithmException, NoSuchPaddingException, - InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - - Cipher rsa = Cipher.getInstance("RSA/ECB/NoPadding"); - rsa.init(Cipher.ENCRYPT_MODE, key); - byte[] encrypted = rsa.doFinal(data); - - return encrypted; - - } - - public static byte[] rsaDecrypt(Key key, byte[] cipher) - throws NoSuchAlgorithmException, NoSuchPaddingException, - InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - - Cipher rsa = Cipher.getInstance("RSA/ECB/NoPadding"); - rsa.init(Cipher.DECRYPT_MODE, key); - byte[] decrypted = rsa.doFinal(cipher); - - return decrypted; - } - - public static byte[] applyPadding(int blockSize, byte[] data) { - - // add mandatory 0x80 - byte[] extended = new byte[data.length + 1]; - System.arraycopy(data, 0, extended, 0, data.length); - extended[extended.length - 1] = (byte) 0x80; - - if (extended.length % blockSize == 0) { - - return extended; - } - - int requiredBlocks = ((int) (extended.length / blockSize) + 1); - - byte[] result = new byte[requiredBlocks * blockSize]; - Arrays.fill(result, (byte) 0x00); - System.arraycopy(extended, 0, result, 0, extended.length); - - return result; - - } - - public static byte[] removePadding(byte[] paddedData) throws CardException { - - for (int i = paddedData.length - 1; i >= 0; i--) { - - byte current = paddedData[i]; - - if (current == (byte) 0x00) { - - continue; - } - - if (current == (byte) 0x80) { - - // end of padding reached - byte[] data = new byte[i]; - System.arraycopy(paddedData, 0, data, 0, i); - return data; - - } else { - - throw new CardException("Wrong padding."); - } - } - - throw new CardException( - "Error removing padding from data. Unexpected data format."); - - } - - public static byte[] calculateAPDUMAC(byte[] data, byte[] key, byte[] ssc, - int blockLength) throws CardException { - - SecretKeySpec desSingleKey = new SecretKeySpec(key, 0, blockLength, - "DES"); - Cipher singleDesCipher; - try { - singleDesCipher = Cipher.getInstance("DES/CBC/NoPadding"); - } catch (Exception e) { - - throw new CardException("Error creating DES cipher instance.", e); - } - - // Calculate the first n - 1 block. - IvParameterSpec ivSpec; - ivSpec = new IvParameterSpec(IV); - int dataLen = data.length; - - try { - singleDesCipher.init(Cipher.ENCRYPT_MODE, desSingleKey, ivSpec); - } catch (Exception e) { - throw new CardException("Error initializing DES cipher.", e); - } - byte[] result; - try { - result = singleDesCipher.doFinal(ssc); - } catch (Exception e) { - throw new CardException("Error applying DES cipher.", e); - } - - byte[] dataBlock = new byte[blockLength]; - - for (int i = 0; i < dataLen - blockLength; i = i + blockLength) { - - System.arraycopy(data, i, dataBlock, 0, blockLength); - byte[] input = xorByteArrays(result, dataBlock); - - try { - result = singleDesCipher.doFinal(input); - } catch (Exception e) { - throw new CardException("Error applying DES cipher.", e); - } - } - - // calculate the last block with 3DES - byte[] fullKey = new byte[24]; - System.arraycopy(key, 0, fullKey, 0, 16); - System.arraycopy(key, 0, fullKey, 16, 8); - - SecretKeySpec desKey = new SecretKeySpec(fullKey, "DESede"); - Cipher cipher; - try { - cipher = Cipher.getInstance("DESede/CBC/NoPadding"); - } catch (Exception e) { - throw new CardException("Error getting 3DES cipher instance.", e); - } - - ivSpec = new IvParameterSpec(IV); - try { - cipher.init(Cipher.ENCRYPT_MODE, desKey, ivSpec); - } catch (Exception e) { - throw new CardException("Error initializing 3DES cipher.", e); - } - - System.arraycopy(data, data.length - blockLength, dataBlock, 0, - blockLength); - byte[] input = xorByteArrays(result, dataBlock); - - byte[] mac = new byte[4]; - - try { - - result = cipher.doFinal(input); - - } catch (Exception e) { - throw new CardException("Error applying 3DES cipher.", e); - } - - System.arraycopy(result, 0, mac, 0, 4); - return mac; - } - - public static byte[] xorByteArrays(byte[] array1, byte[] array2) - throws CardException { - - if (array1 == null || array2 == null || array1.length != array2.length) { - - throw new CardException("Cannot xor byte arrays - invalid input."); - } - - byte[] result = new byte[array1.length]; - - for (int i = 0; i < array1.length; i++) { - - result[i] = (byte) (array1[i] ^ array2[i]); - } - - return result; - } - - public static byte[] perform3DESCipherOperation(byte[] data, - byte[] keyData, int mode) throws NoSuchAlgorithmException, - NoSuchProviderException, NoSuchPaddingException, - InvalidKeyException, InvalidAlgorithmParameterException, - ShortBufferException, IllegalBlockSizeException, - BadPaddingException { - - byte[] full3DESKey = new byte[24]; - System.arraycopy(keyData, 0, full3DESKey, 0, 16); - System.arraycopy(keyData, 0, full3DESKey, 16, 8); - - SecretKeySpec key = new SecretKeySpec(full3DESKey, "DESede"); - IvParameterSpec ivSpec = new IvParameterSpec(IV); - - Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding"); - - cipher.init(mode, key, ivSpec); - byte[] cipherText = new byte[cipher.getOutputSize(data.length)]; - int ctLength = cipher.update(data, 0, data.length, cipherText, 0); - ctLength += cipher.doFinal(cipherText, ctLength); - return cipherText; - - } - - public static int getCutOffLength(byte[] data, int blockSize) - throws CardException { - - int len = data.length % blockSize; - - // verify - if (data[len - 1] == (byte) 0x01) { - - return len; - } else { - throw new CardException( - "Unable to reconstruct encrypted datablock."); - } - - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.KeySpec; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Arrays; +import java.util.Random; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.smartcardio.CardException; + +public class DNIeCryptoUtil { + + private final static byte[] IV = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }; + + public static X509Certificate createCertificate(byte[] certData) + throws CardException { + + try { + InputStream inStream = new ByteArrayInputStream(certData); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate certificate = (X509Certificate) cf + .generateCertificate(inStream); + inStream.close(); + + return certificate; + + } catch (Exception e) { + + throw new CardException("Unable to create certificate.", e); + } + } + + public static RSAPrivateKey createRSAPrivateKey(String mod, + String privExponent) throws CardException { + + BigInteger modulus = new BigInteger(mod, 16); + BigInteger privExp = new BigInteger(privExponent, 16); + + KeyFactory fac; + RSAPrivateKey key; + try { + fac = KeyFactory.getInstance("RSA"); + KeySpec spec = new RSAPrivateKeySpec(modulus, privExp); + key = (RSAPrivateKey) fac.generatePrivate(spec); + } catch (Exception e) { + + throw new CardException("Unable to create private key.", e); + } + + return key; + } + + public static RSAPublicKey createRSAPublicKey(String mod, String pubExponent) + throws CardException { + + BigInteger modulus = new BigInteger(mod, 16); + BigInteger pubExp = new BigInteger(pubExponent, 16); + + KeyFactory fac; + RSAPublicKey key; + try { + fac = KeyFactory.getInstance("RSA"); + KeySpec spec = new RSAPublicKeySpec(modulus, pubExp); + key = (RSAPublicKey) fac.generatePublic(spec); + } catch (Exception e) { + + throw new CardException("Unable to create public key.", e); + } + + return key; + } + + public static byte[] getRandomBytes(int length) { + + byte[] result = new byte[length]; + + for (int i = 0; i < length; i++) { + + Random rand = new Random(); + byte current = (byte) rand.nextInt(255); + result[i] = current; + } + + return result; + } + + public static byte[] computeSHA1Hash(byte[] data) throws CardException { + + try { + MessageDigest sha = MessageDigest.getInstance("SHA"); + + sha.update(data); + return sha.digest(); + + } catch (NoSuchAlgorithmException e) { + throw new CardException("Error computing SHA1 hash.", e); + } + + } + + public static byte[] rsaEncrypt(Key key, byte[] data) + throws NoSuchAlgorithmException, NoSuchPaddingException, + InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + + Cipher rsa = Cipher.getInstance("RSA/ECB/NoPadding"); + rsa.init(Cipher.ENCRYPT_MODE, key); + byte[] encrypted = rsa.doFinal(data); + + return encrypted; + + } + + public static byte[] rsaDecrypt(Key key, byte[] cipher) + throws NoSuchAlgorithmException, NoSuchPaddingException, + InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + + Cipher rsa = Cipher.getInstance("RSA/ECB/NoPadding"); + rsa.init(Cipher.DECRYPT_MODE, key); + byte[] decrypted = rsa.doFinal(cipher); + + return decrypted; + } + + public static byte[] applyPadding(int blockSize, byte[] data) { + + // add mandatory 0x80 + byte[] extended = new byte[data.length + 1]; + System.arraycopy(data, 0, extended, 0, data.length); + extended[extended.length - 1] = (byte) 0x80; + + if (extended.length % blockSize == 0) { + + return extended; + } + + int requiredBlocks = ((int) (extended.length / blockSize) + 1); + + byte[] result = new byte[requiredBlocks * blockSize]; + Arrays.fill(result, (byte) 0x00); + System.arraycopy(extended, 0, result, 0, extended.length); + + return result; + + } + + public static byte[] removePadding(byte[] paddedData) throws CardException { + + for (int i = paddedData.length - 1; i >= 0; i--) { + + byte current = paddedData[i]; + + if (current == (byte) 0x00) { + + continue; + } + + if (current == (byte) 0x80) { + + // end of padding reached + byte[] data = new byte[i]; + System.arraycopy(paddedData, 0, data, 0, i); + return data; + + } else { + + throw new CardException("Wrong padding."); + } + } + + throw new CardException( + "Error removing padding from data. Unexpected data format."); + + } + + public static byte[] calculateAPDUMAC(byte[] data, byte[] key, byte[] ssc, + int blockLength) throws CardException { + + SecretKeySpec desSingleKey = new SecretKeySpec(key, 0, blockLength, + "DES"); + Cipher singleDesCipher; + try { + singleDesCipher = Cipher.getInstance("DES/CBC/NoPadding"); + } catch (Exception e) { + + throw new CardException("Error creating DES cipher instance.", e); + } + + // Calculate the first n - 1 block. + IvParameterSpec ivSpec; + ivSpec = new IvParameterSpec(IV); + int dataLen = data.length; + + try { + singleDesCipher.init(Cipher.ENCRYPT_MODE, desSingleKey, ivSpec); + } catch (Exception e) { + throw new CardException("Error initializing DES cipher.", e); + } + byte[] result; + try { + result = singleDesCipher.doFinal(ssc); + } catch (Exception e) { + throw new CardException("Error applying DES cipher.", e); + } + + byte[] dataBlock = new byte[blockLength]; + + for (int i = 0; i < dataLen - blockLength; i = i + blockLength) { + + System.arraycopy(data, i, dataBlock, 0, blockLength); + byte[] input = xorByteArrays(result, dataBlock); + + try { + result = singleDesCipher.doFinal(input); + } catch (Exception e) { + throw new CardException("Error applying DES cipher.", e); + } + } + + // calculate the last block with 3DES + byte[] fullKey = new byte[24]; + System.arraycopy(key, 0, fullKey, 0, 16); + System.arraycopy(key, 0, fullKey, 16, 8); + + SecretKeySpec desKey = new SecretKeySpec(fullKey, "DESede"); + Cipher cipher; + try { + cipher = Cipher.getInstance("DESede/CBC/NoPadding"); + } catch (Exception e) { + throw new CardException("Error getting 3DES cipher instance.", e); + } + + ivSpec = new IvParameterSpec(IV); + try { + cipher.init(Cipher.ENCRYPT_MODE, desKey, ivSpec); + } catch (Exception e) { + throw new CardException("Error initializing 3DES cipher.", e); + } + + System.arraycopy(data, data.length - blockLength, dataBlock, 0, + blockLength); + byte[] input = xorByteArrays(result, dataBlock); + + byte[] mac = new byte[4]; + + try { + + result = cipher.doFinal(input); + + } catch (Exception e) { + throw new CardException("Error applying 3DES cipher.", e); + } + + System.arraycopy(result, 0, mac, 0, 4); + return mac; + } + + public static byte[] xorByteArrays(byte[] array1, byte[] array2) + throws CardException { + + if (array1 == null || array2 == null || array1.length != array2.length) { + + throw new CardException("Cannot xor byte arrays - invalid input."); + } + + byte[] result = new byte[array1.length]; + + for (int i = 0; i < array1.length; i++) { + + result[i] = (byte) (array1[i] ^ array2[i]); + } + + return result; + } + + public static byte[] perform3DESCipherOperation(byte[] data, + byte[] keyData, int mode) throws NoSuchAlgorithmException, + NoSuchProviderException, NoSuchPaddingException, + InvalidKeyException, InvalidAlgorithmParameterException, + ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + + byte[] full3DESKey = new byte[24]; + System.arraycopy(keyData, 0, full3DESKey, 0, 16); + System.arraycopy(keyData, 0, full3DESKey, 16, 8); + + SecretKeySpec key = new SecretKeySpec(full3DESKey, "DESede"); + IvParameterSpec ivSpec = new IvParameterSpec(IV); + + Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding"); + + cipher.init(mode, key, ivSpec); + byte[] cipherText = new byte[cipher.getOutputSize(data.length)]; + int ctLength = cipher.update(data, 0, data.length, cipherText, 0); + ctLength += cipher.doFinal(cipherText, ctLength); + return cipherText; + + } + + public static int getCutOffLength(byte[] data, int blockSize) + throws CardException { + + int len = data.length % blockSize; + + // verify + if (data[len - 1] == (byte) 0x01) { + + return len; + } else { + throw new CardException( + "Unable to reconstruct encrypted datablock."); + } + + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/DNIeSecuredChannel.java b/smcc/src/main/java/at/gv/egiz/smcc/DNIeSecuredChannel.java index 858a6cc5..6f3f3a89 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/DNIeSecuredChannel.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/DNIeSecuredChannel.java @@ -1,1132 +1,1156 @@ -package at.gv.egiz.smcc; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.security.PublicKey; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.util.Arrays; - -import javax.crypto.Cipher; -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.util.SMCCHelper; - -public class DNIeSecuredChannel extends T0CardChannel { - - // Public key data of Root CA - required to validate card certificates - private static final String ROOT_CA_MODULO = "EADEDA455332945039DAA404C8EBC4D3B7F5DC869283CDEA2F101E2AB54FB0D0B03D8F030DAF2458028288F54CE552F8FA57AB2FB103B112427E11131D1D27E10A5B500EAAE5D940301E30EB26C3E9066B257156ED639D70CCC090B863AFBB3BFED8C17BE7673034B9823E977ED657252927F9575B9FFF6691DB64F80B5E92CD"; - private static final String ROOT_CA_PUBEXP = "010001"; - - // Terminal private RSA key for secure channel establishment - private final String TERMINAL_MODULO = "DB2CB41E112BACFA2BD7C3D3D7967E84FB9434FC261F9D090A8983947DAF8488D3DF8FBDCC1F92493585E134A1B42DE519F463244D7ED384E26D516CC7A4FF7895B1992140043AACADFC12E856B202346AF8226B1A882137DC3C5A57F0D2815C1FCD4BB46FA9157FDFFD79EC3A10A824CCC1EB3CE0B6B4396AE236590016BA69"; - private final String TERMINAL_PRIVEXP = "18B44A3D155C61EBF4E3261C8BB157E36F63FE30E9AF28892B59E2ADEB18CC8C8BAD284B9165819CA4DEC94AA06B69BCE81706D1C1B668EB128695E5F7FEDE18A908A3011A646A481D3EA71D8A387D474609BD57A882B182E047DE80E04B4221416BD39DFA1FAC0300641962ADB109E28CAF50061B68C9CABD9B00313C0F46ED"; - - private final byte[] C_CV_CA = new byte[] { - - (byte) 0x7F, (byte) 0x21, (byte) 0x81, (byte) 0xCE, (byte) 0x5F, - (byte) 0x37, (byte) 0x81, (byte) 0x80, (byte) 0x3C, (byte) 0xBA, - (byte) 0xDC, (byte) 0x36, (byte) 0x84, (byte) 0xBE, (byte) 0xF3, - (byte) 0x20, (byte) 0x41, (byte) 0xAD, (byte) 0x15, (byte) 0x50, - (byte) 0x89, (byte) 0x25, (byte) 0x8D, (byte) 0xFD, (byte) 0x20, - (byte) 0xC6, (byte) 0x91, (byte) 0x15, (byte) 0xD7, (byte) 0x2F, - (byte) 0x9C, (byte) 0x38, (byte) 0xAA, (byte) 0x99, (byte) 0xAD, - (byte) 0x6C, (byte) 0x1A, (byte) 0xED, (byte) 0xFA, (byte) 0xB2, - (byte) 0xBF, (byte) 0xAC, (byte) 0x90, (byte) 0x92, (byte) 0xFC, - (byte) 0x70, (byte) 0xCC, (byte) 0xC0, (byte) 0x0C, (byte) 0xAF, - (byte) 0x48, (byte) 0x2A, (byte) 0x4B, (byte) 0xE3, (byte) 0x1A, - (byte) 0xFD, (byte) 0xBD, (byte) 0x3C, (byte) 0xBC, (byte) 0x8C, - (byte) 0x83, (byte) 0x82, (byte) 0xCF, (byte) 0x06, (byte) 0xBC, - (byte) 0x07, (byte) 0x19, (byte) 0xBA, (byte) 0xAB, (byte) 0xB5, - (byte) 0x6B, (byte) 0x6E, (byte) 0xC8, (byte) 0x07, (byte) 0x60, - (byte) 0xA4, (byte) 0xA9, (byte) 0x3F, (byte) 0xA2, (byte) 0xD7, - (byte) 0xC3, (byte) 0x47, (byte) 0xF3, (byte) 0x44, (byte) 0x27, - (byte) 0xF9, (byte) 0xFF, (byte) 0x5C, (byte) 0x8D, (byte) 0xE6, - (byte) 0xD6, (byte) 0x5D, (byte) 0xAC, (byte) 0x95, (byte) 0xF2, - (byte) 0xF1, (byte) 0x9D, (byte) 0xAC, (byte) 0x00, (byte) 0x53, - (byte) 0xDF, (byte) 0x11, (byte) 0xA5, (byte) 0x07, (byte) 0xFB, - (byte) 0x62, (byte) 0x5E, (byte) 0xEB, (byte) 0x8D, (byte) 0xA4, - (byte) 0xC0, (byte) 0x29, (byte) 0x9E, (byte) 0x4A, (byte) 0x21, - (byte) 0x12, (byte) 0xAB, (byte) 0x70, (byte) 0x47, (byte) 0x58, - (byte) 0x8B, (byte) 0x8D, (byte) 0x6D, (byte) 0xA7, (byte) 0x59, - (byte) 0x22, (byte) 0x14, (byte) 0xF2, (byte) 0xDB, (byte) 0xA1, - (byte) 0x40, (byte) 0xC7, (byte) 0xD1, (byte) 0x22, (byte) 0x57, - (byte) 0x9B, (byte) 0x5F, (byte) 0x38, (byte) 0x3D, (byte) 0x22, - (byte) 0x53, (byte) 0xC8, (byte) 0xB9, (byte) 0xCB, (byte) 0x5B, - (byte) 0xC3, (byte) 0x54, (byte) 0x3A, (byte) 0x55, (byte) 0x66, - (byte) 0x0B, (byte) 0xDA, (byte) 0x80, (byte) 0x94, (byte) 0x6A, - (byte) 0xFB, (byte) 0x05, (byte) 0x25, (byte) 0xE8, (byte) 0xE5, - (byte) 0x58, (byte) 0x6B, (byte) 0x4E, (byte) 0x63, (byte) 0xE8, - (byte) 0x92, (byte) 0x41, (byte) 0x49, (byte) 0x78, (byte) 0x36, - (byte) 0xD8, (byte) 0xD3, (byte) 0xAB, (byte) 0x08, (byte) 0x8C, - (byte) 0xD4, (byte) 0x4C, (byte) 0x21, (byte) 0x4D, (byte) 0x6A, - (byte) 0xC8, (byte) 0x56, (byte) 0xE2, (byte) 0xA0, (byte) 0x07, - (byte) 0xF4, (byte) 0x4F, (byte) 0x83, (byte) 0x74, (byte) 0x33, - (byte) 0x37, (byte) 0x37, (byte) 0x1A, (byte) 0xDD, (byte) 0x8E, - (byte) 0x03, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, - (byte) 0x42, (byte) 0x08, (byte) 0x65, (byte) 0x73, (byte) 0x52, - (byte) 0x44, (byte) 0x49, (byte) 0x60, (byte) 0x00, (byte) 0x06 }; - - private final byte[] CHR = new byte[] { - - (byte) 0x83, (byte) 0x08, (byte) 0x65, (byte) 0x73, (byte) 0x53, - (byte) 0x44, (byte) 0x49, (byte) 0x60, (byte) 0x00, (byte) 0x06 }; - - private final byte[] KEY_SELECTOR = new byte[] { - - (byte) 0x83, (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x84, - (byte) 0x02, (byte) 0x02, (byte) 0x1F }; - - private final byte[] C_CV_IFD = new byte[] { - - (byte) 0x7f, (byte) 0x21, (byte) 0x81, (byte) 0xcd, (byte) 0x5f, - (byte) 0x37, (byte) 0x81, (byte) 0x80, (byte) 0x82, (byte) 0x5b, - (byte) 0x69, (byte) 0xc6, (byte) 0x45, (byte) 0x1e, (byte) 0x5f, - (byte) 0x51, (byte) 0x70, (byte) 0x74, (byte) 0x38, (byte) 0x5f, - (byte) 0x2f, (byte) 0x17, (byte) 0xd6, (byte) 0x4d, (byte) 0xfe, - (byte) 0x2e, (byte) 0x68, (byte) 0x56, (byte) 0x75, (byte) 0x67, - (byte) 0x09, (byte) 0x4b, (byte) 0x57, (byte) 0xf3, (byte) 0xc5, - (byte) 0x78, (byte) 0xe8, (byte) 0x30, (byte) 0xe4, (byte) 0x25, - (byte) 0x57, (byte) 0x2d, (byte) 0xe8, (byte) 0x28, (byte) 0xfa, - (byte) 0xf4, (byte) 0xde, (byte) 0x1b, (byte) 0x01, (byte) 0xc3, - (byte) 0x94, (byte) 0xe3, (byte) 0x45, (byte) 0xc2, (byte) 0xfb, - (byte) 0x06, (byte) 0x29, (byte) 0xa3, (byte) 0x93, (byte) 0x49, - (byte) 0x2f, (byte) 0x94, (byte) 0xf5, (byte) 0x70, (byte) 0xb0, - (byte) 0x0b, (byte) 0x1d, (byte) 0x67, (byte) 0x77, (byte) 0x29, - (byte) 0xf7, (byte) 0x55, (byte) 0xd1, (byte) 0x07, (byte) 0x02, - (byte) 0x2b, (byte) 0xb0, (byte) 0xa1, (byte) 0x16, (byte) 0xe1, - (byte) 0xd7, (byte) 0xd7, (byte) 0x65, (byte) 0x9d, (byte) 0xb5, - (byte) 0xc4, (byte) 0xac, (byte) 0x0d, (byte) 0xde, (byte) 0xab, - (byte) 0x07, (byte) 0xff, (byte) 0x04, (byte) 0x5f, (byte) 0x37, - (byte) 0xb5, (byte) 0xda, (byte) 0xf1, (byte) 0x73, (byte) 0x2b, - (byte) 0x54, (byte) 0xea, (byte) 0xb2, (byte) 0x38, (byte) 0xa2, - (byte) 0xce, (byte) 0x17, (byte) 0xc9, (byte) 0x79, (byte) 0x41, - (byte) 0x87, (byte) 0x75, (byte) 0x9c, (byte) 0xea, (byte) 0x9f, - (byte) 0x92, (byte) 0xa1, (byte) 0x78, (byte) 0x05, (byte) 0xa2, - (byte) 0x7c, (byte) 0x10, (byte) 0x15, (byte) 0xec, (byte) 0x56, - (byte) 0xcc, (byte) 0x7e, (byte) 0x47, (byte) 0x1a, (byte) 0x48, - (byte) 0x8e, (byte) 0x6f, (byte) 0x1b, (byte) 0x91, (byte) 0xf7, - (byte) 0xaa, (byte) 0x5f, (byte) 0x38, (byte) 0x3c, (byte) 0xad, - (byte) 0xfc, (byte) 0x12, (byte) 0xe8, (byte) 0x56, (byte) 0xb2, - (byte) 0x02, (byte) 0x34, (byte) 0x6a, (byte) 0xf8, (byte) 0x22, - (byte) 0x6b, (byte) 0x1a, (byte) 0x88, (byte) 0x21, (byte) 0x37, - (byte) 0xdc, (byte) 0x3c, (byte) 0x5a, (byte) 0x57, (byte) 0xf0, - (byte) 0xd2, (byte) 0x81, (byte) 0x5c, (byte) 0x1f, (byte) 0xcd, - (byte) 0x4b, (byte) 0xb4, (byte) 0x6f, (byte) 0xa9, (byte) 0x15, - (byte) 0x7f, (byte) 0xdf, (byte) 0xfd, (byte) 0x79, (byte) 0xec, - (byte) 0x3a, (byte) 0x10, (byte) 0xa8, (byte) 0x24, (byte) 0xcc, - (byte) 0xc1, (byte) 0xeb, (byte) 0x3c, (byte) 0xe0, (byte) 0xb6, - (byte) 0xb4, (byte) 0x39, (byte) 0x6a, (byte) 0xe2, (byte) 0x36, - (byte) 0x59, (byte) 0x00, (byte) 0x16, (byte) 0xba, (byte) 0x69, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x42, - (byte) 0x08, (byte) 0x65, (byte) 0x73, (byte) 0x53, (byte) 0x44, - (byte) 0x49, (byte) 0x60, (byte) 0x00, (byte) 0x06 - - }; - - // PDU to retrieve card info - private final byte[] APDU_GET_CHIP_INFO = new byte[] { (byte) 0x90, - (byte) 0xB8, (byte) 0x00, (byte) 0x00, (byte) 0x07 }; - - // Path to card's component certificate - private final byte[] SECURE_CHANNEL_COMP_CERT_ID = new byte[] { - (byte) 0x60, (byte) 0x1F }; - - // Path to card's intermediate certificate - private final byte[] SECURE_CHANNEL_INTERMEDIAT_CERT_ID = new byte[] { - (byte) 0x60, (byte) 0x20 }; - - private final byte[] TERMINAL_CHALLENGE_TAIL = new byte[] { - - (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x01 }; - - private final byte[] KENC_COMPUTATION_TAIL = new byte[] { - - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 }; - - private final byte[] KMAC_COMPUTATION_TAIL = new byte[] { - - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02 }; - - private final int BLOCK_LENGTH = 8; - - private final Logger log = LoggerFactory - .getLogger(DNIeSecuredChannel.class); - - private byte[] snIcc; - private byte[] componentCert; - private byte[] intermediateCert; - - private byte[] rndIfd; - private byte[] rndIcc; - private int prndLength; - - private byte[] kicc; - private byte[] kifd; - - private byte[] kEnc; - private byte[] kMac; - private byte[] ssc; - - private boolean established; - - public DNIeSecuredChannel(CardChannel channel) { - - super(channel); - this.established = false; - - try { - - this.establish(); - - } catch (CardException e) { - - log.error("Error establishing secure channel with card.", e); - } - } - - public void establish() throws CardException { - - log.trace("Try to set up secure channel to card.."); - - // select master file - executeSelectMasterFile(); - - // get chip info - this.snIcc = executeGetChipInfo(); - - // get card certificates to establish secure channel - this.intermediateCert = executeReadCardCertificate(SECURE_CHANNEL_INTERMEDIAT_CERT_ID); - this.componentCert = executeReadCardCertificate(SECURE_CHANNEL_COMP_CERT_ID); - - // verify card's secure channel certificates - verifyCertificates(); - - // load terminal secure channel certificates and select appropriate keys - loadTerminalCertsAndSelectKeys(); - - // perform internal authentication - performInternalAuthentication(); - - // perform external authentication - performExternalAuthentication(); - - // derive channel keys - calculateChannelKeys(); - - // secure channel successfully established - this.established = true; - log.trace("Secure channel successfully established."); - - } - - @Override - public int transmit(ByteBuffer command, ByteBuffer response) - throws CardException { - - byte[] commandAPDU = new byte[command.remaining()]; - for (int i = 0; i < commandAPDU.length; i++) { - - commandAPDU[i] = command.get(); - } - - CommandAPDU apdu = new CommandAPDU(commandAPDU); - ResponseAPDU resp = transmit(apdu); - - byte[] responseData = resp.getBytes(); - for (int i = 0; i < responseData.length; i++) { - - response.put(responseData[i]); - } - - return responseData.length; - } - - @Override - public ResponseAPDU transmit(CommandAPDU apdu) throws CardException { - - if (!this.established) { - - this.establish(); - } - - byte[] plainAPDUData = apdu.getBytes(); - byte[] securedAPDUData = secureAPDU(plainAPDUData); - - CommandAPDU securedAPDU = new CommandAPDU(securedAPDUData); - ResponseAPDU securedResp = super.transmit(securedAPDU); - - byte[] respData = verifyAndDecryptSecuredResponseAPDU(securedResp - .getData()); - ResponseAPDU resp = new ResponseAPDU(respData); - - return resp; - } - - private byte[] executeGetChipInfo() throws CardException { - - // get chip info - read out card serial number - CommandAPDU command = new CommandAPDU(APDU_GET_CHIP_INFO); - ResponseAPDU resp = super.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error getting chip info: " - + Integer.toHexString(resp.getSW())); - throw new CardException("Error getting chip info: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private byte[] executeReadCardCertificate(byte[] certId) - throws CardException { - - byte[] fci = executeSelect(certId); - - byte certLenHigh; - byte certLenLow; - - if (fci != null && fci.length >= 7) { - - certLenHigh = fci[7]; - certLenLow = fci[8]; - } else { - log.error("Error reading card certificate: Invalid FCI"); - throw new CardException("Invalid FCI obtained from card."); - } - - ByteArrayOutputStream bof = new ByteArrayOutputStream(); - - int bytes2read = (certLenHigh * 256) + certLenLow; - int bytesRead = 0; - - boolean done = false; - int offset = 0; - int len = 0; - - while (!done) { - - if (bytes2read - bytesRead > 255) { - len = 255; - } else { - len = bytes2read - bytesRead; - } - - byte[] offsetBytes = SMCCHelper.toByteArray(offset); - - byte[] apdu = new byte[5]; - apdu[0] = (byte) 0x00; - apdu[1] = (byte) 0xB0; - apdu[2] = offsetBytes[0]; - apdu[3] = offsetBytes[1]; - apdu[4] = (byte) len; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = super.transmit(command); - - byte[] certData = resp.getData(); - - try { - bof.write(certData); - } catch (IOException e) { - log.error("Error reading card certificate.", e); - throw new CardException("Error reading certificate from card", - e); - } - - bytesRead = bytesRead + certData.length; - offset = bytesRead; - - if (bytesRead == bytes2read) { - - done = true; - } - } - - return bof.toByteArray(); - } - - private byte[] executeSelect(byte[] id) throws CardException { - - byte[] apduHeader = new byte[] { (byte) 0x00, (byte) 0xA4, (byte) 0x00, - (byte) 0x00 }; - - byte[] apdu = new byte[apduHeader.length + 1 + id.length]; - System.arraycopy(apduHeader, 0, apdu, 0, apduHeader.length); - apdu[apduHeader.length] = (byte) id.length; - System.arraycopy(id, 0, apdu, apduHeader.length + 1, id.length); - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = super.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error selecting DF or EF: " - + Integer.toHexString(resp.getSW())); - throw new CardException("Unexpected response to Select Command: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private void executeSelectMasterFile() throws CardException { - - byte[] apdu = new byte[ESDNIeCard.MASTER_FILE_ID.length + 5]; - apdu[0] = (byte) 0x00; - apdu[1] = (byte) 0xA4; - apdu[2] = (byte) 0x04; - apdu[3] = (byte) 0x00; - apdu[4] = (byte) ESDNIeCard.MASTER_FILE_ID.length; - System.arraycopy(ESDNIeCard.MASTER_FILE_ID, 0, apdu, 5, - ESDNIeCard.MASTER_FILE_ID.length); - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = super.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error selecting master file: " - + Integer.toHexString(resp.getSW())); - throw new CardException("Error selecting master file: " - + Integer.toHexString(resp.getSW())); - } - } - - private void verifyCertificates() throws CardException { - - // This method verifies the card's component and intermediate - // certificates cryptographically only (no revocation checking). - - RSAPublicKey rootPubKey = DNIeCryptoUtil.createRSAPublicKey( - ROOT_CA_MODULO, ROOT_CA_PUBEXP); - - X509Certificate intermediate = DNIeCryptoUtil - .createCertificate(intermediateCert); - X509Certificate component = DNIeCryptoUtil - .createCertificate(componentCert); - - try { - component.verify(intermediate.getPublicKey()); - intermediate.verify(rootPubKey); - } catch (Exception e) { - - log.error("Error verifying SM card certificate.", e); - throw new CardException("Certificate verification failed.", e); - } - } - - private void loadTerminalCertsAndSelectKeys() throws CardException { - - // MSE - executeManageSecurityEnvironment((byte) 0x81, (byte) 0xB6, new byte[] { - (byte) 0x83, (byte) 0x02, (byte) 0x02, (byte) 0x0F }); - - // PSO - load intermediate certificate - executePerformSecurityOperation(C_CV_CA); - - // MSE - executeManageSecurityEnvironment((byte) 0x81, (byte) 0xB6, CHR); - - // PSO - load terminal certificate - executePerformSecurityOperation(C_CV_IFD); - - // MSE - select keys - executeManageSecurityEnvironment((byte) 0xC1, (byte) 0xA4, KEY_SELECTOR); - - } - - private void executeManageSecurityEnvironment(byte p1, byte p2, byte[] data) - throws CardException { - - // MSE - CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x22, p1, p2, - data); - ResponseAPDU resp = super.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error executing Manage Security Environment: " - + Integer.toHexString(resp.getSW())); - throw new CardException( - "Unexpected response from card during preparation of secure channel credentials: " - + Integer.toHexString(resp.getSW())); - } - } - - private void executePerformSecurityOperation(byte[] data) - throws CardException { - - // PSO - load intermediate certificate - CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x2A, - (byte) 0x00, (byte) 0xAE, data); - ResponseAPDU resp = super.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error executing Perform Security Operation: " - + Integer.toHexString(resp.getSW())); - throw new CardException( - "Unexpected response from card during preparation of secure channel credentials: " - + Integer.toHexString(resp.getSW())); - } - } - - private void performInternalAuthentication() throws CardException { - - log.trace("Starting internal authentication.."); - - byte[] randomBytes = DNIeCryptoUtil.getRandomBytes(BLOCK_LENGTH); - byte[] challengeData = new byte[randomBytes.length - + TERMINAL_CHALLENGE_TAIL.length]; - - this.rndIfd = randomBytes; - - System.arraycopy(randomBytes, 0, challengeData, 0, randomBytes.length); - System.arraycopy(TERMINAL_CHALLENGE_TAIL, 0, challengeData, - randomBytes.length, TERMINAL_CHALLENGE_TAIL.length); - - byte[] responseData = executeSendTerminalChallenge(challengeData); - - // verify response - boolean ok = verifyCardResponse(responseData); - - log.trace("Internal Authentiction succeeded: " + ok); - - if (!ok) { - - log - .error("Internal authentication failed - unable to sucessfully verify card response."); - throw new CardException("Internal authentication failed"); - } - - } - - private byte[] executeSendTerminalChallenge(byte[] challenge) - throws CardException { - - // send challenge to card - CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x88, - (byte) 0x00, (byte) 0x00, challenge); - ResponseAPDU resp = super.transmit(command); - - byte[] data = null; - - if (resp.getSW() == 0x9000) { - - data = resp.getData(); - - } else { - - log.error("Error sending terminal challenge to card: " - + Integer.toHexString(resp.getSW())); - throw new CardException("Invalid response to terminal challenge: " - + Integer.toHexString(resp.getSW())); - } - - return data; - } - - private boolean verifyCardResponse(byte[] resp) throws CardException { - - byte[] challenge = this.rndIfd; - byte[] response = resp; - - // decrypt response with terminal private key - byte[] plain = null; - RSAPrivateKey terminalPrivateKey = DNIeCryptoUtil.createRSAPrivateKey( - TERMINAL_MODULO, TERMINAL_PRIVEXP); - try { - plain = DNIeCryptoUtil.rsaDecrypt(terminalPrivateKey, response); - } catch (Exception e) { - log.error("Error verifying card response."); - throw new CardException("Error decrypting card response.", e); - } - - X509Certificate cert = DNIeCryptoUtil.createCertificate(componentCert); - PublicKey pubKey = cert.getPublicKey(); - - byte[] sig = null; - - try { - sig = DNIeCryptoUtil.rsaDecrypt(pubKey, plain); - - } catch (Exception e) { - - log.error("Error verifying card response.", e); - throw new CardException( - "Error decrypting card response with card's public key", e); - } - - if (sig == null) { - - log - .error("Error verifying card response - decryption result is null"); - throw new CardException("Invalid decryption result: null."); - } else { - - if (sig[0] == (byte) 0x6A && sig[sig.length - 1] == (byte) 0xBC) { - - // Obtained response from card was obviously SIG - nothing else - // to do here so far - - } else { - - // Obtained response from card was probably N.ICC-SIG - - // compute N.ICC-SIG and decrypt result again - - RSAPublicKey rsaPubKey = (RSAPublicKey) pubKey; - BigInteger mod = rsaPubKey.getModulus(); - BigInteger sigVal = SMCCHelper.createUnsignedBigInteger(plain); - - BigInteger substractionResult = mod.subtract(sigVal); - byte[] encrypted = substractionResult.toByteArray(); - - // necessary if substraction result contains leading - // zero byte - byte[] trimmed = new byte[128]; - System.arraycopy(encrypted, encrypted.length - 128, trimmed, 0, - 128); - - try { - sig = DNIeCryptoUtil.rsaDecrypt(pubKey, trimmed); - - } catch (Exception e) { - - log.error("Error verifying card response.", e); - throw new CardException("Error decrypting card response.", - e); - } - } - } - - // extract data from decrypted response - byte[] hash = new byte[20]; - byte[] kIcc = new byte[32]; - byte[] prnd1 = new byte[sig.length - 2 - 20 - 32]; - - this.prndLength = prnd1.length; - - System.arraycopy(sig, 1, prnd1, 0, prnd1.length); // 1 byte offset due - // to 6A padding - System.arraycopy(sig, prnd1.length + 1, kIcc, 0, kIcc.length); - System.arraycopy(sig, prnd1.length + kIcc.length + 1, hash, 0, - hash.length); - - // verify hash - byte[] hashData = new byte[prnd1.length + kIcc.length - + challenge.length + TERMINAL_CHALLENGE_TAIL.length]; - - System.arraycopy(prnd1, 0, hashData, 0, prnd1.length); - System.arraycopy(kIcc, 0, hashData, prnd1.length, kIcc.length); - System.arraycopy(challenge, 0, hashData, prnd1.length + kIcc.length, - challenge.length); - System.arraycopy(TERMINAL_CHALLENGE_TAIL, 0, hashData, prnd1.length - + kIcc.length + challenge.length, - TERMINAL_CHALLENGE_TAIL.length); - - byte[] digest = DNIeCryptoUtil.computeSHA1Hash(hashData); - - boolean internalAuthResult = Arrays.equals(hash, digest); - - if (internalAuthResult) { - - // if verification succeeded, remember kicc for subsequent channel - // key derivation - this.kicc = kIcc; - } - - return internalAuthResult; - } - - private void performExternalAuthentication() throws CardException { - - log.trace("Performing external authentication."); - - byte[] cardChallenge = executeRequestCardChallenge(); - - this.rndIcc = cardChallenge; - - byte[] prnd2 = DNIeCryptoUtil.getRandomBytes(this.prndLength); - - byte[] kIfd = DNIeCryptoUtil.getRandomBytes(32); - - // compute hash - byte[] hashData = new byte[prnd2.length + kIfd.length - + cardChallenge.length + BLOCK_LENGTH]; - - System.arraycopy(prnd2, 0, hashData, 0, prnd2.length); - System.arraycopy(kIfd, 0, hashData, prnd2.length, kIfd.length); - System.arraycopy(cardChallenge, 0, hashData, - prnd2.length + kIfd.length, cardChallenge.length); - - int snPadding = BLOCK_LENGTH - snIcc.length; - - for (int i = 0; i < snPadding; i++) { - - hashData[prnd2.length + kIfd.length + cardChallenge.length + i] = (byte) 0x00; - } - - System.arraycopy(snIcc, 0, hashData, prnd2.length + kIfd.length - + cardChallenge.length + snPadding, snIcc.length); - - byte[] digest = DNIeCryptoUtil.computeSHA1Hash(hashData); - - // prepare data to be encrypted - byte[] plain = new byte[2 + prnd2.length + kIfd.length + digest.length]; - - plain[0] = (byte) 0x6A; - - System.arraycopy(prnd2, 0, plain, 1, prnd2.length); - System.arraycopy(kIfd, 0, plain, 1 + prnd2.length, kIfd.length); - System.arraycopy(digest, 0, plain, 1 + prnd2.length + kIfd.length, - digest.length); - - plain[plain.length - 1] = (byte) 0xBC; - - // encrypt plain data - RSAPrivateKey terminalPrivateKey = DNIeCryptoUtil.createRSAPrivateKey( - TERMINAL_MODULO, TERMINAL_PRIVEXP); - - byte[] encResult = null; - try { - encResult = DNIeCryptoUtil.rsaEncrypt(terminalPrivateKey, plain); - } catch (Exception e) { - log.error("Error performing external authentication.", e); - throw new CardException("Error encrypting authentication data.", e); - } - - // apply MIN function - BigInteger sig = SMCCHelper.createUnsignedBigInteger(encResult); - BigInteger mod = new BigInteger(TERMINAL_MODULO, 16); - - BigInteger diff = mod.subtract(sig); - BigInteger sigMin = diff.min(sig); - - // encrypt with card public key - PublicKey cardPubKey = null; - - X509Certificate cert = DNIeCryptoUtil.createCertificate(componentCert); - cardPubKey = cert.getPublicKey(); - - byte[] authData = null; - try { - authData = DNIeCryptoUtil.rsaEncrypt(cardPubKey, sigMin - .toByteArray()); - } catch (Exception e) { - log.error("Error performing external authentication.", e); - throw new CardException("Error encrypting authentication data.", e); - } - - // send auth data to card - // BE CAREFUL WITH THAT! EXT-AUTH METHOD MAY GET BLOCKED! - if (executeExternalAuthenticate(authData)) { - - log.trace("External authentication succeeded."); - this.kifd = kIfd; - } else { - log.error("Error performing external authentication"); - throw new CardException("External Authentication failed."); - } - - } - - private byte[] executeRequestCardChallenge() throws CardException { - - CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x84, - (byte) 0x00, (byte) 0x00, (byte) BLOCK_LENGTH); - ResponseAPDU resp = super.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error requesting challenge from card: " - + Integer.toHexString(resp.getSW())); - throw new CardException( - "Invalid response from card upon challenge request: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private boolean executeExternalAuthenticate(byte[] authData) - throws CardException { - - CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x82, - (byte) 0x00, (byte) 0x00, authData); - ResponseAPDU resp = super.transmit(command); - - log.trace("Card answer to EXTERNL AUTHENTICATE: " - + Integer.toHexString(resp.getSW())); - - return resp.getSW() == 0x9000; - } - - private void calculateChannelKeys() throws CardException { - - if (this.kicc == null || this.kifd == null) { - - log - .error("Error generating channel keys - required key data is null."); - throw new CardException( - "Required data for deriving keys not available."); - } - - if (this.kicc.length != this.kifd.length) { - - log.error("Error generating channel keys - invalid key data"); - throw new CardException( - "Required data for deriving keys is invalid."); - } - - byte[] kifdicc = new byte[this.kicc.length]; - - for (int i = 0; i < kifdicc.length; i++) { - - kifdicc[i] = (byte) (this.kicc[i] ^ this.kifd[i]); - } - - byte[] kEncHashData = new byte[kifdicc.length - + KENC_COMPUTATION_TAIL.length]; - byte[] kMacHashData = new byte[kifdicc.length - + KMAC_COMPUTATION_TAIL.length]; - - System.arraycopy(kifdicc, 0, kEncHashData, 0, kifdicc.length); - System.arraycopy(kifdicc, 0, kMacHashData, 0, kifdicc.length); - - System.arraycopy(KENC_COMPUTATION_TAIL, 0, kEncHashData, - kifdicc.length, KENC_COMPUTATION_TAIL.length); - System.arraycopy(KMAC_COMPUTATION_TAIL, 0, kMacHashData, - kifdicc.length, KMAC_COMPUTATION_TAIL.length); - - byte[] hashEnc = DNIeCryptoUtil.computeSHA1Hash(kEncHashData); - byte[] hashMac = DNIeCryptoUtil.computeSHA1Hash(kMacHashData); - - this.kEnc = Arrays.copyOfRange(hashEnc, 0, 16); - this.kMac = Arrays.copyOfRange(hashMac, 0, 16); - - // compute sequence counter SSC - if (this.rndIcc == null || this.rndIfd == null - || this.rndIcc.length < 4 || this.rndIfd.length < 4) { - - log.error("Error generating channel keys - invlaid ssc data"); - throw new CardException("Data required to compute SSC not valid."); - } - - this.ssc = new byte[BLOCK_LENGTH]; - - System.arraycopy(this.rndIcc, this.rndIcc.length - 4, this.ssc, 0, 4); - System.arraycopy(this.rndIfd, this.rndIfd.length - 4, this.ssc, 4, 4); - } - - private byte[] secureAPDUWithoutData(byte[] apdu) throws CardException { - - if (apdu.length < 4 || apdu.length > 5) { - - log.error("Error securing APDU - invalid APDU length: " - + apdu.length); - throw new CardException("Invalid APDU length."); - } - - boolean leAvailable = apdu.length == 5; - - byte encCLA = (byte) (apdu[0] | (byte) 0x0C); - byte[] encHeader = new byte[] { encCLA, apdu[1], apdu[2], apdu[3] }; - byte[] paddedHeader = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, - encHeader); - - int leFieldLen; - byte[] leField = null; - if (leAvailable) { - leField = new byte[3]; - leField[0] = (byte) 0x97; - leField[1] = (byte) 0x01; - leField[2] = apdu[4]; - leFieldLen = leField.length; - } else { - - leFieldLen = 0; - } - - byte[] macData = new byte[paddedHeader.length + leFieldLen]; - System.arraycopy(paddedHeader, 0, macData, 0, paddedHeader.length); - - if (leAvailable) { - System.arraycopy(leField, 0, macData, paddedHeader.length, - leField.length); - - macData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, macData); - } - - incrementSSC(); - - byte[] mac = DNIeCryptoUtil.calculateAPDUMAC(macData, kMac, this.ssc, - BLOCK_LENGTH); - - byte[] encapsulatedMac = new byte[mac.length + 2]; - encapsulatedMac[0] = (byte) 0x8E; - encapsulatedMac[1] = (byte) mac.length; - System.arraycopy(mac, 0, encapsulatedMac, 2, mac.length); - - byte[] completeMessage = new byte[5 + leFieldLen - + encapsulatedMac.length]; - completeMessage[0] = encCLA; - completeMessage[1] = apdu[1]; - completeMessage[2] = apdu[2]; - completeMessage[3] = apdu[3]; - completeMessage[4] = (byte) (encapsulatedMac.length + leFieldLen); - - if (leAvailable) { - System.arraycopy(leField, 0, completeMessage, 5, leField.length); - } - - System.arraycopy(encapsulatedMac, 0, completeMessage, 5 + leFieldLen, - encapsulatedMac.length); - - return completeMessage; - - } - - private byte[] secureAPDUWithData(byte[] apdu) throws CardException { - - if (apdu.length < 6) { - - log.error("Error securing APDU - invalid APDU length: " - + apdu.length); - throw new CardException( - "Error securing APDU - invalid APDU length: " + apdu.length); - } - - byte cla = apdu[0]; - byte ins = apdu[1]; - byte p1 = apdu[2]; - byte p2 = apdu[3]; - byte lc = apdu[4]; - - boolean leAvailable; - if (apdu.length == lc + 5 + 1) { - - leAvailable = true; - } else if (apdu.length != lc + 5) { - - log.error("Error securing APDU - invalid APDU length: " - + apdu.length); - throw new CardException("Invalid APDU length or format."); - } else { - - leAvailable = false; - } - - byte[] leField = null; - if (leAvailable) { - - byte le = apdu[apdu.length - 1]; - - leField = new byte[3]; - leField[0] = (byte) 0x97; - leField[1] = (byte) 0x01; - leField[2] = le; - } - - byte[] data = new byte[lc]; - System.arraycopy(apdu, 5, data, 0, lc); - - byte[] paddedData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, data); - - byte[] encrypted = null; - - try { - - encrypted = DNIeCryptoUtil.perform3DESCipherOperation(paddedData, - kEnc, Cipher.ENCRYPT_MODE); - - } catch (Exception e) { - - log.error("Error encrypting APDU.", e); - throw new CardException("Error encrypting APDU.", e); - } - - byte[] encapsulated = new byte[encrypted.length + 3]; - encapsulated[0] = (byte) 0x87; - encapsulated[1] = (byte) (encrypted.length + 1); - encapsulated[2] = (byte) 0x01; - System.arraycopy(encrypted, 0, encapsulated, 3, encrypted.length); - - // calculate MAC - byte encCLA = (byte) (cla | (byte) 0x0C); - byte[] encHeader = new byte[] { encCLA, ins, p1, p2 }; - byte[] paddedHeader = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, - encHeader); - - byte[] headerAndData = new byte[paddedHeader.length - + encapsulated.length]; - System - .arraycopy(paddedHeader, 0, headerAndData, 0, - paddedHeader.length); - System.arraycopy(encapsulated, 0, headerAndData, paddedHeader.length, - encapsulated.length); - - if (leAvailable) { - byte[] macData = new byte[headerAndData.length + leField.length]; - System - .arraycopy(headerAndData, 0, macData, 0, - headerAndData.length); - System.arraycopy(leField, 0, macData, headerAndData.length, - leField.length); - - headerAndData = macData; - } - - byte[] paddedHeaderAndData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, - headerAndData); - - incrementSSC(); - - byte[] mac = DNIeCryptoUtil.calculateAPDUMAC(paddedHeaderAndData, kMac, - this.ssc, BLOCK_LENGTH); - - byte[] encapsulatedMac = new byte[mac.length + 2]; - encapsulatedMac[0] = (byte) 0x8E; - encapsulatedMac[1] = (byte) mac.length; - System.arraycopy(mac, 0, encapsulatedMac, 2, mac.length); - - int leFieldLen; - if (leAvailable) { - leFieldLen = leField.length; - } else { - leFieldLen = 0; - } - - byte[] completeMessage = new byte[5 + encapsulated.length - + encapsulatedMac.length + leFieldLen]; - completeMessage[0] = encCLA; - completeMessage[1] = ins; - completeMessage[2] = p1; - completeMessage[3] = p2; - - completeMessage[4] = (byte) (encapsulated.length + leFieldLen + encapsulatedMac.length); - System.arraycopy(encapsulated, 0, completeMessage, 5, - encapsulated.length); - - if (leAvailable) { - System.arraycopy(leField, 0, completeMessage, - 5 + encapsulated.length, leFieldLen); - } - - System.arraycopy(encapsulatedMac, 0, completeMessage, 5 - + encapsulated.length + leFieldLen, encapsulatedMac.length); - - return completeMessage; - - } - - private byte[] secureAPDU(byte[] apdu) throws CardException { - - if (apdu == null || apdu.length < 4) { - - log.error("Invalid APDU to secure."); - throw new CardException("Invalid APDU to secure."); - } - - if (apdu.length == 4 || apdu.length == 5) { - - return secureAPDUWithoutData(apdu); - } - - if (apdu.length > 5) { - - return secureAPDUWithData(apdu); - } - - throw new CardException("Error securing APDU - unexpected APDU length."); - } - - private byte[] verifyAndDecryptSecuredResponseAPDU(byte[] securedAPDU) - throws CardException { - - byte[] data = new byte[securedAPDU.length - 10]; - byte[] commandResponse = new byte[4]; - byte[] obtainedMac = new byte[4]; - - System.arraycopy(securedAPDU, 0, data, 0, data.length); - System.arraycopy(securedAPDU, data.length, commandResponse, 0, - commandResponse.length); - System.arraycopy(securedAPDU, data.length + commandResponse.length + 2, - obtainedMac, 0, obtainedMac.length); - - byte[] macData = new byte[data.length + commandResponse.length]; - System.arraycopy(data, 0, macData, 0, data.length); - System.arraycopy(commandResponse, 0, macData, data.length, - commandResponse.length); - - byte[] paddedMacData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, - macData); - - incrementSSC(); - - byte[] mac = DNIeCryptoUtil.calculateAPDUMAC(paddedMacData, this.kMac, - this.ssc, BLOCK_LENGTH); - - if (!Arrays.equals(mac, obtainedMac)) { - - log - .error("Error verifiying MAC of secured response. MAC values do not match."); - throw new CardException("Unable to verify MAC of Response APDU."); - } - - if (data.length > 0) { - - byte[] data2decrypt = new byte[data.length - - DNIeCryptoUtil.getCutOffLength(data, BLOCK_LENGTH)]; - System.arraycopy(data, DNIeCryptoUtil.getCutOffLength(data, - BLOCK_LENGTH), data2decrypt, 0, data2decrypt.length); - - byte[] plainData = null; - - try { - plainData = DNIeCryptoUtil.perform3DESCipherOperation( - data2decrypt, this.kEnc, Cipher.DECRYPT_MODE); - } catch (Exception e) { - log.error("Error decrypting data.", e); - throw new CardException("Unable to decrypt data.", e); - } - - byte[] unpaddedData = DNIeCryptoUtil.removePadding(plainData); - - byte[] result = new byte[unpaddedData.length + 2]; - System.arraycopy(unpaddedData, 0, result, 0, unpaddedData.length); - result[result.length - 2] = commandResponse[2]; - result[result.length - 1] = commandResponse[3]; - - return result; - } else { - - // no data in response - byte[] result = new byte[2]; - result[result.length - 2] = commandResponse[2]; - result[result.length - 1] = commandResponse[3]; - return result; - } - } - - private void incrementSSC() { - - BigInteger ssc = new BigInteger(this.ssc); - ssc = ssc.add(new BigInteger("1", 10)); - this.ssc = ssc.toByteArray(); - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +import javax.crypto.Cipher; +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.util.SMCCHelper; + +public class DNIeSecuredChannel extends T0CardChannel { + + // Public key data of Root CA - required to validate card certificates + private static final String ROOT_CA_MODULO = "EADEDA455332945039DAA404C8EBC4D3B7F5DC869283CDEA2F101E2AB54FB0D0B03D8F030DAF2458028288F54CE552F8FA57AB2FB103B112427E11131D1D27E10A5B500EAAE5D940301E30EB26C3E9066B257156ED639D70CCC090B863AFBB3BFED8C17BE7673034B9823E977ED657252927F9575B9FFF6691DB64F80B5E92CD"; + private static final String ROOT_CA_PUBEXP = "010001"; + + // Terminal private RSA key for secure channel establishment + private final String TERMINAL_MODULO = "DB2CB41E112BACFA2BD7C3D3D7967E84FB9434FC261F9D090A8983947DAF8488D3DF8FBDCC1F92493585E134A1B42DE519F463244D7ED384E26D516CC7A4FF7895B1992140043AACADFC12E856B202346AF8226B1A882137DC3C5A57F0D2815C1FCD4BB46FA9157FDFFD79EC3A10A824CCC1EB3CE0B6B4396AE236590016BA69"; + private final String TERMINAL_PRIVEXP = "18B44A3D155C61EBF4E3261C8BB157E36F63FE30E9AF28892B59E2ADEB18CC8C8BAD284B9165819CA4DEC94AA06B69BCE81706D1C1B668EB128695E5F7FEDE18A908A3011A646A481D3EA71D8A387D474609BD57A882B182E047DE80E04B4221416BD39DFA1FAC0300641962ADB109E28CAF50061B68C9CABD9B00313C0F46ED"; + + private final byte[] C_CV_CA = new byte[] { + + (byte) 0x7F, (byte) 0x21, (byte) 0x81, (byte) 0xCE, (byte) 0x5F, + (byte) 0x37, (byte) 0x81, (byte) 0x80, (byte) 0x3C, (byte) 0xBA, + (byte) 0xDC, (byte) 0x36, (byte) 0x84, (byte) 0xBE, (byte) 0xF3, + (byte) 0x20, (byte) 0x41, (byte) 0xAD, (byte) 0x15, (byte) 0x50, + (byte) 0x89, (byte) 0x25, (byte) 0x8D, (byte) 0xFD, (byte) 0x20, + (byte) 0xC6, (byte) 0x91, (byte) 0x15, (byte) 0xD7, (byte) 0x2F, + (byte) 0x9C, (byte) 0x38, (byte) 0xAA, (byte) 0x99, (byte) 0xAD, + (byte) 0x6C, (byte) 0x1A, (byte) 0xED, (byte) 0xFA, (byte) 0xB2, + (byte) 0xBF, (byte) 0xAC, (byte) 0x90, (byte) 0x92, (byte) 0xFC, + (byte) 0x70, (byte) 0xCC, (byte) 0xC0, (byte) 0x0C, (byte) 0xAF, + (byte) 0x48, (byte) 0x2A, (byte) 0x4B, (byte) 0xE3, (byte) 0x1A, + (byte) 0xFD, (byte) 0xBD, (byte) 0x3C, (byte) 0xBC, (byte) 0x8C, + (byte) 0x83, (byte) 0x82, (byte) 0xCF, (byte) 0x06, (byte) 0xBC, + (byte) 0x07, (byte) 0x19, (byte) 0xBA, (byte) 0xAB, (byte) 0xB5, + (byte) 0x6B, (byte) 0x6E, (byte) 0xC8, (byte) 0x07, (byte) 0x60, + (byte) 0xA4, (byte) 0xA9, (byte) 0x3F, (byte) 0xA2, (byte) 0xD7, + (byte) 0xC3, (byte) 0x47, (byte) 0xF3, (byte) 0x44, (byte) 0x27, + (byte) 0xF9, (byte) 0xFF, (byte) 0x5C, (byte) 0x8D, (byte) 0xE6, + (byte) 0xD6, (byte) 0x5D, (byte) 0xAC, (byte) 0x95, (byte) 0xF2, + (byte) 0xF1, (byte) 0x9D, (byte) 0xAC, (byte) 0x00, (byte) 0x53, + (byte) 0xDF, (byte) 0x11, (byte) 0xA5, (byte) 0x07, (byte) 0xFB, + (byte) 0x62, (byte) 0x5E, (byte) 0xEB, (byte) 0x8D, (byte) 0xA4, + (byte) 0xC0, (byte) 0x29, (byte) 0x9E, (byte) 0x4A, (byte) 0x21, + (byte) 0x12, (byte) 0xAB, (byte) 0x70, (byte) 0x47, (byte) 0x58, + (byte) 0x8B, (byte) 0x8D, (byte) 0x6D, (byte) 0xA7, (byte) 0x59, + (byte) 0x22, (byte) 0x14, (byte) 0xF2, (byte) 0xDB, (byte) 0xA1, + (byte) 0x40, (byte) 0xC7, (byte) 0xD1, (byte) 0x22, (byte) 0x57, + (byte) 0x9B, (byte) 0x5F, (byte) 0x38, (byte) 0x3D, (byte) 0x22, + (byte) 0x53, (byte) 0xC8, (byte) 0xB9, (byte) 0xCB, (byte) 0x5B, + (byte) 0xC3, (byte) 0x54, (byte) 0x3A, (byte) 0x55, (byte) 0x66, + (byte) 0x0B, (byte) 0xDA, (byte) 0x80, (byte) 0x94, (byte) 0x6A, + (byte) 0xFB, (byte) 0x05, (byte) 0x25, (byte) 0xE8, (byte) 0xE5, + (byte) 0x58, (byte) 0x6B, (byte) 0x4E, (byte) 0x63, (byte) 0xE8, + (byte) 0x92, (byte) 0x41, (byte) 0x49, (byte) 0x78, (byte) 0x36, + (byte) 0xD8, (byte) 0xD3, (byte) 0xAB, (byte) 0x08, (byte) 0x8C, + (byte) 0xD4, (byte) 0x4C, (byte) 0x21, (byte) 0x4D, (byte) 0x6A, + (byte) 0xC8, (byte) 0x56, (byte) 0xE2, (byte) 0xA0, (byte) 0x07, + (byte) 0xF4, (byte) 0x4F, (byte) 0x83, (byte) 0x74, (byte) 0x33, + (byte) 0x37, (byte) 0x37, (byte) 0x1A, (byte) 0xDD, (byte) 0x8E, + (byte) 0x03, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, + (byte) 0x42, (byte) 0x08, (byte) 0x65, (byte) 0x73, (byte) 0x52, + (byte) 0x44, (byte) 0x49, (byte) 0x60, (byte) 0x00, (byte) 0x06 }; + + private final byte[] CHR = new byte[] { + + (byte) 0x83, (byte) 0x08, (byte) 0x65, (byte) 0x73, (byte) 0x53, + (byte) 0x44, (byte) 0x49, (byte) 0x60, (byte) 0x00, (byte) 0x06 }; + + private final byte[] KEY_SELECTOR = new byte[] { + + (byte) 0x83, (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x84, + (byte) 0x02, (byte) 0x02, (byte) 0x1F }; + + private final byte[] C_CV_IFD = new byte[] { + + (byte) 0x7f, (byte) 0x21, (byte) 0x81, (byte) 0xcd, (byte) 0x5f, + (byte) 0x37, (byte) 0x81, (byte) 0x80, (byte) 0x82, (byte) 0x5b, + (byte) 0x69, (byte) 0xc6, (byte) 0x45, (byte) 0x1e, (byte) 0x5f, + (byte) 0x51, (byte) 0x70, (byte) 0x74, (byte) 0x38, (byte) 0x5f, + (byte) 0x2f, (byte) 0x17, (byte) 0xd6, (byte) 0x4d, (byte) 0xfe, + (byte) 0x2e, (byte) 0x68, (byte) 0x56, (byte) 0x75, (byte) 0x67, + (byte) 0x09, (byte) 0x4b, (byte) 0x57, (byte) 0xf3, (byte) 0xc5, + (byte) 0x78, (byte) 0xe8, (byte) 0x30, (byte) 0xe4, (byte) 0x25, + (byte) 0x57, (byte) 0x2d, (byte) 0xe8, (byte) 0x28, (byte) 0xfa, + (byte) 0xf4, (byte) 0xde, (byte) 0x1b, (byte) 0x01, (byte) 0xc3, + (byte) 0x94, (byte) 0xe3, (byte) 0x45, (byte) 0xc2, (byte) 0xfb, + (byte) 0x06, (byte) 0x29, (byte) 0xa3, (byte) 0x93, (byte) 0x49, + (byte) 0x2f, (byte) 0x94, (byte) 0xf5, (byte) 0x70, (byte) 0xb0, + (byte) 0x0b, (byte) 0x1d, (byte) 0x67, (byte) 0x77, (byte) 0x29, + (byte) 0xf7, (byte) 0x55, (byte) 0xd1, (byte) 0x07, (byte) 0x02, + (byte) 0x2b, (byte) 0xb0, (byte) 0xa1, (byte) 0x16, (byte) 0xe1, + (byte) 0xd7, (byte) 0xd7, (byte) 0x65, (byte) 0x9d, (byte) 0xb5, + (byte) 0xc4, (byte) 0xac, (byte) 0x0d, (byte) 0xde, (byte) 0xab, + (byte) 0x07, (byte) 0xff, (byte) 0x04, (byte) 0x5f, (byte) 0x37, + (byte) 0xb5, (byte) 0xda, (byte) 0xf1, (byte) 0x73, (byte) 0x2b, + (byte) 0x54, (byte) 0xea, (byte) 0xb2, (byte) 0x38, (byte) 0xa2, + (byte) 0xce, (byte) 0x17, (byte) 0xc9, (byte) 0x79, (byte) 0x41, + (byte) 0x87, (byte) 0x75, (byte) 0x9c, (byte) 0xea, (byte) 0x9f, + (byte) 0x92, (byte) 0xa1, (byte) 0x78, (byte) 0x05, (byte) 0xa2, + (byte) 0x7c, (byte) 0x10, (byte) 0x15, (byte) 0xec, (byte) 0x56, + (byte) 0xcc, (byte) 0x7e, (byte) 0x47, (byte) 0x1a, (byte) 0x48, + (byte) 0x8e, (byte) 0x6f, (byte) 0x1b, (byte) 0x91, (byte) 0xf7, + (byte) 0xaa, (byte) 0x5f, (byte) 0x38, (byte) 0x3c, (byte) 0xad, + (byte) 0xfc, (byte) 0x12, (byte) 0xe8, (byte) 0x56, (byte) 0xb2, + (byte) 0x02, (byte) 0x34, (byte) 0x6a, (byte) 0xf8, (byte) 0x22, + (byte) 0x6b, (byte) 0x1a, (byte) 0x88, (byte) 0x21, (byte) 0x37, + (byte) 0xdc, (byte) 0x3c, (byte) 0x5a, (byte) 0x57, (byte) 0xf0, + (byte) 0xd2, (byte) 0x81, (byte) 0x5c, (byte) 0x1f, (byte) 0xcd, + (byte) 0x4b, (byte) 0xb4, (byte) 0x6f, (byte) 0xa9, (byte) 0x15, + (byte) 0x7f, (byte) 0xdf, (byte) 0xfd, (byte) 0x79, (byte) 0xec, + (byte) 0x3a, (byte) 0x10, (byte) 0xa8, (byte) 0x24, (byte) 0xcc, + (byte) 0xc1, (byte) 0xeb, (byte) 0x3c, (byte) 0xe0, (byte) 0xb6, + (byte) 0xb4, (byte) 0x39, (byte) 0x6a, (byte) 0xe2, (byte) 0x36, + (byte) 0x59, (byte) 0x00, (byte) 0x16, (byte) 0xba, (byte) 0x69, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x42, + (byte) 0x08, (byte) 0x65, (byte) 0x73, (byte) 0x53, (byte) 0x44, + (byte) 0x49, (byte) 0x60, (byte) 0x00, (byte) 0x06 + + }; + + // PDU to retrieve card info + private final byte[] APDU_GET_CHIP_INFO = new byte[] { (byte) 0x90, + (byte) 0xB8, (byte) 0x00, (byte) 0x00, (byte) 0x07 }; + + // Path to card's component certificate + private final byte[] SECURE_CHANNEL_COMP_CERT_ID = new byte[] { + (byte) 0x60, (byte) 0x1F }; + + // Path to card's intermediate certificate + private final byte[] SECURE_CHANNEL_INTERMEDIAT_CERT_ID = new byte[] { + (byte) 0x60, (byte) 0x20 }; + + private final byte[] TERMINAL_CHALLENGE_TAIL = new byte[] { + + (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x01 }; + + private final byte[] KENC_COMPUTATION_TAIL = new byte[] { + + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 }; + + private final byte[] KMAC_COMPUTATION_TAIL = new byte[] { + + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02 }; + + private final int BLOCK_LENGTH = 8; + + private final Logger log = LoggerFactory + .getLogger(DNIeSecuredChannel.class); + + private byte[] snIcc; + private byte[] componentCert; + private byte[] intermediateCert; + + private byte[] rndIfd; + private byte[] rndIcc; + private int prndLength; + + private byte[] kicc; + private byte[] kifd; + + private byte[] kEnc; + private byte[] kMac; + private byte[] ssc; + + private boolean established; + + public DNIeSecuredChannel(CardChannel channel) { + + super(channel); + this.established = false; + + try { + + this.establish(); + + } catch (CardException e) { + + log.error("Error establishing secure channel with card.", e); + } + } + + public void establish() throws CardException { + + log.trace("Try to set up secure channel to card.."); + + // select master file + executeSelectMasterFile(); + + // get chip info + this.snIcc = executeGetChipInfo(); + + // get card certificates to establish secure channel + this.intermediateCert = executeReadCardCertificate(SECURE_CHANNEL_INTERMEDIAT_CERT_ID); + this.componentCert = executeReadCardCertificate(SECURE_CHANNEL_COMP_CERT_ID); + + // verify card's secure channel certificates + verifyCertificates(); + + // load terminal secure channel certificates and select appropriate keys + loadTerminalCertsAndSelectKeys(); + + // perform internal authentication + performInternalAuthentication(); + + // perform external authentication + performExternalAuthentication(); + + // derive channel keys + calculateChannelKeys(); + + // secure channel successfully established + this.established = true; + log.trace("Secure channel successfully established."); + + } + + @Override + public int transmit(ByteBuffer command, ByteBuffer response) + throws CardException { + + byte[] commandAPDU = new byte[command.remaining()]; + for (int i = 0; i < commandAPDU.length; i++) { + + commandAPDU[i] = command.get(); + } + + CommandAPDU apdu = new CommandAPDU(commandAPDU); + ResponseAPDU resp = transmit(apdu); + + byte[] responseData = resp.getBytes(); + for (int i = 0; i < responseData.length; i++) { + + response.put(responseData[i]); + } + + return responseData.length; + } + + @Override + public ResponseAPDU transmit(CommandAPDU apdu) throws CardException { + + if (!this.established) { + + this.establish(); + } + + byte[] plainAPDUData = apdu.getBytes(); + byte[] securedAPDUData = secureAPDU(plainAPDUData); + + CommandAPDU securedAPDU = new CommandAPDU(securedAPDUData); + ResponseAPDU securedResp = super.transmit(securedAPDU); + + byte[] respData = verifyAndDecryptSecuredResponseAPDU(securedResp + .getData()); + ResponseAPDU resp = new ResponseAPDU(respData); + + return resp; + } + + private byte[] executeGetChipInfo() throws CardException { + + // get chip info - read out card serial number + CommandAPDU command = new CommandAPDU(APDU_GET_CHIP_INFO); + ResponseAPDU resp = super.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error getting chip info: " + + Integer.toHexString(resp.getSW())); + throw new CardException("Error getting chip info: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private byte[] executeReadCardCertificate(byte[] certId) + throws CardException { + + byte[] fci = executeSelect(certId); + + byte certLenHigh; + byte certLenLow; + + if (fci != null && fci.length >= 7) { + + certLenHigh = fci[7]; + certLenLow = fci[8]; + } else { + log.error("Error reading card certificate: Invalid FCI"); + throw new CardException("Invalid FCI obtained from card."); + } + + ByteArrayOutputStream bof = new ByteArrayOutputStream(); + + int bytes2read = (certLenHigh * 256) + certLenLow; + int bytesRead = 0; + + boolean done = false; + int offset = 0; + int len = 0; + + while (!done) { + + if (bytes2read - bytesRead > 255) { + len = 255; + } else { + len = bytes2read - bytesRead; + } + + byte[] offsetBytes = SMCCHelper.toByteArray(offset); + + byte[] apdu = new byte[5]; + apdu[0] = (byte) 0x00; + apdu[1] = (byte) 0xB0; + apdu[2] = offsetBytes[0]; + apdu[3] = offsetBytes[1]; + apdu[4] = (byte) len; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = super.transmit(command); + + byte[] certData = resp.getData(); + + try { + bof.write(certData); + } catch (IOException e) { + log.error("Error reading card certificate.", e); + throw new CardException("Error reading certificate from card", + e); + } + + bytesRead = bytesRead + certData.length; + offset = bytesRead; + + if (bytesRead == bytes2read) { + + done = true; + } + } + + return bof.toByteArray(); + } + + private byte[] executeSelect(byte[] id) throws CardException { + + byte[] apduHeader = new byte[] { (byte) 0x00, (byte) 0xA4, (byte) 0x00, + (byte) 0x00 }; + + byte[] apdu = new byte[apduHeader.length + 1 + id.length]; + System.arraycopy(apduHeader, 0, apdu, 0, apduHeader.length); + apdu[apduHeader.length] = (byte) id.length; + System.arraycopy(id, 0, apdu, apduHeader.length + 1, id.length); + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = super.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error selecting DF or EF: " + + Integer.toHexString(resp.getSW())); + throw new CardException("Unexpected response to Select Command: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private void executeSelectMasterFile() throws CardException { + + byte[] apdu = new byte[ESDNIeCard.MASTER_FILE_ID.length + 5]; + apdu[0] = (byte) 0x00; + apdu[1] = (byte) 0xA4; + apdu[2] = (byte) 0x04; + apdu[3] = (byte) 0x00; + apdu[4] = (byte) ESDNIeCard.MASTER_FILE_ID.length; + System.arraycopy(ESDNIeCard.MASTER_FILE_ID, 0, apdu, 5, + ESDNIeCard.MASTER_FILE_ID.length); + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = super.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error selecting master file: " + + Integer.toHexString(resp.getSW())); + throw new CardException("Error selecting master file: " + + Integer.toHexString(resp.getSW())); + } + } + + private void verifyCertificates() throws CardException { + + // This method verifies the card's component and intermediate + // certificates cryptographically only (no revocation checking). + + RSAPublicKey rootPubKey = DNIeCryptoUtil.createRSAPublicKey( + ROOT_CA_MODULO, ROOT_CA_PUBEXP); + + X509Certificate intermediate = DNIeCryptoUtil + .createCertificate(intermediateCert); + X509Certificate component = DNIeCryptoUtil + .createCertificate(componentCert); + + try { + component.verify(intermediate.getPublicKey()); + intermediate.verify(rootPubKey); + } catch (Exception e) { + + log.error("Error verifying SM card certificate.", e); + throw new CardException("Certificate verification failed.", e); + } + } + + private void loadTerminalCertsAndSelectKeys() throws CardException { + + // MSE + executeManageSecurityEnvironment((byte) 0x81, (byte) 0xB6, new byte[] { + (byte) 0x83, (byte) 0x02, (byte) 0x02, (byte) 0x0F }); + + // PSO - load intermediate certificate + executePerformSecurityOperation(C_CV_CA); + + // MSE + executeManageSecurityEnvironment((byte) 0x81, (byte) 0xB6, CHR); + + // PSO - load terminal certificate + executePerformSecurityOperation(C_CV_IFD); + + // MSE - select keys + executeManageSecurityEnvironment((byte) 0xC1, (byte) 0xA4, KEY_SELECTOR); + + } + + private void executeManageSecurityEnvironment(byte p1, byte p2, byte[] data) + throws CardException { + + // MSE + CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x22, p1, p2, + data); + ResponseAPDU resp = super.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error executing Manage Security Environment: " + + Integer.toHexString(resp.getSW())); + throw new CardException( + "Unexpected response from card during preparation of secure channel credentials: " + + Integer.toHexString(resp.getSW())); + } + } + + private void executePerformSecurityOperation(byte[] data) + throws CardException { + + // PSO - load intermediate certificate + CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x2A, + (byte) 0x00, (byte) 0xAE, data); + ResponseAPDU resp = super.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error executing Perform Security Operation: " + + Integer.toHexString(resp.getSW())); + throw new CardException( + "Unexpected response from card during preparation of secure channel credentials: " + + Integer.toHexString(resp.getSW())); + } + } + + private void performInternalAuthentication() throws CardException { + + log.trace("Starting internal authentication.."); + + byte[] randomBytes = DNIeCryptoUtil.getRandomBytes(BLOCK_LENGTH); + byte[] challengeData = new byte[randomBytes.length + + TERMINAL_CHALLENGE_TAIL.length]; + + this.rndIfd = randomBytes; + + System.arraycopy(randomBytes, 0, challengeData, 0, randomBytes.length); + System.arraycopy(TERMINAL_CHALLENGE_TAIL, 0, challengeData, + randomBytes.length, TERMINAL_CHALLENGE_TAIL.length); + + byte[] responseData = executeSendTerminalChallenge(challengeData); + + // verify response + boolean ok = verifyCardResponse(responseData); + + log.trace("Internal Authentiction succeeded: " + ok); + + if (!ok) { + + log + .error("Internal authentication failed - unable to sucessfully verify card response."); + throw new CardException("Internal authentication failed"); + } + + } + + private byte[] executeSendTerminalChallenge(byte[] challenge) + throws CardException { + + // send challenge to card + CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x88, + (byte) 0x00, (byte) 0x00, challenge); + ResponseAPDU resp = super.transmit(command); + + byte[] data = null; + + if (resp.getSW() == 0x9000) { + + data = resp.getData(); + + } else { + + log.error("Error sending terminal challenge to card: " + + Integer.toHexString(resp.getSW())); + throw new CardException("Invalid response to terminal challenge: " + + Integer.toHexString(resp.getSW())); + } + + return data; + } + + private boolean verifyCardResponse(byte[] resp) throws CardException { + + byte[] challenge = this.rndIfd; + byte[] response = resp; + + // decrypt response with terminal private key + byte[] plain = null; + RSAPrivateKey terminalPrivateKey = DNIeCryptoUtil.createRSAPrivateKey( + TERMINAL_MODULO, TERMINAL_PRIVEXP); + try { + plain = DNIeCryptoUtil.rsaDecrypt(terminalPrivateKey, response); + } catch (Exception e) { + log.error("Error verifying card response."); + throw new CardException("Error decrypting card response.", e); + } + + X509Certificate cert = DNIeCryptoUtil.createCertificate(componentCert); + PublicKey pubKey = cert.getPublicKey(); + + byte[] sig = null; + + try { + sig = DNIeCryptoUtil.rsaDecrypt(pubKey, plain); + + } catch (Exception e) { + + log.error("Error verifying card response.", e); + throw new CardException( + "Error decrypting card response with card's public key", e); + } + + if (sig == null) { + + log + .error("Error verifying card response - decryption result is null"); + throw new CardException("Invalid decryption result: null."); + } else { + + if (sig[0] == (byte) 0x6A && sig[sig.length - 1] == (byte) 0xBC) { + + // Obtained response from card was obviously SIG - nothing else + // to do here so far + + } else { + + // Obtained response from card was probably N.ICC-SIG - + // compute N.ICC-SIG and decrypt result again + + RSAPublicKey rsaPubKey = (RSAPublicKey) pubKey; + BigInteger mod = rsaPubKey.getModulus(); + BigInteger sigVal = SMCCHelper.createUnsignedBigInteger(plain); + + BigInteger substractionResult = mod.subtract(sigVal); + byte[] encrypted = substractionResult.toByteArray(); + + // necessary if substraction result contains leading + // zero byte + byte[] trimmed = new byte[128]; + System.arraycopy(encrypted, encrypted.length - 128, trimmed, 0, + 128); + + try { + sig = DNIeCryptoUtil.rsaDecrypt(pubKey, trimmed); + + } catch (Exception e) { + + log.error("Error verifying card response.", e); + throw new CardException("Error decrypting card response.", + e); + } + } + } + + // extract data from decrypted response + byte[] hash = new byte[20]; + byte[] kIcc = new byte[32]; + byte[] prnd1 = new byte[sig.length - 2 - 20 - 32]; + + this.prndLength = prnd1.length; + + System.arraycopy(sig, 1, prnd1, 0, prnd1.length); // 1 byte offset due + // to 6A padding + System.arraycopy(sig, prnd1.length + 1, kIcc, 0, kIcc.length); + System.arraycopy(sig, prnd1.length + kIcc.length + 1, hash, 0, + hash.length); + + // verify hash + byte[] hashData = new byte[prnd1.length + kIcc.length + + challenge.length + TERMINAL_CHALLENGE_TAIL.length]; + + System.arraycopy(prnd1, 0, hashData, 0, prnd1.length); + System.arraycopy(kIcc, 0, hashData, prnd1.length, kIcc.length); + System.arraycopy(challenge, 0, hashData, prnd1.length + kIcc.length, + challenge.length); + System.arraycopy(TERMINAL_CHALLENGE_TAIL, 0, hashData, prnd1.length + + kIcc.length + challenge.length, + TERMINAL_CHALLENGE_TAIL.length); + + byte[] digest = DNIeCryptoUtil.computeSHA1Hash(hashData); + + boolean internalAuthResult = Arrays.equals(hash, digest); + + if (internalAuthResult) { + + // if verification succeeded, remember kicc for subsequent channel + // key derivation + this.kicc = kIcc; + } + + return internalAuthResult; + } + + private void performExternalAuthentication() throws CardException { + + log.trace("Performing external authentication."); + + byte[] cardChallenge = executeRequestCardChallenge(); + + this.rndIcc = cardChallenge; + + byte[] prnd2 = DNIeCryptoUtil.getRandomBytes(this.prndLength); + + byte[] kIfd = DNIeCryptoUtil.getRandomBytes(32); + + // compute hash + byte[] hashData = new byte[prnd2.length + kIfd.length + + cardChallenge.length + BLOCK_LENGTH]; + + System.arraycopy(prnd2, 0, hashData, 0, prnd2.length); + System.arraycopy(kIfd, 0, hashData, prnd2.length, kIfd.length); + System.arraycopy(cardChallenge, 0, hashData, + prnd2.length + kIfd.length, cardChallenge.length); + + int snPadding = BLOCK_LENGTH - snIcc.length; + + for (int i = 0; i < snPadding; i++) { + + hashData[prnd2.length + kIfd.length + cardChallenge.length + i] = (byte) 0x00; + } + + System.arraycopy(snIcc, 0, hashData, prnd2.length + kIfd.length + + cardChallenge.length + snPadding, snIcc.length); + + byte[] digest = DNIeCryptoUtil.computeSHA1Hash(hashData); + + // prepare data to be encrypted + byte[] plain = new byte[2 + prnd2.length + kIfd.length + digest.length]; + + plain[0] = (byte) 0x6A; + + System.arraycopy(prnd2, 0, plain, 1, prnd2.length); + System.arraycopy(kIfd, 0, plain, 1 + prnd2.length, kIfd.length); + System.arraycopy(digest, 0, plain, 1 + prnd2.length + kIfd.length, + digest.length); + + plain[plain.length - 1] = (byte) 0xBC; + + // encrypt plain data + RSAPrivateKey terminalPrivateKey = DNIeCryptoUtil.createRSAPrivateKey( + TERMINAL_MODULO, TERMINAL_PRIVEXP); + + byte[] encResult = null; + try { + encResult = DNIeCryptoUtil.rsaEncrypt(terminalPrivateKey, plain); + } catch (Exception e) { + log.error("Error performing external authentication.", e); + throw new CardException("Error encrypting authentication data.", e); + } + + // apply MIN function + BigInteger sig = SMCCHelper.createUnsignedBigInteger(encResult); + BigInteger mod = new BigInteger(TERMINAL_MODULO, 16); + + BigInteger diff = mod.subtract(sig); + BigInteger sigMin = diff.min(sig); + + // encrypt with card public key + PublicKey cardPubKey = null; + + X509Certificate cert = DNIeCryptoUtil.createCertificate(componentCert); + cardPubKey = cert.getPublicKey(); + + byte[] authData = null; + try { + authData = DNIeCryptoUtil.rsaEncrypt(cardPubKey, sigMin + .toByteArray()); + } catch (Exception e) { + log.error("Error performing external authentication.", e); + throw new CardException("Error encrypting authentication data.", e); + } + + // send auth data to card + // BE CAREFUL WITH THAT! EXT-AUTH METHOD MAY GET BLOCKED! + if (executeExternalAuthenticate(authData)) { + + log.trace("External authentication succeeded."); + this.kifd = kIfd; + } else { + log.error("Error performing external authentication"); + throw new CardException("External Authentication failed."); + } + + } + + private byte[] executeRequestCardChallenge() throws CardException { + + CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x84, + (byte) 0x00, (byte) 0x00, (byte) BLOCK_LENGTH); + ResponseAPDU resp = super.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error requesting challenge from card: " + + Integer.toHexString(resp.getSW())); + throw new CardException( + "Invalid response from card upon challenge request: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private boolean executeExternalAuthenticate(byte[] authData) + throws CardException { + + CommandAPDU command = new CommandAPDU((byte) 0x00, (byte) 0x82, + (byte) 0x00, (byte) 0x00, authData); + ResponseAPDU resp = super.transmit(command); + + log.trace("Card answer to EXTERNL AUTHENTICATE: " + + Integer.toHexString(resp.getSW())); + + return resp.getSW() == 0x9000; + } + + private void calculateChannelKeys() throws CardException { + + if (this.kicc == null || this.kifd == null) { + + log + .error("Error generating channel keys - required key data is null."); + throw new CardException( + "Required data for deriving keys not available."); + } + + if (this.kicc.length != this.kifd.length) { + + log.error("Error generating channel keys - invalid key data"); + throw new CardException( + "Required data for deriving keys is invalid."); + } + + byte[] kifdicc = new byte[this.kicc.length]; + + for (int i = 0; i < kifdicc.length; i++) { + + kifdicc[i] = (byte) (this.kicc[i] ^ this.kifd[i]); + } + + byte[] kEncHashData = new byte[kifdicc.length + + KENC_COMPUTATION_TAIL.length]; + byte[] kMacHashData = new byte[kifdicc.length + + KMAC_COMPUTATION_TAIL.length]; + + System.arraycopy(kifdicc, 0, kEncHashData, 0, kifdicc.length); + System.arraycopy(kifdicc, 0, kMacHashData, 0, kifdicc.length); + + System.arraycopy(KENC_COMPUTATION_TAIL, 0, kEncHashData, + kifdicc.length, KENC_COMPUTATION_TAIL.length); + System.arraycopy(KMAC_COMPUTATION_TAIL, 0, kMacHashData, + kifdicc.length, KMAC_COMPUTATION_TAIL.length); + + byte[] hashEnc = DNIeCryptoUtil.computeSHA1Hash(kEncHashData); + byte[] hashMac = DNIeCryptoUtil.computeSHA1Hash(kMacHashData); + + this.kEnc = Arrays.copyOfRange(hashEnc, 0, 16); + this.kMac = Arrays.copyOfRange(hashMac, 0, 16); + + // compute sequence counter SSC + if (this.rndIcc == null || this.rndIfd == null + || this.rndIcc.length < 4 || this.rndIfd.length < 4) { + + log.error("Error generating channel keys - invlaid ssc data"); + throw new CardException("Data required to compute SSC not valid."); + } + + this.ssc = new byte[BLOCK_LENGTH]; + + System.arraycopy(this.rndIcc, this.rndIcc.length - 4, this.ssc, 0, 4); + System.arraycopy(this.rndIfd, this.rndIfd.length - 4, this.ssc, 4, 4); + } + + private byte[] secureAPDUWithoutData(byte[] apdu) throws CardException { + + if (apdu.length < 4 || apdu.length > 5) { + + log.error("Error securing APDU - invalid APDU length: " + + apdu.length); + throw new CardException("Invalid APDU length."); + } + + boolean leAvailable = apdu.length == 5; + + byte encCLA = (byte) (apdu[0] | (byte) 0x0C); + byte[] encHeader = new byte[] { encCLA, apdu[1], apdu[2], apdu[3] }; + byte[] paddedHeader = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, + encHeader); + + int leFieldLen; + byte[] leField = null; + if (leAvailable) { + leField = new byte[3]; + leField[0] = (byte) 0x97; + leField[1] = (byte) 0x01; + leField[2] = apdu[4]; + leFieldLen = leField.length; + } else { + + leFieldLen = 0; + } + + byte[] macData = new byte[paddedHeader.length + leFieldLen]; + System.arraycopy(paddedHeader, 0, macData, 0, paddedHeader.length); + + if (leAvailable) { + System.arraycopy(leField, 0, macData, paddedHeader.length, + leField.length); + + macData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, macData); + } + + incrementSSC(); + + byte[] mac = DNIeCryptoUtil.calculateAPDUMAC(macData, kMac, this.ssc, + BLOCK_LENGTH); + + byte[] encapsulatedMac = new byte[mac.length + 2]; + encapsulatedMac[0] = (byte) 0x8E; + encapsulatedMac[1] = (byte) mac.length; + System.arraycopy(mac, 0, encapsulatedMac, 2, mac.length); + + byte[] completeMessage = new byte[5 + leFieldLen + + encapsulatedMac.length]; + completeMessage[0] = encCLA; + completeMessage[1] = apdu[1]; + completeMessage[2] = apdu[2]; + completeMessage[3] = apdu[3]; + completeMessage[4] = (byte) (encapsulatedMac.length + leFieldLen); + + if (leAvailable) { + System.arraycopy(leField, 0, completeMessage, 5, leField.length); + } + + System.arraycopy(encapsulatedMac, 0, completeMessage, 5 + leFieldLen, + encapsulatedMac.length); + + return completeMessage; + + } + + private byte[] secureAPDUWithData(byte[] apdu) throws CardException { + + if (apdu.length < 6) { + + log.error("Error securing APDU - invalid APDU length: " + + apdu.length); + throw new CardException( + "Error securing APDU - invalid APDU length: " + apdu.length); + } + + byte cla = apdu[0]; + byte ins = apdu[1]; + byte p1 = apdu[2]; + byte p2 = apdu[3]; + byte lc = apdu[4]; + + boolean leAvailable; + if (apdu.length == lc + 5 + 1) { + + leAvailable = true; + } else if (apdu.length != lc + 5) { + + log.error("Error securing APDU - invalid APDU length: " + + apdu.length); + throw new CardException("Invalid APDU length or format."); + } else { + + leAvailable = false; + } + + byte[] leField = null; + if (leAvailable) { + + byte le = apdu[apdu.length - 1]; + + leField = new byte[3]; + leField[0] = (byte) 0x97; + leField[1] = (byte) 0x01; + leField[2] = le; + } + + byte[] data = new byte[lc]; + System.arraycopy(apdu, 5, data, 0, lc); + + byte[] paddedData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, data); + + byte[] encrypted = null; + + try { + + encrypted = DNIeCryptoUtil.perform3DESCipherOperation(paddedData, + kEnc, Cipher.ENCRYPT_MODE); + + } catch (Exception e) { + + log.error("Error encrypting APDU.", e); + throw new CardException("Error encrypting APDU.", e); + } + + byte[] encapsulated = new byte[encrypted.length + 3]; + encapsulated[0] = (byte) 0x87; + encapsulated[1] = (byte) (encrypted.length + 1); + encapsulated[2] = (byte) 0x01; + System.arraycopy(encrypted, 0, encapsulated, 3, encrypted.length); + + // calculate MAC + byte encCLA = (byte) (cla | (byte) 0x0C); + byte[] encHeader = new byte[] { encCLA, ins, p1, p2 }; + byte[] paddedHeader = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, + encHeader); + + byte[] headerAndData = new byte[paddedHeader.length + + encapsulated.length]; + System + .arraycopy(paddedHeader, 0, headerAndData, 0, + paddedHeader.length); + System.arraycopy(encapsulated, 0, headerAndData, paddedHeader.length, + encapsulated.length); + + if (leAvailable) { + byte[] macData = new byte[headerAndData.length + leField.length]; + System + .arraycopy(headerAndData, 0, macData, 0, + headerAndData.length); + System.arraycopy(leField, 0, macData, headerAndData.length, + leField.length); + + headerAndData = macData; + } + + byte[] paddedHeaderAndData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, + headerAndData); + + incrementSSC(); + + byte[] mac = DNIeCryptoUtil.calculateAPDUMAC(paddedHeaderAndData, kMac, + this.ssc, BLOCK_LENGTH); + + byte[] encapsulatedMac = new byte[mac.length + 2]; + encapsulatedMac[0] = (byte) 0x8E; + encapsulatedMac[1] = (byte) mac.length; + System.arraycopy(mac, 0, encapsulatedMac, 2, mac.length); + + int leFieldLen; + if (leAvailable) { + leFieldLen = leField.length; + } else { + leFieldLen = 0; + } + + byte[] completeMessage = new byte[5 + encapsulated.length + + encapsulatedMac.length + leFieldLen]; + completeMessage[0] = encCLA; + completeMessage[1] = ins; + completeMessage[2] = p1; + completeMessage[3] = p2; + + completeMessage[4] = (byte) (encapsulated.length + leFieldLen + encapsulatedMac.length); + System.arraycopy(encapsulated, 0, completeMessage, 5, + encapsulated.length); + + if (leAvailable) { + System.arraycopy(leField, 0, completeMessage, + 5 + encapsulated.length, leFieldLen); + } + + System.arraycopy(encapsulatedMac, 0, completeMessage, 5 + + encapsulated.length + leFieldLen, encapsulatedMac.length); + + return completeMessage; + + } + + private byte[] secureAPDU(byte[] apdu) throws CardException { + + if (apdu == null || apdu.length < 4) { + + log.error("Invalid APDU to secure."); + throw new CardException("Invalid APDU to secure."); + } + + if (apdu.length == 4 || apdu.length == 5) { + + return secureAPDUWithoutData(apdu); + } + + if (apdu.length > 5) { + + return secureAPDUWithData(apdu); + } + + throw new CardException("Error securing APDU - unexpected APDU length."); + } + + private byte[] verifyAndDecryptSecuredResponseAPDU(byte[] securedAPDU) + throws CardException { + + byte[] data = new byte[securedAPDU.length - 10]; + byte[] commandResponse = new byte[4]; + byte[] obtainedMac = new byte[4]; + + System.arraycopy(securedAPDU, 0, data, 0, data.length); + System.arraycopy(securedAPDU, data.length, commandResponse, 0, + commandResponse.length); + System.arraycopy(securedAPDU, data.length + commandResponse.length + 2, + obtainedMac, 0, obtainedMac.length); + + byte[] macData = new byte[data.length + commandResponse.length]; + System.arraycopy(data, 0, macData, 0, data.length); + System.arraycopy(commandResponse, 0, macData, data.length, + commandResponse.length); + + byte[] paddedMacData = DNIeCryptoUtil.applyPadding(BLOCK_LENGTH, + macData); + + incrementSSC(); + + byte[] mac = DNIeCryptoUtil.calculateAPDUMAC(paddedMacData, this.kMac, + this.ssc, BLOCK_LENGTH); + + if (!Arrays.equals(mac, obtainedMac)) { + + log + .error("Error verifiying MAC of secured response. MAC values do not match."); + throw new CardException("Unable to verify MAC of Response APDU."); + } + + if (data.length > 0) { + + byte[] data2decrypt = new byte[data.length + - DNIeCryptoUtil.getCutOffLength(data, BLOCK_LENGTH)]; + System.arraycopy(data, DNIeCryptoUtil.getCutOffLength(data, + BLOCK_LENGTH), data2decrypt, 0, data2decrypt.length); + + byte[] plainData = null; + + try { + plainData = DNIeCryptoUtil.perform3DESCipherOperation( + data2decrypt, this.kEnc, Cipher.DECRYPT_MODE); + } catch (Exception e) { + log.error("Error decrypting data.", e); + throw new CardException("Unable to decrypt data.", e); + } + + byte[] unpaddedData = DNIeCryptoUtil.removePadding(plainData); + + byte[] result = new byte[unpaddedData.length + 2]; + System.arraycopy(unpaddedData, 0, result, 0, unpaddedData.length); + result[result.length - 2] = commandResponse[2]; + result[result.length - 1] = commandResponse[3]; + + return result; + } else { + + // no data in response + byte[] result = new byte[2]; + result[result.length - 2] = commandResponse[2]; + result[result.length - 1] = commandResponse[3]; + return result; + } + } + + private void incrementSSC() { + + BigInteger ssc = new BigInteger(this.ssc); + ssc = ssc.add(new BigInteger("1", 10)); + this.ssc = ssc.toByteArray(); + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ESDNIeCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ESDNIeCard.java index 4f1c7610..b787d5b9 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ESDNIeCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ESDNIeCard.java @@ -1,496 +1,520 @@ -package at.gv.egiz.smcc; - -import at.gv.egiz.smcc.cio.CIOCertificate; -import at.gv.egiz.smcc.cio.ObjectDirectory; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.zip.DataFormatException; -import java.util.zip.Inflater; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.ResponseAPDU; -import javax.smartcardio.CommandAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.pin.gui.PINGUI; -import at.gv.egiz.smcc.util.SMCCHelper; - -public class ESDNIeCard extends AbstractSignatureCard implements SignatureCard { - - public static final byte[] MASTER_FILE_ID = new byte[] { - - (byte) 0x4D, (byte) 0x61, (byte) 0x73, (byte) 0x74, (byte) 0x65, - (byte) 0x72, (byte) 0x2E, (byte) 0x46, (byte) 0x69, (byte) 0x6C, - (byte) 0x65 }; - - private final byte[] HASH_PADDING = new byte[] { - - (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, - (byte) 0x05, (byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02, - (byte) 0x1A, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 }; - - private final String SIG_KEY_NAME = "KprivFirmaDigital"; - private final String SIG_CERT_NAME = "CertFirmaDigital"; - - private final Logger log = LoggerFactory.getLogger(ESDNIeCard.class); - - protected PinInfo pinInfo = new PinInfo(8, 16, - "[0-9A-Za-z_<>!()?%\\-=&+\\.]", "at/gv/egiz/smcc/ESDNIeCard", - "sig.pin", (byte) 0x00, new byte[] {}, PinInfo.UNKNOWN_RETRIES); - - - @Override - protected CardChannel getCardChannel() { - - // set up a new secure channel each time - return new DNIeSecuredChannel(getCard().getBasicChannel()); - } - - @Override - @Exclusive - public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINGUI pinGUI, String alg) throws SignatureCardException, - InterruptedException, IOException { - - CardChannel channel = getCardChannel(); - - try { - - // Select MF - executeSelectMasterFile(channel); - - // Select DF.CIA - executeSelectDFCIA(channel); - - ObjectDirectory efOd = new ObjectDirectory(); - efOd.selectAndRead(channel); - - DNIeCIOCertificateDirectory efPrkd = new DNIeCIOCertificateDirectory( - efOd.getPrKDReferences().get(0)); - efPrkd.selectAndRead(channel); - - byte[] efKey = null; - for (CIOCertificate cioCertificate : efPrkd.getCIOs()) { - String label = cioCertificate.getLabel(); - if (label != null - && label.toLowerCase().contains( - SIG_KEY_NAME.toLowerCase())) { - efKey = cioCertificate.getEfidOrPath(); - } - } - - // Check PIN - // CommandAPDU c = new CommandAPDU((byte) 0x00, (byte) 0x20, - // (byte) 0x00, (byte) 0x00); - // ResponseAPDU r = channel.transmit(c); - // log.debug("Answer to PIN Check: " - // + SMCCHelper.toString(r.getBytes())); - - if (efKey == null) { - throw new NotActivatedException(); - } - - verifyPINLoop(channel, pinInfo, pinGUI); - - if (efKey != null && efKey.length >= 2) { - - byte[] keyId = new byte[2]; - keyId[0] = efKey[efKey.length - 2]; - keyId[1] = efKey[efKey.length - 1]; - - executeManageSecurityEnvironment(channel, keyId); - } else { - - throw new CardException( - "Unable to determine valid key path. Key path either null or unexpected length."); - } - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get MessageDigest.", e); - throw new SignatureCardException(e); - } - // calculate message digest - byte[] digest = new byte[md.getDigestLength()]; - for (int l; (l = input.read(digest)) != -1;) { - md.update(digest, 0, l); - } - digest = md.digest(); - - return executeCreateSignature(channel, digest); - - } catch (CardException e) { - - log.error("Error during signature creation.", e); - throw new SignatureCardException( - "Error creating signature with DNIe card.", e); - } - - } - - @Override - @Exclusive - public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) - throws SignatureCardException, InterruptedException { - - byte[] result = null; - - CardChannel channel = getCardChannel(); - - byte[] certId = null; - - try { - - // Select MF - executeSelectMasterFile(channel); - - // Select DF.CIA - executeSelectDFCIA(channel); - - byte[] efQcert = null; - - ObjectDirectory efOd = new ObjectDirectory(); - efOd.selectAndRead(channel); - - DNIeCIOCertificateDirectory efCd = new DNIeCIOCertificateDirectory( - efOd.getCDReferences().get(0)); - - try { - efCd.selectAndRead(channel); - } catch (IOException e) { - - throw new CardException("Error retrieving certificate path. ", - e); - } - - for (CIOCertificate cioCertificate : efCd.getCIOs()) { - String label = cioCertificate.getLabel(); - if (label != null - && label.toLowerCase().contains( - SIG_CERT_NAME.toLowerCase())) { - efQcert = cioCertificate.getEfidOrPath(); - } - } - - if (efQcert == null) { - throw new NotActivatedException(); - } - - if (efQcert.length == 4) { - - certId = efQcert; - } else { - - throw new CardException( - "Unable to determine valid certificate path. Cert path has unexpected length."); - } - - // verify PIN to be able to read certificate - verifyPINLoop(channel, pinInfo, pinGUI); - - // select master file - executeSelectMasterFile(channel); - - // select certificate path - executeSelect(channel, new byte[] { certId[0], certId[1] }); - byte[] fci = executeSelect(channel, new byte[] { certId[2], - certId[3] }); - - byte sizeHi = fci[7]; - byte sizeLo = fci[8]; - - byte[] data = executeReadBinary(channel, sizeHi, sizeLo); - - byte[] compressedWithoutHeader = new byte[data.length - 8]; - System.arraycopy(data, 8, compressedWithoutHeader, 0, - compressedWithoutHeader.length); - - result = decompressData(compressedWithoutHeader); - - } catch (CardException e) { - - log.error("Error reading certificate from card.", e); - throw new SignatureCardException( - "Error reading certificate from card.", e); - } - - return result; - } - - - @Override - public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) - throws SignatureCardException, InterruptedException { - - log.debug("Attempting to read infobox from DNIe.."); - - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - } - - protected void verifyPINLoop(CardChannel channel, PinInfo spec, - PINGUI provider) throws LockedException, NotActivatedException, - SignatureCardException, InterruptedException, CardException { - - int retries = -1; - do { - retries = verifyPIN(channel, spec, provider, retries); - } while (retries > 0); - } - - protected int verifyPIN(CardChannel channel, PinInfo pinSpec, - PINGUI provider, int retries) throws SignatureCardException, - LockedException, NotActivatedException, InterruptedException, - CardException { - - char[] pin = provider.providePIN(pinSpec, retries); - - byte[] apdu = new byte[5 + pin.length]; - apdu[0] = (byte) 0x00; - apdu[1] = (byte) 0x20; - apdu[2] = (byte) 0x00; - apdu[3] = (byte) 0x00; - apdu[4] = (byte) pin.length; - - for (int i = 0; i < pin.length; i++) { - - apdu[i + 5] = (byte) pin[i]; - } - - ResponseAPDU resp = channel.transmit(new CommandAPDU(apdu)); - int result = resp.getSW(); - - if (result == 0x9000) { - return -1; - } - if (result >> 4 == 0x63c) { - return 0x0f & result; - } - - switch (result) { - case 0x6983: - // authentication method blocked - throw new LockedException(); - - default: - String msg = "VERIFY failed. SW=" + Integer.toHexString(result); - log.info(msg); - throw new SignatureCardException(msg); - } - } - - private void executeSelectMasterFile(CardChannel channel) - throws CardException { - - byte[] apdu = new byte[MASTER_FILE_ID.length + 5]; - apdu[0] = (byte) 0x00; - apdu[1] = (byte) 0xA4; - apdu[2] = (byte) 0x04; - apdu[3] = (byte) 0x00; - apdu[4] = (byte) MASTER_FILE_ID.length; - System.arraycopy(MASTER_FILE_ID, 0, apdu, 5, MASTER_FILE_ID.length); - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error selecting master file: " - + Integer.toHexString(resp.getSW())); - throw new CardException("Error selecting master file: " - + Integer.toHexString(resp.getSW())); - } - } - - private void executeSelectDFCIA(CardChannel channel) throws CardException { - - executeSelect(channel, new byte[] { (byte) 0x50, (byte) 0x015 }); - } - - private byte[] executeSelect(CardChannel channel, byte[] id) - throws CardException { - - byte[] apduHeader = new byte[] { - - (byte) 0x00, (byte) 0xA4, (byte) 0x00, (byte) 0x00, (byte) id.length }; - - byte[] apdu = new byte[apduHeader.length + id.length]; - System.arraycopy(apduHeader, 0, apdu, 0, apduHeader.length); - System.arraycopy(id, 0, apdu, apduHeader.length, id.length); - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("error selecting file " + SMCCHelper.toString(id) + ": " - + Integer.toHexString(resp.getSW())); - throw new CardException("Error selecting file " - + SMCCHelper.toString(id) + ": " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private byte[] executeReadBinary(CardChannel channel, byte lengthHi, - byte lengthLo) throws CardException { - - ByteArrayOutputStream bof = new ByteArrayOutputStream(); - - int bytes2read = (lengthHi * 256) + lengthLo; - int bytesRead = 0; - - boolean done = false; - - int offset = 0; - int len = 0; - - while (!done) { - - if (bytes2read - bytesRead > 0xef) { - len = 0xef; - } else { - len = bytes2read - bytesRead; - } - - byte[] offsetBytes = SMCCHelper.toByteArray(offset); - ResponseAPDU resp = readFromCard(channel, offsetBytes[0], - offsetBytes[1], (byte) len); - - if (resp.getSW1() == (byte) 0x6C) { - - // handle case: card returns 6CXX (wrong number of bytes - // requested) - - resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], - (byte) resp.getSW2()); - - // this has to be the final iteration - done = true; - } - - try { - bof.write(resp.getData()); - } catch (IOException e) { - log.error("Error executing secure read binary.", e); - throw new CardException("Error reading data from card", e); - } - - bytesRead = bytesRead + resp.getData().length; - offset = bytesRead; - - if (bytesRead == bytes2read) { - - done = true; - } - } - - return bof.toByteArray(); - } - - private void executeManageSecurityEnvironment(CardChannel channel, byte[] id) - throws CardException { - - byte[] apdu = new byte[7 + 2]; - apdu[0] = (byte) 0x00; - apdu[1] = (byte) 0x22; - apdu[2] = (byte) 0x41; - apdu[3] = (byte) 0xB6; - apdu[4] = (byte) (2 + 2); - apdu[5] = (byte) 0x84; - apdu[6] = (byte) 0x02; - apdu[7] = id[0]; - apdu[8] = id[1]; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error executing Manage Security Environment: " - + Integer.toHexString(resp.getSW())); - throw new CardException( - "Execution of command Manage Security Environment failed: " - + Integer.toHexString(resp.getSW())); - } - - } - - private byte[] executeCreateSignature(CardChannel channel, byte[] data) - throws CardException { - - byte[] apdu = new byte[5 + HASH_PADDING.length + data.length + 1]; - apdu[0] = (byte) 0x00; - apdu[1] = (byte) 0x2A; - apdu[2] = (byte) 0x9E; - apdu[3] = (byte) 0x9A; - apdu[4] = (byte) (HASH_PADDING.length + data.length); - - System.arraycopy(HASH_PADDING, 0, apdu, 5, HASH_PADDING.length); - System.arraycopy(data, 0, apdu, 5 + HASH_PADDING.length, data.length); - - apdu[apdu.length - 1] = (byte) 0x80; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - if (resp.getSW() != 0x9000) { - - log.error("Error computing electronic signature on card: " - + Integer.toHexString(resp.getSW())); - throw new CardException("Unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - - } - - private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, - byte offsetLo, byte numBytes) throws CardException { - - byte[] apdu = new byte[] { - - (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - return resp; - - } - - private byte[] decompressData(byte[] input) throws CardException { - - Inflater decompresser = new Inflater(); - decompresser.setInput(input, 0, input.length); - byte[] buffer = new byte[256]; - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - try { - while (!decompresser.finished()) { - - int numBytes = decompresser.inflate(buffer); - bos.write(buffer, 0, numBytes); - } - - decompresser.end(); - - } catch (DataFormatException e) { - - throw new CardException("Error decompressing file.", e); - } - - return bos.toByteArray(); - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import at.gv.egiz.smcc.cio.CIOCertificate; +import at.gv.egiz.smcc.cio.ObjectDirectory; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.ResponseAPDU; +import javax.smartcardio.CommandAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.SMCCHelper; + +public class ESDNIeCard extends AbstractSignatureCard implements SignatureCard { + + public static final byte[] MASTER_FILE_ID = new byte[] { + + (byte) 0x4D, (byte) 0x61, (byte) 0x73, (byte) 0x74, (byte) 0x65, + (byte) 0x72, (byte) 0x2E, (byte) 0x46, (byte) 0x69, (byte) 0x6C, + (byte) 0x65 }; + + private final byte[] HASH_PADDING = new byte[] { + + (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, + (byte) 0x05, (byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02, + (byte) 0x1A, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 }; + + private final String SIG_KEY_NAME = "KprivFirmaDigital"; + private final String SIG_CERT_NAME = "CertFirmaDigital"; + + private final Logger log = LoggerFactory.getLogger(ESDNIeCard.class); + + protected PinInfo pinInfo = new PinInfo(8, 16, + "[0-9A-Za-z_<>!()?%\\-=&+\\.]", "at/gv/egiz/smcc/ESDNIeCard", + "sig.pin", (byte) 0x00, new byte[] {}, PinInfo.UNKNOWN_RETRIES); + + + @Override + protected CardChannel getCardChannel() { + + // set up a new secure channel each time + return new DNIeSecuredChannel(getCard().getBasicChannel()); + } + + @Override + @Exclusive + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + CardChannel channel = getCardChannel(); + + try { + + // Select MF + executeSelectMasterFile(channel); + + // Select DF.CIA + executeSelectDFCIA(channel); + + ObjectDirectory efOd = new ObjectDirectory(); + efOd.selectAndRead(channel); + + DNIeCIOCertificateDirectory efPrkd = new DNIeCIOCertificateDirectory( + efOd.getPrKDReferences().get(0)); + efPrkd.selectAndRead(channel); + + byte[] efKey = null; + for (CIOCertificate cioCertificate : efPrkd.getCIOs()) { + String label = cioCertificate.getLabel(); + if (label != null + && label.toLowerCase().contains( + SIG_KEY_NAME.toLowerCase())) { + efKey = cioCertificate.getEfidOrPath(); + } + } + + // Check PIN + // CommandAPDU c = new CommandAPDU((byte) 0x00, (byte) 0x20, + // (byte) 0x00, (byte) 0x00); + // ResponseAPDU r = channel.transmit(c); + // log.debug("Answer to PIN Check: " + // + SMCCHelper.toString(r.getBytes())); + + if (efKey == null) { + throw new NotActivatedException(); + } + + verifyPINLoop(channel, pinInfo, pinGUI); + + if (efKey != null && efKey.length >= 2) { + + byte[] keyId = new byte[2]; + keyId[0] = efKey[efKey.length - 2]; + keyId[1] = efKey[efKey.length - 1]; + + executeManageSecurityEnvironment(channel, keyId); + } else { + + throw new CardException( + "Unable to determine valid key path. Key path either null or unexpected length."); + } + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + byte[] digest = new byte[md.getDigestLength()]; + for (int l; (l = input.read(digest)) != -1;) { + md.update(digest, 0, l); + } + digest = md.digest(); + + return executeCreateSignature(channel, digest); + + } catch (CardException e) { + + log.error("Error during signature creation.", e); + throw new SignatureCardException( + "Error creating signature with DNIe card.", e); + } + + } + + @Override + @Exclusive + public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) + throws SignatureCardException, InterruptedException { + + byte[] result = null; + + CardChannel channel = getCardChannel(); + + byte[] certId = null; + + try { + + // Select MF + executeSelectMasterFile(channel); + + // Select DF.CIA + executeSelectDFCIA(channel); + + byte[] efQcert = null; + + ObjectDirectory efOd = new ObjectDirectory(); + efOd.selectAndRead(channel); + + DNIeCIOCertificateDirectory efCd = new DNIeCIOCertificateDirectory( + efOd.getCDReferences().get(0)); + + try { + efCd.selectAndRead(channel); + } catch (IOException e) { + + throw new CardException("Error retrieving certificate path. ", + e); + } + + for (CIOCertificate cioCertificate : efCd.getCIOs()) { + String label = cioCertificate.getLabel(); + if (label != null + && label.toLowerCase().contains( + SIG_CERT_NAME.toLowerCase())) { + efQcert = cioCertificate.getEfidOrPath(); + } + } + + if (efQcert == null) { + throw new NotActivatedException(); + } + + if (efQcert.length == 4) { + + certId = efQcert; + } else { + + throw new CardException( + "Unable to determine valid certificate path. Cert path has unexpected length."); + } + + // verify PIN to be able to read certificate + verifyPINLoop(channel, pinInfo, pinGUI); + + // select master file + executeSelectMasterFile(channel); + + // select certificate path + executeSelect(channel, new byte[] { certId[0], certId[1] }); + byte[] fci = executeSelect(channel, new byte[] { certId[2], + certId[3] }); + + byte sizeHi = fci[7]; + byte sizeLo = fci[8]; + + byte[] data = executeReadBinary(channel, sizeHi, sizeLo); + + byte[] compressedWithoutHeader = new byte[data.length - 8]; + System.arraycopy(data, 8, compressedWithoutHeader, 0, + compressedWithoutHeader.length); + + result = decompressData(compressedWithoutHeader); + + } catch (CardException e) { + + log.error("Error reading certificate from card.", e); + throw new SignatureCardException( + "Error reading certificate from card.", e); + } + + return result; + } + + + @Override + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + log.debug("Attempting to read infobox from DNIe.."); + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider) throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + int retries = -1; + do { + retries = verifyPIN(channel, spec, provider, retries); + } while (retries > 0); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries) throws SignatureCardException, + LockedException, NotActivatedException, InterruptedException, + CardException { + + char[] pin = provider.providePIN(pinSpec, retries); + + byte[] apdu = new byte[5 + pin.length]; + apdu[0] = (byte) 0x00; + apdu[1] = (byte) 0x20; + apdu[2] = (byte) 0x00; + apdu[3] = (byte) 0x00; + apdu[4] = (byte) pin.length; + + for (int i = 0; i < pin.length; i++) { + + apdu[i + 5] = (byte) pin[i]; + } + + ResponseAPDU resp = channel.transmit(new CommandAPDU(apdu)); + int result = resp.getSW(); + + if (result == 0x9000) { + return -1; + } + if (result >> 4 == 0x63c) { + return 0x0f & result; + } + + switch (result) { + case 0x6983: + // authentication method blocked + throw new LockedException(); + + default: + String msg = "VERIFY failed. SW=" + Integer.toHexString(result); + log.info(msg); + throw new SignatureCardException(msg); + } + } + + private void executeSelectMasterFile(CardChannel channel) + throws CardException { + + byte[] apdu = new byte[MASTER_FILE_ID.length + 5]; + apdu[0] = (byte) 0x00; + apdu[1] = (byte) 0xA4; + apdu[2] = (byte) 0x04; + apdu[3] = (byte) 0x00; + apdu[4] = (byte) MASTER_FILE_ID.length; + System.arraycopy(MASTER_FILE_ID, 0, apdu, 5, MASTER_FILE_ID.length); + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error selecting master file: " + + Integer.toHexString(resp.getSW())); + throw new CardException("Error selecting master file: " + + Integer.toHexString(resp.getSW())); + } + } + + private void executeSelectDFCIA(CardChannel channel) throws CardException { + + executeSelect(channel, new byte[] { (byte) 0x50, (byte) 0x015 }); + } + + private byte[] executeSelect(CardChannel channel, byte[] id) + throws CardException { + + byte[] apduHeader = new byte[] { + + (byte) 0x00, (byte) 0xA4, (byte) 0x00, (byte) 0x00, (byte) id.length }; + + byte[] apdu = new byte[apduHeader.length + id.length]; + System.arraycopy(apduHeader, 0, apdu, 0, apduHeader.length); + System.arraycopy(id, 0, apdu, apduHeader.length, id.length); + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("error selecting file " + SMCCHelper.toString(id) + ": " + + Integer.toHexString(resp.getSW())); + throw new CardException("Error selecting file " + + SMCCHelper.toString(id) + ": " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private byte[] executeReadBinary(CardChannel channel, byte lengthHi, + byte lengthLo) throws CardException { + + ByteArrayOutputStream bof = new ByteArrayOutputStream(); + + int bytes2read = (lengthHi * 256) + lengthLo; + int bytesRead = 0; + + boolean done = false; + + int offset = 0; + int len = 0; + + while (!done) { + + if (bytes2read - bytesRead > 0xef) { + len = 0xef; + } else { + len = bytes2read - bytesRead; + } + + byte[] offsetBytes = SMCCHelper.toByteArray(offset); + ResponseAPDU resp = readFromCard(channel, offsetBytes[0], + offsetBytes[1], (byte) len); + + if (resp.getSW1() == (byte) 0x6C) { + + // handle case: card returns 6CXX (wrong number of bytes + // requested) + + resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], + (byte) resp.getSW2()); + + // this has to be the final iteration + done = true; + } + + try { + bof.write(resp.getData()); + } catch (IOException e) { + log.error("Error executing secure read binary.", e); + throw new CardException("Error reading data from card", e); + } + + bytesRead = bytesRead + resp.getData().length; + offset = bytesRead; + + if (bytesRead == bytes2read) { + + done = true; + } + } + + return bof.toByteArray(); + } + + private void executeManageSecurityEnvironment(CardChannel channel, byte[] id) + throws CardException { + + byte[] apdu = new byte[7 + 2]; + apdu[0] = (byte) 0x00; + apdu[1] = (byte) 0x22; + apdu[2] = (byte) 0x41; + apdu[3] = (byte) 0xB6; + apdu[4] = (byte) (2 + 2); + apdu[5] = (byte) 0x84; + apdu[6] = (byte) 0x02; + apdu[7] = id[0]; + apdu[8] = id[1]; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error executing Manage Security Environment: " + + Integer.toHexString(resp.getSW())); + throw new CardException( + "Execution of command Manage Security Environment failed: " + + Integer.toHexString(resp.getSW())); + } + + } + + private byte[] executeCreateSignature(CardChannel channel, byte[] data) + throws CardException { + + byte[] apdu = new byte[5 + HASH_PADDING.length + data.length + 1]; + apdu[0] = (byte) 0x00; + apdu[1] = (byte) 0x2A; + apdu[2] = (byte) 0x9E; + apdu[3] = (byte) 0x9A; + apdu[4] = (byte) (HASH_PADDING.length + data.length); + + System.arraycopy(HASH_PADDING, 0, apdu, 5, HASH_PADDING.length); + System.arraycopy(data, 0, apdu, 5 + HASH_PADDING.length, data.length); + + apdu[apdu.length - 1] = (byte) 0x80; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + if (resp.getSW() != 0x9000) { + + log.error("Error computing electronic signature on card: " + + Integer.toHexString(resp.getSW())); + throw new CardException("Unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + + } + + private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, + byte offsetLo, byte numBytes) throws CardException { + + byte[] apdu = new byte[] { + + (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + return resp; + + } + + private byte[] decompressData(byte[] input) throws CardException { + + Inflater decompresser = new Inflater(); + decompresser.setInput(input, 0, input.length); + byte[] buffer = new byte[256]; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + try { + while (!decompresser.finished()) { + + int numBytes = decompresser.inflate(buffer); + bos.write(buffer, 0, numBytes); + } + + decompresser.end(); + + } catch (DataFormatException e) { + + throw new CardException("Error decompressing file.", e); + } + + return bos.toByteArray(); + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java b/smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java index 4d1b0855..9092c089 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/EstEIDCard.java @@ -1,19 +1,26 @@ /* -* Copyright 2009 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 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java b/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java index 9e208e36..fc156376 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ExclSignatureCardProxy.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import java.lang.reflect.InvocationHandler; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java b/smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java index b796b045..26e5511c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/Exclusive.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import java.lang.annotation.ElementType; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAODirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAODirectory.java index 3fd1503c..7a928740 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAODirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAODirectory.java @@ -1,143 +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; - -import iaik.me.asn1.ASN1; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.TLVSequence; - -public class FINEIDAODirectory { - - protected static final Logger log = LoggerFactory.getLogger(CIOCertificateDirectory.class); - protected byte[] fid; - protected List aos; - - public FINEIDAODirectory(byte[] fid) { - - this.fid = FINEIDUtil.removeMFPath(fid); - aos = new ArrayList(); - } - - /** - * assume DF.CIA selected - * CIO.CD selected afterwards - * - * @param channel - * @throws CardException - * @throws SignatureCardException - * @throws IOException if ASN.1 structure cannot be parsed - */ - public void selectAndRead(CardChannel channel) throws CardException, SignatureCardException, IOException { - - CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x08, ISO7816Utils.P2_FCI, fid, 256); - ResponseAPDU resp = channel.transmit(cmd); - - byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCI); - byte[] fd = new TLVSequence(fcx).getValue(0x82); - - if ((fd[0] & 0x05) == 0x01) { - - readAuthenticationObjectsFromTransparentFile(channel); - } - } - - protected byte[] doReadTransparentFile(CardChannel channel) throws CardException, SignatureCardException { - - return ISO7816Utils.readTransparentFile(channel, -1); - } - - protected void readAuthenticationObjectsFromTransparentFile(CardChannel channel) throws CardException, SignatureCardException, IOException { - - byte[] ef = doReadTransparentFile(channel); - - int i = 0; - int j; - - do { - int length = 0; - int ll = 0; - if ((ef[i + 1] & 0xf0) == 0x80) { - ll = ef[i + 1] & 0x7f; - for (int it = 0; it < ll; it++) { - length = (length << 8) + (ef[i + it + 2] & 0xff); - } - } else { - length = (ef[i + 1] & 0xff); - } - - log.trace("read transparent file entry: tag 0x{}, length 0x{}", Integer.toHexString(ef[i]), - Integer.toHexString(length)); - - j = i + 2 + ll + length; - addAuthenticationObject(Arrays.copyOfRange(ef, i, j)); - i = j; - } while (i < ef.length && ef[i] > 0); - - } - - protected void addAuthenticationObject(byte[] ao) throws IOException { - - ASN1 authenticationObjects = new ASN1(ao); - - FINEIDAuthenticationObject authObject = new FINEIDAuthenticationObject(); - authObject.setLabel(authenticationObjects.getElementAt(0).getElementAt(0).gvString()); - - authObject.setAuthId(authenticationObjects.getElementAt(1).getElementAt(0).gvByteArray()); - - //read CONTEXTSPECIFIC manually - byte[] ctxSpecific = authenticationObjects.getElementAt(authenticationObjects.getSize()-1).getEncoded(); - - if ((ctxSpecific[0] & 0xff) == 0xa1) { - int ll = ((ctxSpecific[1] & 0xf0) == 0x80) - ? (ctxSpecific[1] & 0x0f) + 2 : 2; - ASN1 aoAttributes = new ASN1(Arrays.copyOfRange(ctxSpecific, ll, ctxSpecific.length)); - - authObject.setPath(aoAttributes.getElementAt(aoAttributes.getSize()-1).getElementAt(0).gvByteArray()); - - // get pwdReference - byte[] ctxSpecific2 = aoAttributes.getElementAt(4).getEncoded(); - ASN1 pwdRef = new ASN1(ctxSpecific2); - - authObject.setPwdReference(pwdRef.gvByteArray()); - - } else { - log.warn("expected CONTEXTSPECIFIC, got 0x{}", - Integer.toHexString(ctxSpecific[0])); - } - - log.debug("adding {}", authObject); - aos.add(authObject); - } - - public List getAOs() { - return aos; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import iaik.me.asn1.ASN1; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.TLVSequence; + +public class FINEIDAODirectory { + + protected static final Logger log = LoggerFactory.getLogger(CIOCertificateDirectory.class); + protected byte[] fid; + protected List aos; + + public FINEIDAODirectory(byte[] fid) { + + this.fid = FINEIDUtil.removeMFPath(fid); + aos = new ArrayList(); + } + + /** + * assume DF.CIA selected + * CIO.CD selected afterwards + * + * @param channel + * @throws CardException + * @throws SignatureCardException + * @throws IOException if ASN.1 structure cannot be parsed + */ + public void selectAndRead(CardChannel channel) throws CardException, SignatureCardException, IOException { + + CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x08, ISO7816Utils.P2_FCI, fid, 256); + ResponseAPDU resp = channel.transmit(cmd); + + byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCI); + byte[] fd = new TLVSequence(fcx).getValue(0x82); + + if ((fd[0] & 0x05) == 0x01) { + + readAuthenticationObjectsFromTransparentFile(channel); + } + } + + protected byte[] doReadTransparentFile(CardChannel channel) throws CardException, SignatureCardException { + + return ISO7816Utils.readTransparentFile(channel, -1); + } + + protected void readAuthenticationObjectsFromTransparentFile(CardChannel channel) throws CardException, SignatureCardException, IOException { + + byte[] ef = doReadTransparentFile(channel); + + int i = 0; + int j; + + do { + int length = 0; + int ll = 0; + if ((ef[i + 1] & 0xf0) == 0x80) { + ll = ef[i + 1] & 0x7f; + for (int it = 0; it < ll; it++) { + length = (length << 8) + (ef[i + it + 2] & 0xff); + } + } else { + length = (ef[i + 1] & 0xff); + } + + log.trace("read transparent file entry: tag 0x{}, length 0x{}", Integer.toHexString(ef[i]), + Integer.toHexString(length)); + + j = i + 2 + ll + length; + addAuthenticationObject(Arrays.copyOfRange(ef, i, j)); + i = j; + } while (i < ef.length && ef[i] > 0); + + } + + protected void addAuthenticationObject(byte[] ao) throws IOException { + + ASN1 authenticationObjects = new ASN1(ao); + + FINEIDAuthenticationObject authObject = new FINEIDAuthenticationObject(); + authObject.setLabel(authenticationObjects.getElementAt(0).getElementAt(0).gvString()); + + authObject.setAuthId(authenticationObjects.getElementAt(1).getElementAt(0).gvByteArray()); + + //read CONTEXTSPECIFIC manually + byte[] ctxSpecific = authenticationObjects.getElementAt(authenticationObjects.getSize()-1).getEncoded(); + + if ((ctxSpecific[0] & 0xff) == 0xa1) { + int ll = ((ctxSpecific[1] & 0xf0) == 0x80) + ? (ctxSpecific[1] & 0x0f) + 2 : 2; + ASN1 aoAttributes = new ASN1(Arrays.copyOfRange(ctxSpecific, ll, ctxSpecific.length)); + + authObject.setPath(aoAttributes.getElementAt(aoAttributes.getSize()-1).getElementAt(0).gvByteArray()); + + // get pwdReference + byte[] ctxSpecific2 = aoAttributes.getElementAt(4).getEncoded(); + ASN1 pwdRef = new ASN1(ctxSpecific2); + + authObject.setPwdReference(pwdRef.gvByteArray()); + + } else { + log.warn("expected CONTEXTSPECIFIC, got 0x{}", + Integer.toHexString(ctxSpecific[0])); + } + + log.debug("adding {}", authObject); + aos.add(authObject); + } + + public List getAOs() { + return aos; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAuthenticationObject.java b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAuthenticationObject.java index d25946f1..13afb485 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAuthenticationObject.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDAuthenticationObject.java @@ -1,57 +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 FINEIDAuthenticationObject { - - private String label; - private byte[] authId; - private byte[] path; - private byte[] pwdReference; - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public byte[] getAuthId() { - return authId; - } - - public void setAuthId(byte[] authId) { - this.authId = authId; - } - - public byte[] getPath() { - return path; - } - - public void setPath(byte[] path) { - this.path = path; - } - - public byte[] getPwdReference() { - return pwdReference; - } - - public void setPwdReference(byte[] pwdReference) { - this.pwdReference = pwdReference; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +public class FINEIDAuthenticationObject { + + private String label; + private byte[] authId; + private byte[] path; + private byte[] pwdReference; + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public byte[] getAuthId() { + return authId; + } + + public void setAuthId(byte[] authId) { + this.authId = authId; + } + + public byte[] getPath() { + return path; + } + + public void setPath(byte[] path) { + this.path = path; + } + + public byte[] getPwdReference() { + return pwdReference; + } + + public void setPwdReference(byte[] pwdReference) { + this.pwdReference = pwdReference; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOCertificateDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOCertificateDirectory.java index 537154c7..de4b5a4f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOCertificateDirectory.java @@ -1,47 +1,54 @@ -/* - * 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.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.TLVSequence; - -public class FINEIDCIOCertificateDirectory extends CIOCertificateDirectory { - - public FINEIDCIOCertificateDirectory(byte[] fid) { - - super(fid); - this.fid = FINEIDUtil.removeMFPath(fid); - } - - @Override - protected byte[] executeSelect(CardChannel channel) throws CardException { - - CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x08, ISO7816Utils.P2_FCI, fid, 256); - ResponseAPDU resp = channel.transmit(cmd); - - byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCI); - byte[] fd = new TLVSequence(fcx).getValue(0x82); - - return fd; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.TLVSequence; + +public class FINEIDCIOCertificateDirectory extends CIOCertificateDirectory { + + public FINEIDCIOCertificateDirectory(byte[] fid) { + + super(fid); + this.fid = FINEIDUtil.removeMFPath(fid); + } + + @Override + protected byte[] executeSelect(CardChannel channel) throws CardException { + + CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x08, ISO7816Utils.P2_FCI, fid, 256); + ResponseAPDU resp = channel.transmit(cmd); + + byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCI); + byte[] fd = new TLVSequence(fcx).getValue(0x82); + + return fd; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOKeyDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOKeyDirectory.java index 2d89e5bc..d4a0a19e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOKeyDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOKeyDirectory.java @@ -1,33 +1,40 @@ -/* - * 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 FINEIDCIOKeyDirectory extends FINEIDCIOCertificateDirectory { - - protected static final boolean RETRIEVE_AUTH_ID_FROM_ASN1 = Boolean.TRUE; - - public FINEIDCIOKeyDirectory(byte[] fid) { - - super(fid); - } - - protected boolean retrieveAuthIdFromASN1() { - - return RETRIEVE_AUTH_ID_FROM_ASN1; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +public class FINEIDCIOKeyDirectory extends FINEIDCIOCertificateDirectory { + + protected static final boolean RETRIEVE_AUTH_ID_FROM_ASN1 = Boolean.TRUE; + + public FINEIDCIOKeyDirectory(byte[] fid) { + + super(fid); + } + + protected boolean retrieveAuthIdFromASN1() { + + return RETRIEVE_AUTH_ID_FROM_ASN1; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCard.java b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCard.java index 92371d8e..4e911d1c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCard.java @@ -1,365 +1,372 @@ -/* - * 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.cio.CIOCertificate; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.pin.gui.PINGUI; -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.SMCCHelper; -import at.gv.egiz.smcc.util.TLVSequence; - -public class FINEIDCard extends AbstractSignatureCard implements SignatureCard { - - private static final int EF_OD_PADDING = 0xFF; - private static final String SIG_CERT_LABEL = "allekirjoitusvarmenne"; - private static final String SIG_KEY_LABEL = "allekirjoitusavain"; - - private final Logger log = LoggerFactory.getLogger(FINEIDCard.class); - - protected PinInfo pinInfo = new PinInfo(6, 8, "[0-9]", - "at/gv/egiz/smcc/FINEIDCard", "sig.pin", (byte) 0x00, - new byte[] {}, PinInfo.UNKNOWN_RETRIES); - - @Override - public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINGUI pinGUI, String alg) throws SignatureCardException, - InterruptedException, IOException { - - CardChannel channel = getCardChannel(); - - try { - - FINEIDEFObjectDirectory ef_od = new FINEIDEFObjectDirectory( - EF_OD_PADDING); - ef_od.selectAndRead(channel); - - // read PRKD to find correct key - FINEIDCIOKeyDirectory ef_prkd = new FINEIDCIOKeyDirectory(ef_od - .getPrKDReferences().get(0)); - ef_prkd.selectAndRead(channel); - - byte[] efKey = null; - byte[] authID = null; - - for (CIOCertificate cioCertificate : ef_prkd.getCIOs()) { - String label = cioCertificate.getLabel(); - if (label != null - && label.toLowerCase().contains( - SIG_KEY_LABEL.toLowerCase())) { - - efKey = cioCertificate.getEfidOrPath(); - authID = cioCertificate.getAuthId(); - } - } - - if (efKey == null) { - - throw new SignatureCardException( - "Could not determine path to private key from PrKD."); - } - - if (authID == null) { - - throw new SignatureCardException( - "Could not determine authID of private key from PrKD."); - } - - // read AOD to find the associated PIN (authId must match) - FINEIDAODirectory ef_aod = new FINEIDAODirectory(ef_od.getAODReferences().get(0)); - ef_aod.selectAndRead(channel); - - byte[] pinPath = null; - byte[] pwdRef = null; - for (FINEIDAuthenticationObject ao : ef_aod.getAOs()) { - - byte[] id = ao.getAuthId(); - if (id != null && Arrays.equals(id, authID)) { - pinPath = ao.getPath(); - pwdRef = ao.getPwdReference(); - } - } - - if (pinPath == null) { - - throw new SignatureCardException( - "Could not determine path to PIN from AOD."); - } - - if (pwdRef == null) { - - throw new SignatureCardException( - "Could not determine PIN reference from AOD."); - } - - // verify PIN - verifyPINLoop(channel, pinInfo, pinGUI, pinPath, - pwdRef[pwdRef.length - 1]); - - // Set MSE - CommandAPDU selectKeyPath = new CommandAPDU((byte) 0x00, - (byte) 0xA4, (byte) 0x08, (byte) 0x00, FINEIDUtil - .removeMFPath(efKey)); - ResponseAPDU resp = channel.transmit(selectKeyPath); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Could not select private key file DF."); - } - - executeRestoreMSE(channel); - - byte[] dst = new byte[] { (byte) 0x80, (byte) 0x01, (byte) 0x12, - (byte) 0x81, (byte) 0x02, efKey[efKey.length - 2], - efKey[efKey.length - 1] }; - - executeSetMSE(channel, dst); - - // SIGN - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get MessageDigest.", e); - throw new SignatureCardException(e); - } - // calculate message digest - byte[] digest = new byte[md.getDigestLength()]; - for (int l; (l = input.read(digest)) != -1;) { - md.update(digest, 0, l); - } - digest = md.digest(); - - byte[] sigVal = executeSign(channel, digest); - return sigVal; - - } catch (CardException e) { - - throw new SignatureCardException("Error creating signature.", e); - } - - } - - @Override - public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) - throws SignatureCardException, InterruptedException { - - CardChannel channel = getCardChannel(); - - try { - FINEIDEFObjectDirectory ef_od = new FINEIDEFObjectDirectory( - EF_OD_PADDING); - ef_od.selectAndRead(channel); - - byte[] certPath = null; - - for (int i = 0; i < ef_od.getCDReferences().size(); i++) { - - FINEIDCIOCertificateDirectory ef_cd = new FINEIDCIOCertificateDirectory( - ef_od.getCDReferences().get(i)); - - try { - ef_cd.selectAndRead(channel); - } catch (IOException e) { - log.debug("Cannot read EF.CD - try next one in list.."); - continue; - } - - for (CIOCertificate cioCertificate : ef_cd.getCIOs()) { - String label = cioCertificate.getLabel(); - if (label != null - && label.toLowerCase().contains( - SIG_CERT_LABEL.toLowerCase())) { - certPath = cioCertificate.getEfidOrPath(); - } - } - } - - if (certPath == null) { - - throw new SignatureCardException( - "Could not determine path to certificate."); - } - - log - .debug("Read certificate path: " - + SMCCHelper.toString(certPath)); - - certPath = FINEIDUtil.removeMFPath(certPath); - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x08, (byte) 0x00, certPath); - ResponseAPDU resp = channel.transmit(apdu); - - byte[] fcx = new TLVSequence(resp.getBytes()) - .getValue(ISO7816Utils.TAG_FCI); - byte[] fileDataLength = new TLVSequence(fcx).getValue(0x81); - - return ISO7816Utils.readTransparentFile(channel, - computeLengthFromByteArray(fileDataLength)); - - } catch (CardException e) { - - throw new SignatureCardException( - "Error reading certificate from card.", e); - } - } - - @Override - public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) - throws SignatureCardException, InterruptedException { - - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - } - - protected void verifyPINLoop(CardChannel channel, PinInfo spec, - PINGUI provider, byte[] pinPath, byte keyID) - throws LockedException, NotActivatedException, - SignatureCardException, InterruptedException, CardException { - - CommandAPDU verifySelect = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x08, (byte) 0x00, FINEIDUtil.removeMFPath(pinPath)); - ResponseAPDU response = channel.transmit(verifySelect); - - if (response.getSW() != 0x9000) { - - throw new SignatureCardException("Cannot select PIN path " - + SMCCHelper.toString(pinPath) + ": " - + Integer.toHexString(response.getSW())); - } - - int retries = -1; - - do { - retries = verifyPIN(channel, spec, provider, retries, keyID); - } while (retries > 0); - } - - protected int verifyPIN(CardChannel channel, PinInfo pinSpec, - PINGUI provider, int retries, byte keyID) - throws SignatureCardException, LockedException, - NotActivatedException, InterruptedException, CardException { - - VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(new byte[] { (byte) 0x00, - (byte) 0x20, (byte) 0x00, keyID, (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, provider, pinSpec, - 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(); - 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); - } - - } - - private void executeRestoreMSE(CardChannel channel) throws CardException { - - CommandAPDU mseRestore = new CommandAPDU((byte) 0x00, (byte) 0x22, - (byte) 0xF3, (byte) 0x00); - ResponseAPDU resp = channel.transmit(mseRestore); - - if (resp.getSW() != 0x9000) { - - throw new CardException("Error restoring MSE: " - + Integer.toHexString(resp.getSW())); - } - - } - - private void executeSetMSE(CardChannel channel, byte[] dst) - throws CardException { - - CommandAPDU mseSet = new CommandAPDU((byte) 0x00, (byte) 0x22, - (byte) 0x41, (byte) 0xB6, dst); - ResponseAPDU resp = channel.transmit(mseSet); - - if (resp.getSW() != 0x9000) { - - throw new CardException("Error setting MSE: " - + Integer.toHexString(resp.getSW())); - } - - } - - private byte[] executeSign(CardChannel channel, byte[] hash) - throws CardException { - - CommandAPDU sign = new CommandAPDU((byte) 0x00, (byte) 0x2A, - (byte) 0x9E, (byte) 0x9A, hash); - ResponseAPDU resp = channel.transmit(sign); - - if (resp.getSW() != 0x9000) { - - throw new CardException("Error signing hash: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private int computeLengthFromByteArray(byte[] input) { - - int result = 0; - - for (int i = 0; i < input.length; i++) { - int current = input[input.length - 1 - i]; - result = result + (int) (current * Math.pow(256, i)); - } - return result; - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import at.gv.egiz.smcc.cio.CIOCertificate; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.SMCCHelper; +import at.gv.egiz.smcc.util.TLVSequence; + +public class FINEIDCard extends AbstractSignatureCard implements SignatureCard { + + private static final int EF_OD_PADDING = 0xFF; + private static final String SIG_CERT_LABEL = "allekirjoitusvarmenne"; + private static final String SIG_KEY_LABEL = "allekirjoitusavain"; + + private final Logger log = LoggerFactory.getLogger(FINEIDCard.class); + + protected PinInfo pinInfo = new PinInfo(6, 8, "[0-9]", + "at/gv/egiz/smcc/FINEIDCard", "sig.pin", (byte) 0x00, + new byte[] {}, PinInfo.UNKNOWN_RETRIES); + + @Override + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + CardChannel channel = getCardChannel(); + + try { + + FINEIDEFObjectDirectory ef_od = new FINEIDEFObjectDirectory( + EF_OD_PADDING); + ef_od.selectAndRead(channel); + + // read PRKD to find correct key + FINEIDCIOKeyDirectory ef_prkd = new FINEIDCIOKeyDirectory(ef_od + .getPrKDReferences().get(0)); + ef_prkd.selectAndRead(channel); + + byte[] efKey = null; + byte[] authID = null; + + for (CIOCertificate cioCertificate : ef_prkd.getCIOs()) { + String label = cioCertificate.getLabel(); + if (label != null + && label.toLowerCase().contains( + SIG_KEY_LABEL.toLowerCase())) { + + efKey = cioCertificate.getEfidOrPath(); + authID = cioCertificate.getAuthId(); + } + } + + if (efKey == null) { + + throw new SignatureCardException( + "Could not determine path to private key from PrKD."); + } + + if (authID == null) { + + throw new SignatureCardException( + "Could not determine authID of private key from PrKD."); + } + + // read AOD to find the associated PIN (authId must match) + FINEIDAODirectory ef_aod = new FINEIDAODirectory(ef_od.getAODReferences().get(0)); + ef_aod.selectAndRead(channel); + + byte[] pinPath = null; + byte[] pwdRef = null; + for (FINEIDAuthenticationObject ao : ef_aod.getAOs()) { + + byte[] id = ao.getAuthId(); + if (id != null && Arrays.equals(id, authID)) { + pinPath = ao.getPath(); + pwdRef = ao.getPwdReference(); + } + } + + if (pinPath == null) { + + throw new SignatureCardException( + "Could not determine path to PIN from AOD."); + } + + if (pwdRef == null) { + + throw new SignatureCardException( + "Could not determine PIN reference from AOD."); + } + + // verify PIN + verifyPINLoop(channel, pinInfo, pinGUI, pinPath, + pwdRef[pwdRef.length - 1]); + + // Set MSE + CommandAPDU selectKeyPath = new CommandAPDU((byte) 0x00, + (byte) 0xA4, (byte) 0x08, (byte) 0x00, FINEIDUtil + .removeMFPath(efKey)); + ResponseAPDU resp = channel.transmit(selectKeyPath); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Could not select private key file DF."); + } + + executeRestoreMSE(channel); + + byte[] dst = new byte[] { (byte) 0x80, (byte) 0x01, (byte) 0x12, + (byte) 0x81, (byte) 0x02, efKey[efKey.length - 2], + efKey[efKey.length - 1] }; + + executeSetMSE(channel, dst); + + // SIGN + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + byte[] digest = new byte[md.getDigestLength()]; + for (int l; (l = input.read(digest)) != -1;) { + md.update(digest, 0, l); + } + digest = md.digest(); + + byte[] sigVal = executeSign(channel, digest); + return sigVal; + + } catch (CardException e) { + + throw new SignatureCardException("Error creating signature.", e); + } + + } + + @Override + public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) + throws SignatureCardException, InterruptedException { + + CardChannel channel = getCardChannel(); + + try { + FINEIDEFObjectDirectory ef_od = new FINEIDEFObjectDirectory( + EF_OD_PADDING); + ef_od.selectAndRead(channel); + + byte[] certPath = null; + + for (int i = 0; i < ef_od.getCDReferences().size(); i++) { + + FINEIDCIOCertificateDirectory ef_cd = new FINEIDCIOCertificateDirectory( + ef_od.getCDReferences().get(i)); + + try { + ef_cd.selectAndRead(channel); + } catch (IOException e) { + log.debug("Cannot read EF.CD - try next one in list.."); + continue; + } + + for (CIOCertificate cioCertificate : ef_cd.getCIOs()) { + String label = cioCertificate.getLabel(); + if (label != null + && label.toLowerCase().contains( + SIG_CERT_LABEL.toLowerCase())) { + certPath = cioCertificate.getEfidOrPath(); + } + } + } + + if (certPath == null) { + + throw new SignatureCardException( + "Could not determine path to certificate."); + } + + log + .debug("Read certificate path: " + + SMCCHelper.toString(certPath)); + + certPath = FINEIDUtil.removeMFPath(certPath); + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x08, (byte) 0x00, certPath); + ResponseAPDU resp = channel.transmit(apdu); + + byte[] fcx = new TLVSequence(resp.getBytes()) + .getValue(ISO7816Utils.TAG_FCI); + byte[] fileDataLength = new TLVSequence(fcx).getValue(0x81); + + return ISO7816Utils.readTransparentFile(channel, + computeLengthFromByteArray(fileDataLength)); + + } catch (CardException e) { + + throw new SignatureCardException( + "Error reading certificate from card.", e); + } + } + + @Override + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider, byte[] pinPath, byte keyID) + throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + CommandAPDU verifySelect = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x08, (byte) 0x00, FINEIDUtil.removeMFPath(pinPath)); + ResponseAPDU response = channel.transmit(verifySelect); + + if (response.getSW() != 0x9000) { + + throw new SignatureCardException("Cannot select PIN path " + + SMCCHelper.toString(pinPath) + ": " + + Integer.toHexString(response.getSW())); + } + + int retries = -1; + + do { + retries = verifyPIN(channel, spec, provider, retries, keyID); + } while (retries > 0); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries, byte keyID) + throws SignatureCardException, LockedException, + NotActivatedException, InterruptedException, CardException { + + VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(new byte[] { (byte) 0x00, + (byte) 0x20, (byte) 0x00, keyID, (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, provider, pinSpec, + 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(); + 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); + } + + } + + private void executeRestoreMSE(CardChannel channel) throws CardException { + + CommandAPDU mseRestore = new CommandAPDU((byte) 0x00, (byte) 0x22, + (byte) 0xF3, (byte) 0x00); + ResponseAPDU resp = channel.transmit(mseRestore); + + if (resp.getSW() != 0x9000) { + + throw new CardException("Error restoring MSE: " + + Integer.toHexString(resp.getSW())); + } + + } + + private void executeSetMSE(CardChannel channel, byte[] dst) + throws CardException { + + CommandAPDU mseSet = new CommandAPDU((byte) 0x00, (byte) 0x22, + (byte) 0x41, (byte) 0xB6, dst); + ResponseAPDU resp = channel.transmit(mseSet); + + if (resp.getSW() != 0x9000) { + + throw new CardException("Error setting MSE: " + + Integer.toHexString(resp.getSW())); + } + + } + + private byte[] executeSign(CardChannel channel, byte[] hash) + throws CardException { + + CommandAPDU sign = new CommandAPDU((byte) 0x00, (byte) 0x2A, + (byte) 0x9E, (byte) 0x9A, hash); + ResponseAPDU resp = channel.transmit(sign); + + if (resp.getSW() != 0x9000) { + + throw new CardException("Error signing hash: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private int computeLengthFromByteArray(byte[] input) { + + int result = 0; + + for (int i = 0; i < input.length; i++) { + int current = input[input.length - 1 - i]; + result = result + (int) (current * Math.pow(256, i)); + } + return result; + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDEFObjectDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDEFObjectDirectory.java index ce44a892..61d7b1a9 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDEFObjectDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDEFObjectDirectory.java @@ -1,28 +1,35 @@ -/* - * 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.cio.ObjectDirectory; - -public class FINEIDEFObjectDirectory extends ObjectDirectory { - - public FINEIDEFObjectDirectory(int padding) { - - super(padding, 0x00); - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import at.gv.egiz.smcc.cio.ObjectDirectory; + +public class FINEIDEFObjectDirectory extends ObjectDirectory { + + public FINEIDEFObjectDirectory(int padding) { + + super(padding, 0x00); + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDUtil.java b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDUtil.java index 11f37100..c28eb6b0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDUtil.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDUtil.java @@ -1,37 +1,45 @@ -/* -* 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 FINEIDUtil { - - public static byte[] removeMFPath(byte[] completePath) { - - byte[] result = null; - - // remove MF path - if (completePath.length >= 2 && completePath[0] == 0x3F - && completePath[1] == 0x00) { - result = new byte[completePath.length - 2]; - System.arraycopy(completePath, 2, result, 0, - completePath.length - 2); - } else { - result = completePath; - } - - return result; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +public class FINEIDUtil { + + public static byte[] removeMFPath(byte[] completePath) { + + byte[] result = null; + + // remove MF path + if (completePath.length >= 2 && completePath[0] == 0x3F + && completePath[1] == 0x00) { + result = new byte[completePath.length - 2]; + System.arraycopy(completePath, 2, result, 0, + completePath.length - 2); + } else { + result = completePath; + } + + return result; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FileNotFoundException.java b/smcc/src/main/java/at/gv/egiz/smcc/FileNotFoundException.java index f96611c2..acc7b5c2 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FileNotFoundException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FileNotFoundException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class FileNotFoundException extends SignatureCardException { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ISMAESTROCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ISMAESTROCard.java index e72ccb7b..03974293 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ISMAESTROCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ISMAESTROCard.java @@ -1,400 +1,424 @@ -package at.gv.egiz.smcc; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import at.gv.egiz.smcc.pin.gui.PINGUI; -import at.gv.egiz.smcc.util.SMCCHelper; -import at.gv.egiz.smcc.util.TLV; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ISMAESTROCard extends AbstractISCard implements SignatureCard { - - private static final byte[] APPLET_ID = new byte[] { (byte) 0xA0, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x50, - (byte) 0x4B, (byte) 0x43, (byte) 0x53, (byte) 0x2D, (byte) 0x31, - (byte) 0x35 }; - - private static final String CERTIFICATE_IDENTIFIER = "Undirritun"; - - private static final PinInfo PIN_SPEC = new PinInfo(6, 6, "[0-9]", - "at/gv/egiz/smcc/ISMAESTROCard", "sig.pin", (byte) 0x02, - new byte[] {}, PinInfo.UNKNOWN_RETRIES); - - private final Logger log = LoggerFactory.getLogger(ISMAESTROCard.class); - - @Override - @Exclusive - public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINGUI pinGUI, String alg) throws SignatureCardException, - InterruptedException, IOException { - - CardChannel channel = getCardChannel(); - - byte[] signatureValue = null; - - try { - selectApplet(channel); - - // MSE RESTORE - executeMSERestore(channel); - - selectFile(channel, new byte[] { (byte) 0x45, (byte) 0x41 }); - - // VERIFY PIN - verifyPINLoop(channel, PIN_SPEC, pinGUI); - - // MSE SET - executeMSESet(channel); - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get MessageDigest.", e); - throw new SignatureCardException(e); - } - // calculate message digest - byte[] digest = new byte[md.getDigestLength()]; - for (int l; (l = input.read(digest)) != -1;) { - md.update(digest, 0, l); - } - digest = md.digest(); - - signatureValue = executePSOCDS(channel, digest); - - } catch (CardException e) { - throw new SignatureCardException("Error creating signature.", e); - } - - return signatureValue; - } - - protected void verifyPINLoop(CardChannel channel, PinInfo spec, - PINGUI provider) throws LockedException, NotActivatedException, - SignatureCardException, InterruptedException, CardException { - - int retries = -1; - do { - retries = verifyPIN(channel, spec, provider, retries); - } while (retries >= -1); - } - - protected int verifyPIN(CardChannel channel, PinInfo pinSpec, - PINGUI provider, int retries) throws SignatureCardException, - LockedException, NotActivatedException, InterruptedException, - CardException { - - VerifyAPDUSpec apduSpecProductive = new VerifyAPDUSpec(new byte[] { - (byte) 0x80, (byte) 0x20, (byte) 0x00, pinSpec.getKID(), - (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00 }, 0, - VerifyAPDUSpec.PIN_FORMAT_ASCII, 6); - - VerifyAPDUSpec apduSpec = apduSpecProductive; - - ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, - retries); - - if (resp.getSW() == 0x9000) { - return -2; - } - if (resp.getSW() >> 4 == 0x63c) { - return 0x0f & resp.getSW(); - } - - switch (resp.getSW()) { - case 0x6300: - // incorrect PIN, number of retries not provided - return -1; - case 0x6400: - // ? - throw new TimeoutException(); - 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(); - case 0x6700: - - // Probably we are dealing with a test card - try to send test card - // specific APDU sequence - return verifyTestCard(channel, pinSpec, provider, retries); - - default: - String msg = "VERIFY failed. SW=" - + Integer.toHexString(resp.getSW()); - log.info(msg); - throw new SignatureCardException(msg); - } - - } - - // This method verifies the PIN according to the test card specific APDU sequence - // Note that this requires an additional PIN entry. - private int verifyTestCard(CardChannel channel, PinInfo pinSpec, - PINGUI provider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException { - - VerifyAPDUSpec apduSpecTest = new VerifyAPDUSpec(new byte[] { (byte) - 0x80, - (byte) 0x20, (byte) 0x00, pinSpec.getKID(), (byte) 0x20, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF }, 0, - VerifyAPDUSpec.PIN_FORMAT_ASCII, 6); - - VerifyAPDUSpec apduSpec = apduSpecTest; - - ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, - retries); - - if (resp.getSW() == 0x9000) { - return -2; - } - if (resp.getSW() >> 4 == 0x63c) { - return 0x0f & resp.getSW(); - } - - switch (resp.getSW()) { - case 0x6300: - // incorrect PIN, number of retries not provided - return -1; - case 0x6400: - // ? - throw new TimeoutException(); - 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); - } - - } - - private byte[] executePSOCDS(CardChannel channel, byte[] digest) - throws CardException, SignatureCardException { - - byte[] data = new byte[digest.length + OID.length]; - System.arraycopy(OID, 0, data, 0, OID.length); - System.arraycopy(digest, 0, data, OID.length, digest.length); - - CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0x2A, - (byte) 0x9E, (byte) 0x9A, data); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException("Unexpected Response to PSO CDS: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private void executeMSESet(CardChannel channel) throws CardException, - SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0x22, - (byte) 0x41, (byte) 0xB6, new byte[] { (byte) 0x80, (byte) 01, - (byte) 0x01, (byte) 0x81, (byte) 0x02, (byte) 0x61, - (byte) 0x01, (byte) 0x84, (byte) 0x01, (byte) 0x00 }); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException("Unexpected Response to SET MSE: " - + Integer.toHexString(resp.getSW())); - } - - } - - private void executeMSERestore(CardChannel channel) throws CardException, - SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0x22, - (byte) 0xF3, (byte) 0x01); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Unexpected Response to RESTORE MSE: " - + Integer.toHexString(resp.getSW())); - } - - } - - @Override - @Exclusive - public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) - throws SignatureCardException, InterruptedException { - - CardChannel channel = getCardChannel(); - - byte[] cert = null; - - try { - selectApplet(channel); - - byte[] fileInfo = selectFile(channel, new byte[] { (byte) 0x45, - (byte) 0x41 }); - - TLV fileInfoTLV = new TLV(fileInfo, 0); - int len = toInt(fileInfoTLV.getValue()); - byte[] certs = executeReadBinary(channel, len); - - // get cert file info - fileInfo = selectFile(channel, new byte[] { (byte) 0x44, - (byte) 0x04 }); - - fileInfoTLV = new TLV(fileInfo, 0); - len = toInt(fileInfoTLV.getValue()); - - byte[] certsMetaInfo = executeReadBinary(channel, len); - cert = retrieveSigningCertificate(certs, certsMetaInfo, - CERTIFICATE_IDENTIFIER); - - } catch (CardException e) { - - throw new SignatureCardException("Error reading certificate.", e); - - } catch (IOException e) { - - throw new SignatureCardException("Error reading certificate.", e); - } - - return cert; - - } - - private byte[] selectFile(CardChannel channel, byte[] id) - throws CardException, SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0xA4, - (byte) 0x00, (byte) 0x00, id); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Error selecting DF. Unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private byte[] executeReadBinary(CardChannel channel, int length) - throws CardException { - - ByteArrayOutputStream bof = new ByteArrayOutputStream(); - - int bytesRead = 0; - boolean done = false; - int offset = 0; - - while (!done) { - - byte len = (length - bytesRead) < 0xff ? (byte) (length - bytesRead) - : (byte) 0xff; - - byte[] offsetBytes = SMCCHelper.toByteArray(offset); - ResponseAPDU resp = readFromCard(channel, offsetBytes[0], - offsetBytes[1], (byte) len); - - if (resp.getSW1() == (byte) 0x6C) { - - // handle case: card returns 6CXX (wrong number of bytes - // requested) - - resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], - (byte) resp.getSW2()); - } - - if (resp.getSW() == 0x6700) { - - done = true; - } - - try { - bof.write(resp.getData()); - } catch (IOException e) { - log.error("Error executing secure read binary.", e); - throw new CardException("Error reading data from card", e); - } - - bytesRead = bytesRead + resp.getData().length; - - if (bytesRead >= length) { - - done = true; - } - - offset = bytesRead; - } - - return bof.toByteArray(); - } - - private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, - byte offsetLo, byte numBytes) throws CardException { - - byte[] apdu = new byte[] { - - (byte) 0x80, (byte) 0xB0, offsetHi, offsetLo, numBytes }; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - return resp; - - } - - @Override - public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) - throws SignatureCardException, InterruptedException { - - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - } - - @Override - protected byte[] getAppletID() { - - return APPLET_ID; - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.SMCCHelper; +import at.gv.egiz.smcc.util.TLV; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ISMAESTROCard extends AbstractISCard implements SignatureCard { + + private static final byte[] APPLET_ID = new byte[] { (byte) 0xA0, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x50, + (byte) 0x4B, (byte) 0x43, (byte) 0x53, (byte) 0x2D, (byte) 0x31, + (byte) 0x35 }; + + private static final String CERTIFICATE_IDENTIFIER = "Undirritun"; + + private static final PinInfo PIN_SPEC = new PinInfo(6, 6, "[0-9]", + "at/gv/egiz/smcc/ISMAESTROCard", "sig.pin", (byte) 0x02, + new byte[] {}, PinInfo.UNKNOWN_RETRIES); + + private final Logger log = LoggerFactory.getLogger(ISMAESTROCard.class); + + @Override + @Exclusive + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + CardChannel channel = getCardChannel(); + + byte[] signatureValue = null; + + try { + selectApplet(channel); + + // MSE RESTORE + executeMSERestore(channel); + + selectFile(channel, new byte[] { (byte) 0x45, (byte) 0x41 }); + + // VERIFY PIN + verifyPINLoop(channel, PIN_SPEC, pinGUI); + + // MSE SET + executeMSESet(channel); + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + byte[] digest = new byte[md.getDigestLength()]; + for (int l; (l = input.read(digest)) != -1;) { + md.update(digest, 0, l); + } + digest = md.digest(); + + signatureValue = executePSOCDS(channel, digest); + + } catch (CardException e) { + throw new SignatureCardException("Error creating signature.", e); + } + + return signatureValue; + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider) throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + int retries = -1; + do { + retries = verifyPIN(channel, spec, provider, retries); + } while (retries >= -1); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries) throws SignatureCardException, + LockedException, NotActivatedException, InterruptedException, + CardException { + + VerifyAPDUSpec apduSpecProductive = new VerifyAPDUSpec(new byte[] { + (byte) 0x80, (byte) 0x20, (byte) 0x00, pinSpec.getKID(), + (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00 }, 0, + VerifyAPDUSpec.PIN_FORMAT_ASCII, 6); + + VerifyAPDUSpec apduSpec = apduSpecProductive; + + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, + retries); + + if (resp.getSW() == 0x9000) { + return -2; + } + if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } + + switch (resp.getSW()) { + case 0x6300: + // incorrect PIN, number of retries not provided + return -1; + case 0x6400: + // ? + throw new TimeoutException(); + 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(); + case 0x6700: + + // Probably we are dealing with a test card - try to send test card + // specific APDU sequence + return verifyTestCard(channel, pinSpec, provider, retries); + + default: + String msg = "VERIFY failed. SW=" + + Integer.toHexString(resp.getSW()); + log.info(msg); + throw new SignatureCardException(msg); + } + + } + + // This method verifies the PIN according to the test card specific APDU sequence + // Note that this requires an additional PIN entry. + private int verifyTestCard(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException { + + VerifyAPDUSpec apduSpecTest = new VerifyAPDUSpec(new byte[] { (byte) + 0x80, + (byte) 0x20, (byte) 0x00, pinSpec.getKID(), (byte) 0x20, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF }, 0, + VerifyAPDUSpec.PIN_FORMAT_ASCII, 6); + + VerifyAPDUSpec apduSpec = apduSpecTest; + + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, + retries); + + if (resp.getSW() == 0x9000) { + return -2; + } + if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } + + switch (resp.getSW()) { + case 0x6300: + // incorrect PIN, number of retries not provided + return -1; + case 0x6400: + // ? + throw new TimeoutException(); + 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); + } + + } + + private byte[] executePSOCDS(CardChannel channel, byte[] digest) + throws CardException, SignatureCardException { + + byte[] data = new byte[digest.length + OID.length]; + System.arraycopy(OID, 0, data, 0, OID.length); + System.arraycopy(digest, 0, data, OID.length, digest.length); + + CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0x2A, + (byte) 0x9E, (byte) 0x9A, data); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException("Unexpected Response to PSO CDS: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private void executeMSESet(CardChannel channel) throws CardException, + SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0x22, + (byte) 0x41, (byte) 0xB6, new byte[] { (byte) 0x80, (byte) 01, + (byte) 0x01, (byte) 0x81, (byte) 0x02, (byte) 0x61, + (byte) 0x01, (byte) 0x84, (byte) 0x01, (byte) 0x00 }); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException("Unexpected Response to SET MSE: " + + Integer.toHexString(resp.getSW())); + } + + } + + private void executeMSERestore(CardChannel channel) throws CardException, + SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0x22, + (byte) 0xF3, (byte) 0x01); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Unexpected Response to RESTORE MSE: " + + Integer.toHexString(resp.getSW())); + } + + } + + @Override + @Exclusive + public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) + throws SignatureCardException, InterruptedException { + + CardChannel channel = getCardChannel(); + + byte[] cert = null; + + try { + selectApplet(channel); + + byte[] fileInfo = selectFile(channel, new byte[] { (byte) 0x45, + (byte) 0x41 }); + + TLV fileInfoTLV = new TLV(fileInfo, 0); + int len = toInt(fileInfoTLV.getValue()); + byte[] certs = executeReadBinary(channel, len); + + // get cert file info + fileInfo = selectFile(channel, new byte[] { (byte) 0x44, + (byte) 0x04 }); + + fileInfoTLV = new TLV(fileInfo, 0); + len = toInt(fileInfoTLV.getValue()); + + byte[] certsMetaInfo = executeReadBinary(channel, len); + cert = retrieveSigningCertificate(certs, certsMetaInfo, + CERTIFICATE_IDENTIFIER); + + } catch (CardException e) { + + throw new SignatureCardException("Error reading certificate.", e); + + } catch (IOException e) { + + throw new SignatureCardException("Error reading certificate.", e); + } + + return cert; + + } + + private byte[] selectFile(CardChannel channel, byte[] id) + throws CardException, SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0xA4, + (byte) 0x00, (byte) 0x00, id); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Error selecting DF. Unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private byte[] executeReadBinary(CardChannel channel, int length) + throws CardException { + + ByteArrayOutputStream bof = new ByteArrayOutputStream(); + + int bytesRead = 0; + boolean done = false; + int offset = 0; + + while (!done) { + + byte len = (length - bytesRead) < 0xff ? (byte) (length - bytesRead) + : (byte) 0xff; + + byte[] offsetBytes = SMCCHelper.toByteArray(offset); + ResponseAPDU resp = readFromCard(channel, offsetBytes[0], + offsetBytes[1], (byte) len); + + if (resp.getSW1() == (byte) 0x6C) { + + // handle case: card returns 6CXX (wrong number of bytes + // requested) + + resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], + (byte) resp.getSW2()); + } + + if (resp.getSW() == 0x6700) { + + done = true; + } + + try { + bof.write(resp.getData()); + } catch (IOException e) { + log.error("Error executing secure read binary.", e); + throw new CardException("Error reading data from card", e); + } + + bytesRead = bytesRead + resp.getData().length; + + if (bytesRead >= length) { + + done = true; + } + + offset = bytesRead; + } + + return bof.toByteArray(); + } + + private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, + byte offsetLo, byte numBytes) throws CardException { + + byte[] apdu = new byte[] { + + (byte) 0x80, (byte) 0xB0, offsetHi, offsetLo, numBytes }; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + return resp; + + } + + @Override + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + @Override + protected byte[] getAppletID() { + + return APPLET_ID; + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ISVISAElectronCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ISVISAElectronCard.java index 3a76e750..ff677531 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ISVISAElectronCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ISVISAElectronCard.java @@ -1,402 +1,426 @@ -package at.gv.egiz.smcc; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.pin.gui.PINGUI; -import at.gv.egiz.smcc.util.SMCCHelper; - -public class ISVISAElectronCard extends AbstractISCard implements SignatureCard { - - private static final byte[] APPLET_ID = new byte[] { (byte) 0xD2, - (byte) 0x76, (byte) 0x00, (byte) 0x00, (byte) 0x98, (byte) 0x00, - (byte) 0x00, (byte) 0x00 }; - - private static final byte[] PKI_PROFILE = new byte[] { (byte) 0xA0, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x50, - (byte) 0x4B, (byte) 0x43, (byte) 0x53, (byte) 0x2D, (byte) 0x31, - (byte) 0x35 }; - - private static final String CERTIFICATE_IDENTIFIER = "Undirritun"; - - private static final int TRANSFER_BLOCK_SIZE = 0x80; - - private static final PinInfo PIN_SPEC = new PinInfo(6, 6, "[0-9]", - "at/gv/egiz/smcc/ISVISAElectronCard", "sig.pin", (byte) 0x04, - new byte[] {}, PinInfo.UNKNOWN_RETRIES); - - private final Logger log = LoggerFactory - .getLogger(ISVISAElectronCard.class); - - @Override - @Exclusive - public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) - throws SignatureCardException, InterruptedException { - - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - } - - @Override - @Exclusive - public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINGUI pinGUI, String alg) throws SignatureCardException, - InterruptedException, IOException { - - CardChannel channel = getCardChannel(); - - try { - - selectApplet(channel); - selectPKIProfile(channel); - - // VERIFY PIN - verifyPINLoop(channel, PIN_SPEC, pinGUI); - - setMSE(channel); - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get MessageDigest.", e); - throw new SignatureCardException(e); - } - // calculate message digest - byte[] digest = new byte[md.getDigestLength()]; - for (int l; (l = input.read(digest)) != -1;) { - md.update(digest, 0, l); - } - digest = md.digest(); - - return executeSecurityOperation(channel, digest); - - } catch (CardException e) { - e.printStackTrace(); - throw new SignatureCardException("Error creating signature.", e); - } - } - - protected void verifyPINLoop(CardChannel channel, PinInfo spec, - PINGUI provider) throws LockedException, NotActivatedException, - SignatureCardException, InterruptedException, CardException { - - int retries = -1; - do { - retries = verifyPIN(channel, spec, provider, retries); - } while (retries >= -1); - } - - protected int verifyPIN(CardChannel channel, PinInfo pinSpec, - PINGUI provider, int retries) throws SignatureCardException, - LockedException, NotActivatedException, InterruptedException, - CardException { - - VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(new byte[] { (byte) 0x00, - (byte) 0x20, (byte) 0x00, pinSpec.getKID(), (byte) 0x06, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00 }, 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, - 6); - - ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, - retries); - - if (resp.getSW() == 0x9000) { - return -2; - } - if (resp.getSW() >> 4 == 0x63c) { - return 0x0f & resp.getSW(); - } - - switch (resp.getSW()) { - case 0x6300: - // incorrect PIN, number of retries not provided - return -1; - case 0x6400: - // ? - throw new TimeoutException(); - 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); - } - - } - - private byte[] executeSecurityOperation(CardChannel channel, byte[] digest) - throws CardException, SignatureCardException { - - byte[] apduData = new byte[256]; - - // pre-fill with padding - for (int i = 0; i < apduData.length; i++) { - apduData[i] = (byte) 0xFF; - } - apduData[0] = (byte) 0x00; - apduData[1] = (byte) 0x01; - apduData[apduData.length - 1 - OID.length - digest.length] = (byte) 0x00; - - System.arraycopy(digest, 0, apduData, apduData.length - digest.length, - digest.length); - System.arraycopy(OID, 0, apduData, apduData.length - OID.length - - digest.length, OID.length); - - byte[] apduHeader = new byte[] { (byte) 0x00, (byte) 0x2A, (byte) 0x9E, - (byte) 0x9A, (byte) 0x00, (byte) 0x01, (byte) 0x00 }; - - byte[] data = new byte[apduData.length + apduHeader.length]; - System.arraycopy(apduHeader, 0, data, 0, apduHeader.length); - System.arraycopy(apduData, 0, data, apduHeader.length, apduData.length); - - // We need to send 263 bytes, thus we need to split the data into - // several blocks - boolean finished = false; - int bytesSent = 0; - - while (!finished) { - - boolean lastBlock = data.length - bytesSent <= TRANSFER_BLOCK_SIZE; - - int blockSize = lastBlock ? data.length - bytesSent - : TRANSFER_BLOCK_SIZE; - - byte[] block = new byte[blockSize]; - System.arraycopy(data, bytesSent, block, 0, block.length); - - byte p1 = lastBlock ? (byte) 0x80 : (byte) 0x00; - - CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0xAA, p1, - (byte) 0x00, block); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - - bytesSent = bytesSent + block.length; - - if (bytesSent >= data.length) { - - finished = true; - } - } - - // try to get response - finished = false; - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - while (!finished) { - CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0xAB, - (byte) 0x00, (byte) 0x00); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW1() == 0x6C) { - - apdu = new CommandAPDU((byte) 0x80, (byte) 0xAB, (byte) 0x00, - (byte) 0x00, resp.getSW2()); - resp = channel.transmit(apdu); - } - - try { - bos.write(resp.getData()); - } catch (IOException e) { - - throw new SignatureCardException("Error saving card response.", - e); - } - - if (resp.getSW() == 0x6282) { - - // card indicates that all data has been read - finished = true; - } - - } - - return bos.toByteArray(); - } - - private void setMSE(CardChannel channel) throws CardException, - SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x22, - (byte) 0xF1, (byte) 0xB6, new byte[] { (byte) 0x84, - (byte) 0x01, (byte) 0x02 }); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException("Unexpected response to MSE SET: " - + Integer.toHexString(resp.getSW())); - } - - } - - @Override - @Exclusive - public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) - throws SignatureCardException, InterruptedException { - - log.debug("Trying to read certificate.."); - CardChannel channel = getCardChannel(); - - byte[] cert = null; - - try { - - selectApplet(channel); - selectPKIProfile(channel); - - selectDF(channel, new byte[] { (byte) 0x43, (byte) 0x04 }); - selectDF(channel, new byte[] { (byte) 0x45, (byte) 0x41 }); - - byte[] certs = executeReadBinary(channel); - - selectPKIProfile(channel); - selectDF(channel, new byte[] { (byte) 0x44, (byte) 0x04 }); - - byte[] certsMetaInfo = executeReadBinary(channel); - - cert = retrieveSigningCertificate(certs, certsMetaInfo, - CERTIFICATE_IDENTIFIER); - - } catch (CardException e) { - - throw new SignatureCardException("Error reading certificate.", e); - } catch (IOException e) { - - throw new SignatureCardException("Error reading certificate.", e); - } - - return cert; - } - - private void selectPKIProfile(CardChannel channel) throws CardException, - SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x04, (byte) 0x00, PKI_PROFILE); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Error selecting pki profile. Unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - - } - - private void selectDF(CardChannel channel, byte[] id) throws CardException, - SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x00, (byte) 0x00, id); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Error selecting DF. Unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - - } - - private byte[] executeReadBinary(CardChannel channel) throws CardException { - - ByteArrayOutputStream bof = new ByteArrayOutputStream(); - - int bytesRead = 0; - - boolean done = false; - - int offset = 0; - int len = 0; - - while (!done) { - - byte[] offsetBytes = SMCCHelper.toByteArray(offset); - ResponseAPDU resp = readFromCard(channel, offsetBytes[0], - offsetBytes[1], (byte) len); - - if (resp.getSW1() == (byte) 0x6C) { - - // handle case: card returns 6CXX (wrong number of bytes - // requested) - - resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], - (byte) resp.getSW2()); - } - - if (resp.getSW() == 0x6282) { - - done = true; - } - - try { - bof.write(resp.getData()); - } catch (IOException e) { - log.error("Error executing secure read binary.", e); - throw new CardException("Error reading data from card", e); - } - - bytesRead = bytesRead + resp.getData().length; - offset = bytesRead; - - } - - return bof.toByteArray(); - } - - private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, - byte offsetLo, byte numBytes) throws CardException { - - byte[] apdu = new byte[] { - - (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - return resp; - - } - - @Override - protected byte[] getAppletID() { - - return APPLET_ID; - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.SMCCHelper; + +public class ISVISAElectronCard extends AbstractISCard implements SignatureCard { + + private static final byte[] APPLET_ID = new byte[] { (byte) 0xD2, + (byte) 0x76, (byte) 0x00, (byte) 0x00, (byte) 0x98, (byte) 0x00, + (byte) 0x00, (byte) 0x00 }; + + private static final byte[] PKI_PROFILE = new byte[] { (byte) 0xA0, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x50, + (byte) 0x4B, (byte) 0x43, (byte) 0x53, (byte) 0x2D, (byte) 0x31, + (byte) 0x35 }; + + private static final String CERTIFICATE_IDENTIFIER = "Undirritun"; + + private static final int TRANSFER_BLOCK_SIZE = 0x80; + + private static final PinInfo PIN_SPEC = new PinInfo(6, 6, "[0-9]", + "at/gv/egiz/smcc/ISVISAElectronCard", "sig.pin", (byte) 0x04, + new byte[] {}, PinInfo.UNKNOWN_RETRIES); + + private final Logger log = LoggerFactory + .getLogger(ISVISAElectronCard.class); + + @Override + @Exclusive + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + @Override + @Exclusive + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + CardChannel channel = getCardChannel(); + + try { + + selectApplet(channel); + selectPKIProfile(channel); + + // VERIFY PIN + verifyPINLoop(channel, PIN_SPEC, pinGUI); + + setMSE(channel); + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + byte[] digest = new byte[md.getDigestLength()]; + for (int l; (l = input.read(digest)) != -1;) { + md.update(digest, 0, l); + } + digest = md.digest(); + + return executeSecurityOperation(channel, digest); + + } catch (CardException e) { + e.printStackTrace(); + throw new SignatureCardException("Error creating signature.", e); + } + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider) throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + int retries = -1; + do { + retries = verifyPIN(channel, spec, provider, retries); + } while (retries >= -1); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries) throws SignatureCardException, + LockedException, NotActivatedException, InterruptedException, + CardException { + + VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(new byte[] { (byte) 0x00, + (byte) 0x20, (byte) 0x00, pinSpec.getKID(), (byte) 0x06, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00 }, 0, VerifyAPDUSpec.PIN_FORMAT_ASCII, + 6); + + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, + retries); + + if (resp.getSW() == 0x9000) { + return -2; + } + if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } + + switch (resp.getSW()) { + case 0x6300: + // incorrect PIN, number of retries not provided + return -1; + case 0x6400: + // ? + throw new TimeoutException(); + 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); + } + + } + + private byte[] executeSecurityOperation(CardChannel channel, byte[] digest) + throws CardException, SignatureCardException { + + byte[] apduData = new byte[256]; + + // pre-fill with padding + for (int i = 0; i < apduData.length; i++) { + apduData[i] = (byte) 0xFF; + } + apduData[0] = (byte) 0x00; + apduData[1] = (byte) 0x01; + apduData[apduData.length - 1 - OID.length - digest.length] = (byte) 0x00; + + System.arraycopy(digest, 0, apduData, apduData.length - digest.length, + digest.length); + System.arraycopy(OID, 0, apduData, apduData.length - OID.length + - digest.length, OID.length); + + byte[] apduHeader = new byte[] { (byte) 0x00, (byte) 0x2A, (byte) 0x9E, + (byte) 0x9A, (byte) 0x00, (byte) 0x01, (byte) 0x00 }; + + byte[] data = new byte[apduData.length + apduHeader.length]; + System.arraycopy(apduHeader, 0, data, 0, apduHeader.length); + System.arraycopy(apduData, 0, data, apduHeader.length, apduData.length); + + // We need to send 263 bytes, thus we need to split the data into + // several blocks + boolean finished = false; + int bytesSent = 0; + + while (!finished) { + + boolean lastBlock = data.length - bytesSent <= TRANSFER_BLOCK_SIZE; + + int blockSize = lastBlock ? data.length - bytesSent + : TRANSFER_BLOCK_SIZE; + + byte[] block = new byte[blockSize]; + System.arraycopy(data, bytesSent, block, 0, block.length); + + byte p1 = lastBlock ? (byte) 0x80 : (byte) 0x00; + + CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0xAA, p1, + (byte) 0x00, block); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + + bytesSent = bytesSent + block.length; + + if (bytesSent >= data.length) { + + finished = true; + } + } + + // try to get response + finished = false; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + while (!finished) { + CommandAPDU apdu = new CommandAPDU((byte) 0x80, (byte) 0xAB, + (byte) 0x00, (byte) 0x00); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW1() == 0x6C) { + + apdu = new CommandAPDU((byte) 0x80, (byte) 0xAB, (byte) 0x00, + (byte) 0x00, resp.getSW2()); + resp = channel.transmit(apdu); + } + + try { + bos.write(resp.getData()); + } catch (IOException e) { + + throw new SignatureCardException("Error saving card response.", + e); + } + + if (resp.getSW() == 0x6282) { + + // card indicates that all data has been read + finished = true; + } + + } + + return bos.toByteArray(); + } + + private void setMSE(CardChannel channel) throws CardException, + SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x22, + (byte) 0xF1, (byte) 0xB6, new byte[] { (byte) 0x84, + (byte) 0x01, (byte) 0x02 }); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException("Unexpected response to MSE SET: " + + Integer.toHexString(resp.getSW())); + } + + } + + @Override + @Exclusive + public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) + throws SignatureCardException, InterruptedException { + + log.debug("Trying to read certificate.."); + CardChannel channel = getCardChannel(); + + byte[] cert = null; + + try { + + selectApplet(channel); + selectPKIProfile(channel); + + selectDF(channel, new byte[] { (byte) 0x43, (byte) 0x04 }); + selectDF(channel, new byte[] { (byte) 0x45, (byte) 0x41 }); + + byte[] certs = executeReadBinary(channel); + + selectPKIProfile(channel); + selectDF(channel, new byte[] { (byte) 0x44, (byte) 0x04 }); + + byte[] certsMetaInfo = executeReadBinary(channel); + + cert = retrieveSigningCertificate(certs, certsMetaInfo, + CERTIFICATE_IDENTIFIER); + + } catch (CardException e) { + + throw new SignatureCardException("Error reading certificate.", e); + } catch (IOException e) { + + throw new SignatureCardException("Error reading certificate.", e); + } + + return cert; + } + + private void selectPKIProfile(CardChannel channel) throws CardException, + SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x04, (byte) 0x00, PKI_PROFILE); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Error selecting pki profile. Unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + + } + + private void selectDF(CardChannel channel, byte[] id) throws CardException, + SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x00, (byte) 0x00, id); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Error selecting DF. Unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + + } + + private byte[] executeReadBinary(CardChannel channel) throws CardException { + + ByteArrayOutputStream bof = new ByteArrayOutputStream(); + + int bytesRead = 0; + + boolean done = false; + + int offset = 0; + int len = 0; + + while (!done) { + + byte[] offsetBytes = SMCCHelper.toByteArray(offset); + ResponseAPDU resp = readFromCard(channel, offsetBytes[0], + offsetBytes[1], (byte) len); + + if (resp.getSW1() == (byte) 0x6C) { + + // handle case: card returns 6CXX (wrong number of bytes + // requested) + + resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], + (byte) resp.getSW2()); + } + + if (resp.getSW() == 0x6282) { + + done = true; + } + + try { + bof.write(resp.getData()); + } catch (IOException e) { + log.error("Error executing secure read binary.", e); + throw new CardException("Error reading data from card", e); + } + + bytesRead = bytesRead + resp.getData().length; + offset = bytesRead; + + } + + return bof.toByteArray(); + } + + private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, + byte offsetLo, byte numBytes) throws CardException { + + byte[] apdu = new byte[] { + + (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + return resp; + + } + + @Override + protected byte[] getAppletID() { + + return APPLET_ID; + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java index 4010b37a..67d2b001 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/Infobox.java b/smcc/src/main/java/at/gv/egiz/smcc/Infobox.java index 4eff6348..bdebd63a 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/Infobox.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/Infobox.java @@ -1,19 +1,27 @@ /* -* Copyright 2009 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 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/InfoboxContainer.java b/smcc/src/main/java/at/gv/egiz/smcc/InfoboxContainer.java index 1ca98015..3596a28d 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/InfoboxContainer.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/InfoboxContainer.java @@ -1,19 +1,27 @@ /* -* Copyright 2009 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 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/InfoboxException.java b/smcc/src/main/java/at/gv/egiz/smcc/InfoboxException.java index 816c4420..c9340b1f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/InfoboxException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/InfoboxException.java @@ -1,19 +1,27 @@ /* -* Copyright 2009 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 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java b/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java index d84b3228..c6ace5ce 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LockedException.java b/smcc/src/main/java/at/gv/egiz/smcc/LockedException.java index e00322a0..0ccbfb2e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LockedException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LockedException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class LockedException extends SignatureCardException { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java index 0645b9bb..c06c3296 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import java.nio.ByteBuffer; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificate.java b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificate.java index 9a8e5a06..b5f15ecf 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificate.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificate.java @@ -1,79 +1,86 @@ -/* -* Copyright 2009 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 iaik.me.asn1.ASN1; -import iaik.me.security.BigInteger; - -import java.io.IOException; -import java.util.Arrays; - -import at.gv.egiz.smcc.cio.CIOCertificate; - -public class LtEIDCIOCertificate extends CIOCertificate { - - // The Lithuanian eID card stores both certificates in one file. - // For each certificate, EF.CD contains an offset and a length that may be used - // to extract the certificates from the file. - private BigInteger offset; - private byte[] length; - - public LtEIDCIOCertificate(byte[] cio) throws IOException { - - super(cio); - - ASN1 x509Certificate = new ASN1(cio); - - //read CONTEXTSPECIFIC manually - byte[] ctxSpecific = x509Certificate.getElementAt(x509Certificate.getSize()-1).getEncoded(); - if ((ctxSpecific[0] & 0xff) == 0xa1) { - int ll = ((ctxSpecific[1] & 0xf0) == 0x80) - ? (ctxSpecific[1] & 0x0f) + 2 : 2; - ASN1 x509CertificateAttributes = new ASN1(Arrays.copyOfRange(ctxSpecific, ll, ctxSpecific.length)); - - offset = x509CertificateAttributes.getElementAt(0).getElementAt(1).gvBigInteger(); - - // first byte indicates number of relevant bytes in array - byte[] lengthValue = x509CertificateAttributes.getElementAt(0).getElementAt(2).gvByteArray(); - if(lengthValue == null || lengthValue[0] != lengthValue.length-1) { - - throw new IOException("Cannot extract certificate length information. Unexpected format."); - } - - length = new byte[lengthValue[0]]; - System.arraycopy(lengthValue, 1, length, 0, lengthValue[0]); - - } - } - - public BigInteger getOffset() { - return offset; - } - - public void setOffset(BigInteger offset) { - this.offset = offset; - } - - public byte[] getLength() { - return length; - } - - public void setLength(byte[] length) { - this.length = length; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import iaik.me.asn1.ASN1; +import iaik.me.security.BigInteger; + +import java.io.IOException; +import java.util.Arrays; + +import at.gv.egiz.smcc.cio.CIOCertificate; + +public class LtEIDCIOCertificate extends CIOCertificate { + + // The Lithuanian eID card stores both certificates in one file. + // For each certificate, EF.CD contains an offset and a length that may be used + // to extract the certificates from the file. + private BigInteger offset; + private byte[] length; + + public LtEIDCIOCertificate(byte[] cio) throws IOException { + + super(cio); + + ASN1 x509Certificate = new ASN1(cio); + + //read CONTEXTSPECIFIC manually + byte[] ctxSpecific = x509Certificate.getElementAt(x509Certificate.getSize()-1).getEncoded(); + if ((ctxSpecific[0] & 0xff) == 0xa1) { + int ll = ((ctxSpecific[1] & 0xf0) == 0x80) + ? (ctxSpecific[1] & 0x0f) + 2 : 2; + ASN1 x509CertificateAttributes = new ASN1(Arrays.copyOfRange(ctxSpecific, ll, ctxSpecific.length)); + + offset = x509CertificateAttributes.getElementAt(0).getElementAt(1).gvBigInteger(); + + // first byte indicates number of relevant bytes in array + byte[] lengthValue = x509CertificateAttributes.getElementAt(0).getElementAt(2).gvByteArray(); + if(lengthValue == null || lengthValue[0] != lengthValue.length-1) { + + throw new IOException("Cannot extract certificate length information. Unexpected format."); + } + + length = new byte[lengthValue[0]]; + System.arraycopy(lengthValue, 1, length, 0, lengthValue[0]); + + } + } + + public BigInteger getOffset() { + return offset; + } + + public void setOffset(BigInteger offset) { + this.offset = offset; + } + + public byte[] getLength() { + return length; + } + + public void setLength(byte[] length) { + this.length = length; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificateDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificateDirectory.java index efff6cad..ddbb9287 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOCertificateDirectory.java @@ -1,83 +1,90 @@ -/* -* Copyright 2009 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 javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.TLVSequence; - -public class LtEIDCIOCertificateDirectory extends CIOCertificateDirectory { - - public LtEIDCIOCertificateDirectory(byte[] fid) { - super(fid); - } - - protected void addCIOCertificate(byte[] cio) throws IOException { - - LtEIDCIOCertificate cioCert = new LtEIDCIOCertificate(cio); - - log.debug("adding {}", cioCert); - cios.add(cioCert); - } - - @Override - protected byte[] executeSelect(CardChannel channel) - throws CardException { - - byte[] finalPath = null; - - if (fid != null && fid.length > 2 && fid[0] == (byte) 0x3F - && fid[1] == (byte) 0x00) { - - // cut off MF identifier - finalPath = new byte[fid.length - 2]; - System.arraycopy(fid, 2, finalPath, 0, fid.length - 2); - } else { - finalPath = fid; - } - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x08, ISO7816Utils.P2_FCP, finalPath); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new CardException( - "Error selecting File - unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - - byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCP); - byte[] fd = new TLVSequence(fcx).getValue(0x82); - - return fd; - } - - @Override - protected byte[] doReadTransparentFile(CardChannel channel) throws CardException, SignatureCardException { - - return ISO7816Utils.readTransparentFile(channel, 0xEE); - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.IOException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.TLVSequence; + +public class LtEIDCIOCertificateDirectory extends CIOCertificateDirectory { + + public LtEIDCIOCertificateDirectory(byte[] fid) { + super(fid); + } + + protected void addCIOCertificate(byte[] cio) throws IOException { + + LtEIDCIOCertificate cioCert = new LtEIDCIOCertificate(cio); + + log.debug("adding {}", cioCert); + cios.add(cioCert); + } + + @Override + protected byte[] executeSelect(CardChannel channel) + throws CardException { + + byte[] finalPath = null; + + if (fid != null && fid.length > 2 && fid[0] == (byte) 0x3F + && fid[1] == (byte) 0x00) { + + // cut off MF identifier + finalPath = new byte[fid.length - 2]; + System.arraycopy(fid, 2, finalPath, 0, fid.length - 2); + } else { + finalPath = fid; + } + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x08, ISO7816Utils.P2_FCP, finalPath); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new CardException( + "Error selecting File - unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + + byte[] fcx = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCP); + byte[] fd = new TLVSequence(fcx).getValue(0x82); + + return fd; + } + + @Override + protected byte[] doReadTransparentFile(CardChannel channel) throws CardException, SignatureCardException { + + return ISO7816Utils.readTransparentFile(channel, 0xEE); + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKey.java b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKey.java index cab5a491..ee5dc0a5 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKey.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKey.java @@ -1,53 +1,60 @@ -/* -* Copyright 2009 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 iaik.me.asn1.ASN1; -import iaik.me.security.BigInteger; - -import java.io.IOException; - -public class LtEIDCIOKey { - - private byte[] iD; - private BigInteger keyReference; - - public LtEIDCIOKey(byte[] cio) throws IOException { - - ASN1 asn1 = new ASN1(cio); - - iD = asn1.getElementAt(1).getElementAt(0).gvByteArray(); - keyReference = asn1.getElementAt(1).getElementAt(3).gvBigInteger(); - } - - public byte[] getID() { - return iD; - } - - public void setID(byte[] id) { - iD = id; - } - - public BigInteger getKeyReference() { - return keyReference; - } - - public void setKeyReference(BigInteger keyReference) { - this.keyReference = keyReference; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import iaik.me.asn1.ASN1; +import iaik.me.security.BigInteger; + +import java.io.IOException; + +public class LtEIDCIOKey { + + private byte[] iD; + private BigInteger keyReference; + + public LtEIDCIOKey(byte[] cio) throws IOException { + + ASN1 asn1 = new ASN1(cio); + + iD = asn1.getElementAt(1).getElementAt(0).gvByteArray(); + keyReference = asn1.getElementAt(1).getElementAt(3).gvBigInteger(); + } + + public byte[] getID() { + return iD; + } + + public void setID(byte[] id) { + iD = id; + } + + public BigInteger getKeyReference() { + return keyReference; + } + + public void setKeyReference(BigInteger keyReference) { + this.keyReference = keyReference; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKeyDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKeyDirectory.java index dfb8e9eb..5f38cb5c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKeyDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCIOKeyDirectory.java @@ -1,46 +1,53 @@ -/* -* Copyright 2009 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 java.util.ArrayList; -import java.util.List; - -public class LtEIDCIOKeyDirectory extends LtEIDCIOCertificateDirectory { - - protected List keys; - - public LtEIDCIOKeyDirectory(byte[] fid) { - - super(fid); - keys = new ArrayList(); - } - - protected void addCIOCertificate(byte[] cio) throws IOException { - - LtEIDCIOKey cioKey = new LtEIDCIOKey(cio); - - log.debug("adding {}", cioKey); - keys.add(cioKey); - } - - public List getKeys() { - - return this.keys; - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class LtEIDCIOKeyDirectory extends LtEIDCIOCertificateDirectory { + + protected List keys; + + public LtEIDCIOKeyDirectory(byte[] fid) { + + super(fid); + keys = new ArrayList(); + } + + protected void addCIOCertificate(byte[] cio) throws IOException { + + LtEIDCIOKey cioKey = new LtEIDCIOKey(cio); + + log.debug("adding {}", cioKey); + keys.add(cioKey); + } + + public List getKeys() { + + return this.keys; + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCard.java b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCard.java index e37f4018..3226dda9 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDCard.java @@ -1,526 +1,533 @@ -/* - * Copyright 2009 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.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.List; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.gv.egiz.smcc.cio.CIOCertificate; -import at.gv.egiz.smcc.pin.gui.PINGUI; -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.SMCCHelper; - -public class LtEIDCard extends AbstractSignatureCard implements SignatureCard { - - private static final byte[] AID = new byte[] { - - (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x18, - (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x63, - (byte) 0x42, (byte) 0x00 }; - - private static final String CERT_LABEL_IDENTIFIER = "DigitalSignature"; - - private static final PinInfo QS_PIN_SPEC = new PinInfo(8, 8, ".", - "at/gv/egiz/smcc/LtEIDCard", "qs.pin", (byte) 0x81, AID, - PinInfo.UNKNOWN_RETRIES); - - private final Logger log = LoggerFactory.getLogger(LtEIDCard.class); - - @Override - public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINGUI pinGUI, String alg) throws SignatureCardException, - InterruptedException, IOException { - - CardChannel channel = getCardChannel(); - - // select AID - try { - selectApplication(channel); - } catch (CardException e) { - - throw new SignatureCardException("Error selecting AID.", e); - } - - try { - // read certificate info to get key id - byte[] signCertAndKeyID = null; - - LtEIDObjectDirectory efod = new LtEIDObjectDirectory(); - - efod.selectAndRead(channel); - - if (efod.getCDReferences() == null - || efod.getCDReferences().size() < 1) { - - throw new SignatureCardException( - "EF.CD not found - cannot get certificate information."); - } - - LtEIDCIOCertificateDirectory efcd = new LtEIDCIOCertificateDirectory( - efod.getCDReferences().get(0)); - efcd.selectAndRead(channel); - - List cioList = efcd.getCIOs(); - - LtEIDCIOCertificate sigCertInfo = null; - for (CIOCertificate cert : cioList) { - - if (cert instanceof LtEIDCIOCertificate - && cert.getLabel().contains(CERT_LABEL_IDENTIFIER)) { - - sigCertInfo = (LtEIDCIOCertificate) cert; - signCertAndKeyID = sigCertInfo.getiD(); - } - } - - // verify PIN - // Note: PIN verify is required prior to read PrKD - // verifyPIN(channel); - - log.debug("Starting real PIN Verification.."); - // TODO: Test real PIN Verification - verifyPINLoop(channel, QS_PIN_SPEC, pinGUI); - - if (efod.getPrKDReferences() == null - || efod.getPrKDReferences().size() < 1) { - - throw new SignatureCardException( - "EF.PrKD not found - cannot get key information."); - } - - List prKDReferences = efod.getPrKDReferences(); - - LtEIDCIOKeyDirectory efprkd = new LtEIDCIOKeyDirectory(efod - .getPrKDReferences().get(0)); - efprkd.selectAndRead(channel); - - LtEIDCIOKey signKey = null; - - for (LtEIDCIOKey key : efprkd.getKeys()) { - - if (signCertAndKeyID != null - && Arrays.equals(key.getID(), signCertAndKeyID)) { - - signKey = key; - } - } - - if (signKey == null) { - - throw new SignatureCardException( - "Unable to determine required key information."); - } - - execMSESet(channel, signKey.getKeyReference().intValue()); - execPSOHash(channel, input); - - return execPSOComputeDigitalSignature(channel); - - } catch (CardException e) { - - throw new SignatureCardException("Error creating signature.", e); - } - } - - @Override - public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) - throws SignatureCardException, InterruptedException { - - CardChannel channel = getCardChannel(); - - // select AID - try { - selectApplication(channel); - } catch (CardException e) { - - throw new SignatureCardException("Error selecting AID.", e); - } - - LtEIDObjectDirectory efod = new LtEIDObjectDirectory(); - try { - efod.selectAndRead(channel); - - if (efod.getCDReferences() == null - || efod.getCDReferences().size() < 1) { - - throw new SignatureCardException( - "EF.CD not found - cannot get certificate information."); - } - - LtEIDCIOCertificateDirectory efcd = new LtEIDCIOCertificateDirectory( - efod.getCDReferences().get(0)); - efcd.selectAndRead(channel); - - List cioList = efcd.getCIOs(); - - LtEIDCIOCertificate sigCertInfo = null; - for (CIOCertificate cert : cioList) { - - if (cert instanceof LtEIDCIOCertificate - && cert.getLabel().contains(CERT_LABEL_IDENTIFIER)) { - - sigCertInfo = (LtEIDCIOCertificate) cert; - } - } - - if (sigCertInfo == null) { - - throw new SignatureCardException( - "Unable to determine signature certificate."); - } - - if (sigCertInfo.getOffset() == null - || sigCertInfo.getLength() == null - || sigCertInfo.getEfidOrPath() == null) { - - throw new SignatureCardException( - "Unable to retrieve required certificate information."); - } - - // select file with cert - byte[] fci = selectFile(channel, sigCertInfo.getEfidOrPath()); - - byte[] certFile = executeReadBinary(channel, ISO7816Utils - .getLengthFromFCx(fci)); - byte[] sigCert = new byte[toInt(sigCertInfo.getLength())]; - System.arraycopy(certFile, sigCertInfo.getOffset().intValue(), - sigCert, 0, sigCert.length); - - return sigCert; - - } catch (CardException e) { - throw new SignatureCardException( - "Unable to retrieve certificate from card.", e); - } catch (FileNotFoundException e) { - throw new SignatureCardException( - "Unable to retrieve certificate from card.", e); - } catch (IOException e) { - throw new SignatureCardException( - "Unable to retrieve certificate from card.", e); - } - - } - - private void execMSESet(CardChannel channel, int keyReference) - throws CardException { - - // Note: AlgoID (tag 0x80) has to be 0x12 - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x22, - (byte) 0x41, (byte) 0xB6, new byte[] { (byte) 0x80, - (byte) 0x01, (byte) 0x12, (byte) 0x84, (byte) 0x01, - (byte) keyReference }); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new CardException( - "Error executing MSE-SET. Unexpected response: " - + Integer.toHexString(resp.getSW())); - } - } - - private void execPSOHash(CardChannel channel, InputStream input) - throws SignatureCardException { - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get MessageDigest.", e); - throw new SignatureCardException(e); - } - // calculate message digest - ByteArrayOutputStream data = new ByteArrayOutputStream(); - - try { - byte[] digest = new byte[md.getDigestLength()]; - for (int l; (l = input.read(digest)) != -1;) { - md.update(digest, 0, l); - } - digest = md.digest(); - - data.write(new byte[] { (byte) 0x90, (byte) 0x14 }); - data.write(digest); - - } catch (IOException e) { - throw new SignatureCardException("Error computing hash.", e); - } - - try { - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x2A, - (byte) 0x90, (byte) 0xA0, data.toByteArray()); - - ResponseAPDU resp = channel.transmit(apdu); - - log.debug("Answer to PSO-HASH: " - + Integer.toHexString(resp.getSW())); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Error setting hash. Unexpected answer from card: " - + Integer.toHexString(resp.getSW())); - } - - } catch (CardException e) { - throw new SignatureCardException("Error setting hash.", e); - } - } - - private byte[] execPSOComputeDigitalSignature(CardChannel channel) - throws SignatureCardException { - - // Note: Le is mandatory to ensure correct functionality - CommandAPDU apdu = new CommandAPDU(new byte[] { (byte) 0x00, - (byte) 0x2A, (byte) 0x9E, (byte) 0x9A, (byte) 0x00 }); - - try { - ResponseAPDU resp = channel.transmit(apdu); - - log.debug("Answer to PSO-Compute Digital Signature: " - + Integer.toHexString(resp.getSW())); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException( - "Error computing signature. Unexpected answer from card: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - - } catch (CardException e) { - throw new SignatureCardException("Error computing signature.", e); - } - - } - - protected void verifyPINLoop(CardChannel channel, PinInfo spec, - PINGUI provider) throws LockedException, NotActivatedException, - SignatureCardException, InterruptedException, CardException { - - int retries = -1; - do { - retries = verifyPIN(channel, spec, provider, retries); - } while (retries >= -1); - } - - protected int verifyPIN(CardChannel channel, PinInfo pinSpec, - PINGUI provider, int retries) throws SignatureCardException, - LockedException, NotActivatedException, InterruptedException, - CardException { - - VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(new byte[] { (byte) 0x00, - (byte) 0x20, (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, 16); - - ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, - retries); - - if (resp.getSW() == 0x9000) { - return -2; - } - if (resp.getSW() >> 4 == 0x63c) { - return 0x0f & resp.getSW(); - } - - switch (resp.getSW()) { - case 0x6300: - // incorrect PIN, number of retries not provided - return -1; - case 0x6400: - // ? - throw new TimeoutException(); - 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); - } - - } - - @Override - public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) - throws SignatureCardException, InterruptedException { - - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - - } - - private void selectApplication(CardChannel channel) throws CardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x04, (byte) 0x00, AID); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new CardException( - "Error selecting AID - unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - } - - private byte[] selectFile(CardChannel channel, byte[] path) - throws CardException { - - byte[] finalPath = null; - - if (path != null && path.length > 2 && path[0] == (byte) 0x3F - && path[1] == (byte) 0x00) { - - // cut off MF identifier - finalPath = new byte[path.length - 2]; - System.arraycopy(path, 2, finalPath, 0, path.length - 2); - } else { - finalPath = path; - } - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x08, (byte) 0x00, finalPath); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new CardException( - "Error selecting File - unexpected response from card: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - - } - - private byte[] executeReadBinary(CardChannel channel, int bytes2read) - throws CardException { - - ByteArrayOutputStream bof = new ByteArrayOutputStream(); - - // int bytes2read = (lengthHi * 256) + lengthLo; - int bytesRead = 0; - - boolean done = false; - - int offset = 0; - int len = 0; - - while (!done) { - - if (bytes2read - bytesRead > 0xef) { - len = 0xef; - } else { - len = bytes2read - bytesRead; - } - - byte[] offsetBytes = SMCCHelper.toByteArray(offset); - ResponseAPDU resp = readFromCard(channel, offsetBytes[0], - offsetBytes[1], (byte) len); - - if (resp.getSW1() == (byte) 0x6C) { - - // handle case: card returns 6CXX (wrong number of bytes - // requested) - - resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], - (byte) resp.getSW2()); - - // this has to be the final iteration - done = true; - } - - try { - bof.write(resp.getData()); - } catch (IOException e) { - log.error("Error executing secure read binary.", e); - throw new CardException("Error reading data from card", e); - } - - bytesRead = bytesRead + resp.getData().length; - offset = bytesRead; - - if (bytesRead == bytes2read) { - - done = true; - } - } - - return bof.toByteArray(); - } - - private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, - byte offsetLo, byte numBytes) throws CardException { - - byte[] apdu = new byte[] { - - (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - return resp; - - } - - private int toInt(byte[] array) { - - int len = array.length; - int result = 0; - - for (int i = len - 1; i >= 0; i--) { - - result = (int) (result + array[i] * Math.pow(256, len - i - 1)); - } - - return result; - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.List; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.cio.CIOCertificate; +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.SMCCHelper; + +public class LtEIDCard extends AbstractSignatureCard implements SignatureCard { + + private static final byte[] AID = new byte[] { + + (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x18, + (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x63, + (byte) 0x42, (byte) 0x00 }; + + private static final String CERT_LABEL_IDENTIFIER = "DigitalSignature"; + + private static final PinInfo QS_PIN_SPEC = new PinInfo(8, 8, ".", + "at/gv/egiz/smcc/LtEIDCard", "qs.pin", (byte) 0x81, AID, + PinInfo.UNKNOWN_RETRIES); + + private final Logger log = LoggerFactory.getLogger(LtEIDCard.class); + + @Override + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + CardChannel channel = getCardChannel(); + + // select AID + try { + selectApplication(channel); + } catch (CardException e) { + + throw new SignatureCardException("Error selecting AID.", e); + } + + try { + // read certificate info to get key id + byte[] signCertAndKeyID = null; + + LtEIDObjectDirectory efod = new LtEIDObjectDirectory(); + + efod.selectAndRead(channel); + + if (efod.getCDReferences() == null + || efod.getCDReferences().size() < 1) { + + throw new SignatureCardException( + "EF.CD not found - cannot get certificate information."); + } + + LtEIDCIOCertificateDirectory efcd = new LtEIDCIOCertificateDirectory( + efod.getCDReferences().get(0)); + efcd.selectAndRead(channel); + + List cioList = efcd.getCIOs(); + + LtEIDCIOCertificate sigCertInfo = null; + for (CIOCertificate cert : cioList) { + + if (cert instanceof LtEIDCIOCertificate + && cert.getLabel().contains(CERT_LABEL_IDENTIFIER)) { + + sigCertInfo = (LtEIDCIOCertificate) cert; + signCertAndKeyID = sigCertInfo.getiD(); + } + } + + // verify PIN + // Note: PIN verify is required prior to read PrKD + // verifyPIN(channel); + + log.debug("Starting real PIN Verification.."); + // TODO: Test real PIN Verification + verifyPINLoop(channel, QS_PIN_SPEC, pinGUI); + + if (efod.getPrKDReferences() == null + || efod.getPrKDReferences().size() < 1) { + + throw new SignatureCardException( + "EF.PrKD not found - cannot get key information."); + } + + List prKDReferences = efod.getPrKDReferences(); + + LtEIDCIOKeyDirectory efprkd = new LtEIDCIOKeyDirectory(efod + .getPrKDReferences().get(0)); + efprkd.selectAndRead(channel); + + LtEIDCIOKey signKey = null; + + for (LtEIDCIOKey key : efprkd.getKeys()) { + + if (signCertAndKeyID != null + && Arrays.equals(key.getID(), signCertAndKeyID)) { + + signKey = key; + } + } + + if (signKey == null) { + + throw new SignatureCardException( + "Unable to determine required key information."); + } + + execMSESet(channel, signKey.getKeyReference().intValue()); + execPSOHash(channel, input); + + return execPSOComputeDigitalSignature(channel); + + } catch (CardException e) { + + throw new SignatureCardException("Error creating signature.", e); + } + } + + @Override + public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) + throws SignatureCardException, InterruptedException { + + CardChannel channel = getCardChannel(); + + // select AID + try { + selectApplication(channel); + } catch (CardException e) { + + throw new SignatureCardException("Error selecting AID.", e); + } + + LtEIDObjectDirectory efod = new LtEIDObjectDirectory(); + try { + efod.selectAndRead(channel); + + if (efod.getCDReferences() == null + || efod.getCDReferences().size() < 1) { + + throw new SignatureCardException( + "EF.CD not found - cannot get certificate information."); + } + + LtEIDCIOCertificateDirectory efcd = new LtEIDCIOCertificateDirectory( + efod.getCDReferences().get(0)); + efcd.selectAndRead(channel); + + List cioList = efcd.getCIOs(); + + LtEIDCIOCertificate sigCertInfo = null; + for (CIOCertificate cert : cioList) { + + if (cert instanceof LtEIDCIOCertificate + && cert.getLabel().contains(CERT_LABEL_IDENTIFIER)) { + + sigCertInfo = (LtEIDCIOCertificate) cert; + } + } + + if (sigCertInfo == null) { + + throw new SignatureCardException( + "Unable to determine signature certificate."); + } + + if (sigCertInfo.getOffset() == null + || sigCertInfo.getLength() == null + || sigCertInfo.getEfidOrPath() == null) { + + throw new SignatureCardException( + "Unable to retrieve required certificate information."); + } + + // select file with cert + byte[] fci = selectFile(channel, sigCertInfo.getEfidOrPath()); + + byte[] certFile = executeReadBinary(channel, ISO7816Utils + .getLengthFromFCx(fci)); + byte[] sigCert = new byte[toInt(sigCertInfo.getLength())]; + System.arraycopy(certFile, sigCertInfo.getOffset().intValue(), + sigCert, 0, sigCert.length); + + return sigCert; + + } catch (CardException e) { + throw new SignatureCardException( + "Unable to retrieve certificate from card.", e); + } catch (FileNotFoundException e) { + throw new SignatureCardException( + "Unable to retrieve certificate from card.", e); + } catch (IOException e) { + throw new SignatureCardException( + "Unable to retrieve certificate from card.", e); + } + + } + + private void execMSESet(CardChannel channel, int keyReference) + throws CardException { + + // Note: AlgoID (tag 0x80) has to be 0x12 + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x22, + (byte) 0x41, (byte) 0xB6, new byte[] { (byte) 0x80, + (byte) 0x01, (byte) 0x12, (byte) 0x84, (byte) 0x01, + (byte) keyReference }); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new CardException( + "Error executing MSE-SET. Unexpected response: " + + Integer.toHexString(resp.getSW())); + } + } + + private void execPSOHash(CardChannel channel, InputStream input) + throws SignatureCardException { + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + ByteArrayOutputStream data = new ByteArrayOutputStream(); + + try { + byte[] digest = new byte[md.getDigestLength()]; + for (int l; (l = input.read(digest)) != -1;) { + md.update(digest, 0, l); + } + digest = md.digest(); + + data.write(new byte[] { (byte) 0x90, (byte) 0x14 }); + data.write(digest); + + } catch (IOException e) { + throw new SignatureCardException("Error computing hash.", e); + } + + try { + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x2A, + (byte) 0x90, (byte) 0xA0, data.toByteArray()); + + ResponseAPDU resp = channel.transmit(apdu); + + log.debug("Answer to PSO-HASH: " + + Integer.toHexString(resp.getSW())); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Error setting hash. Unexpected answer from card: " + + Integer.toHexString(resp.getSW())); + } + + } catch (CardException e) { + throw new SignatureCardException("Error setting hash.", e); + } + } + + private byte[] execPSOComputeDigitalSignature(CardChannel channel) + throws SignatureCardException { + + // Note: Le is mandatory to ensure correct functionality + CommandAPDU apdu = new CommandAPDU(new byte[] { (byte) 0x00, + (byte) 0x2A, (byte) 0x9E, (byte) 0x9A, (byte) 0x00 }); + + try { + ResponseAPDU resp = channel.transmit(apdu); + + log.debug("Answer to PSO-Compute Digital Signature: " + + Integer.toHexString(resp.getSW())); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException( + "Error computing signature. Unexpected answer from card: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + + } catch (CardException e) { + throw new SignatureCardException("Error computing signature.", e); + } + + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider) throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + int retries = -1; + do { + retries = verifyPIN(channel, spec, provider, retries); + } while (retries >= -1); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI provider, int retries) throws SignatureCardException, + LockedException, NotActivatedException, InterruptedException, + CardException { + + VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(new byte[] { (byte) 0x00, + (byte) 0x20, (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, 16); + + ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, + retries); + + if (resp.getSW() == 0x9000) { + return -2; + } + if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } + + switch (resp.getSW()) { + case 0x6300: + // incorrect PIN, number of retries not provided + return -1; + case 0x6400: + // ? + throw new TimeoutException(); + 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); + } + + } + + @Override + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + + } + + private void selectApplication(CardChannel channel) throws CardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x04, (byte) 0x00, AID); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new CardException( + "Error selecting AID - unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + } + + private byte[] selectFile(CardChannel channel, byte[] path) + throws CardException { + + byte[] finalPath = null; + + if (path != null && path.length > 2 && path[0] == (byte) 0x3F + && path[1] == (byte) 0x00) { + + // cut off MF identifier + finalPath = new byte[path.length - 2]; + System.arraycopy(path, 2, finalPath, 0, path.length - 2); + } else { + finalPath = path; + } + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x08, (byte) 0x00, finalPath); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new CardException( + "Error selecting File - unexpected response from card: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + + } + + private byte[] executeReadBinary(CardChannel channel, int bytes2read) + throws CardException { + + ByteArrayOutputStream bof = new ByteArrayOutputStream(); + + // int bytes2read = (lengthHi * 256) + lengthLo; + int bytesRead = 0; + + boolean done = false; + + int offset = 0; + int len = 0; + + while (!done) { + + if (bytes2read - bytesRead > 0xef) { + len = 0xef; + } else { + len = bytes2read - bytesRead; + } + + byte[] offsetBytes = SMCCHelper.toByteArray(offset); + ResponseAPDU resp = readFromCard(channel, offsetBytes[0], + offsetBytes[1], (byte) len); + + if (resp.getSW1() == (byte) 0x6C) { + + // handle case: card returns 6CXX (wrong number of bytes + // requested) + + resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], + (byte) resp.getSW2()); + + // this has to be the final iteration + done = true; + } + + try { + bof.write(resp.getData()); + } catch (IOException e) { + log.error("Error executing secure read binary.", e); + throw new CardException("Error reading data from card", e); + } + + bytesRead = bytesRead + resp.getData().length; + offset = bytesRead; + + if (bytesRead == bytes2read) { + + done = true; + } + } + + return bof.toByteArray(); + } + + private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, + byte offsetLo, byte numBytes) throws CardException { + + byte[] apdu = new byte[] { + + (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + return resp; + + } + + private int toInt(byte[] array) { + + int len = array.length; + int result = 0; + + for (int i = len - 1; i >= 0; i--) { + + result = (int) (result + array[i] * Math.pow(256, len - i - 1)); + } + + return result; + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDObjectDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDObjectDirectory.java index 624b8f3e..f1eed259 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LtEIDObjectDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LtEIDObjectDirectory.java @@ -1,29 +1,36 @@ -/* -* Copyright 2009 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.cio.ObjectDirectory; - -public class LtEIDObjectDirectory extends ObjectDirectory { - - public LtEIDObjectDirectory() { - - super(new byte[]{(byte)0x50, (byte)0x00, (byte)0x50, (byte)0x31}); - this.setP1((byte)0x08); - } -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import at.gv.egiz.smcc.cio.ObjectDirectory; + +public class LtEIDObjectDirectory extends ObjectDirectory { + + public LtEIDObjectDirectory() { + + super(new byte[]{(byte)0x50, (byte)0x00, (byte)0x50, (byte)0x31}); + this.setP1((byte)0x08); + } +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java index 2eadaf26..4221653f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/NewReferenceDataAPDUSpec.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class NewReferenceDataAPDUSpec extends VerifyAPDUSpec { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/NotActivatedException.java b/smcc/src/main/java/at/gv/egiz/smcc/NotActivatedException.java index 9181fc5f..e259ca0c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/NotActivatedException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/NotActivatedException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; /** 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 4d7d34f5..2299061e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; /** 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 08bc0f18..ef861b23 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; /** diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java index 70b19ff0..1035d806 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; 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 51e4904e..1f3055e4 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; /** diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PinInfo.java b/smcc/src/main/java/at/gv/egiz/smcc/PinInfo.java index d2acf666..107cd18e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PinInfo.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PinInfo.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import java.util.Locale; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java b/smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java index 61a27a6c..57f45aba 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PtEidCard.java @@ -1,30 +1,28 @@ /* - * Copyright 2010 Federal Chancellery Austria and - * Graz University of Technology - * + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * * based on an implementation - * + * * Copyright 2009 Manuel Preliteiro, MULTICERT S.A. * - * Licensed under the EUPL, Version 1.1 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the - * Licence. - * + * Licensed under the EUPL, Version 1.1 or – as soon they will be approved by + * the European Commission – subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * - * http://ec.europa.eu/idabc/eupl + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * - * See the Licence for the specific language governing - * permissions and limitations under the Licence. + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java index 7e71eb7e..bd3de194 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class ResetRetryCounterAPDUSpec extends ChangeReferenceDataAPDUSpec { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SEIdentityCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SEIdentityCard.java index 4538ecca..a56948fc 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SEIdentityCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SEIdentityCard.java @@ -1,319 +1,343 @@ -package at.gv.egiz.smcc; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; - -import at.gv.egiz.smcc.pin.gui.PINGUI; -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.SMCCHelper; - -// TODO: This class uses predefined IDs and path to communicate with the Swedish e-ID card. -// Key and certificate IDs / paths should instead be read out from files defined by ISO 7816-15 - -public class SEIdentityCard extends AbstractSignatureCard implements - SignatureCard { - - private static final byte[] SIGDATA_PREFIX = 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 }; - - private static final PinInfo PIN_SPEC = new PinInfo(6, 8, ".", - "at/gv/egiz/smcc/SEIdentityCard", "pin", (byte) 0x82, null, - PinInfo.UNKNOWN_RETRIES); - - private final Logger log = LoggerFactory.getLogger(SEIdentityCard.class); - - @Override - public byte[] createSignature(InputStream input, KeyboxName keyboxName, - PINGUI pinGUI, String alg) throws SignatureCardException, - InterruptedException, IOException { - - log.debug("Trying to create signature.."); - - CardChannel channel = getCardChannel(); - - // SELECT FILE - try { - selectFile(channel, new byte[] { (byte) 0x50, (byte) 0x15, - (byte) 0x50, (byte) 0x16, (byte) 0x4B, (byte) 0x02 }); - } catch (CardException e) { - - throw new SignatureCardException("Error selecting file.", e); - } - - // VERIFY PIN - try { - verifyPINLoop(channel, PIN_SPEC, pinGUI); - } catch (CardException e1) { - - throw new SignatureCardException("Error verifying PIN.", e1); - } - - // SET MSE - setMSE(channel); - - // CREATE SIGNATURE - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get MessageDigest.", e); - throw new SignatureCardException(e); - } - // calculate message digest - try { - byte[] digest = new byte[md.getDigestLength()]; - for (int l; (l = input.read(digest)) != -1;) { - md.update(digest, 0, l); - } - digest = md.digest(); - - byte[] sigData = new byte[SIGDATA_PREFIX.length + digest.length]; - System.arraycopy(SIGDATA_PREFIX, 0, sigData, 0, SIGDATA_PREFIX.length); - System.arraycopy(digest, 0, sigData, SIGDATA_PREFIX.length, digest.length); - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x2A, - (byte) 0x9E, (byte) 0x9A, sigData); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException("Error creating signature: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - - - } catch (IOException e) { - throw new SignatureCardException("Error creating signature.", e); - } catch (CardException e) { - throw new SignatureCardException("Error creating signature.", e); - } - } - - @Override - public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) - throws SignatureCardException, InterruptedException { - - log.debug("Trying to fetch certificate.."); - - CardChannel channel = getCardChannel(); - - byte[] fci = null; - - try { - fci = selectFile(channel, new byte[] { (byte) 0x50, (byte) 0x15, - (byte) 0x50, (byte) 0x16, (byte) 0x43, (byte) 0x32 }); - } catch (CardException e) { - - throw new SignatureCardException("Error selecting card file.", e); - } - - if (fci == null) { - throw new SignatureCardException( - "Could not retireve FCI for certificate file."); - } - - byte[] cert = null; - - try { - cert = executeReadBinary(channel, ISO7816Utils - .getLengthFromFCx(fci)); - } catch (CardException e) { - throw new SignatureCardException( - "Error reading certificate from card.", e); - } - - return cert; - } - - @Override - public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) - throws SignatureCardException, InterruptedException { - - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - } - - private void setMSE(CardChannel channel) throws SignatureCardException { - - byte[] dst = new byte[] { (byte) 0x80, (byte) 0x01, (byte) 0x02, - (byte) 0x81, (byte) 0x02, (byte) 0x4B, (byte) 0x02 }; - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x22, - (byte) 0x41, (byte) 0xB6, dst); - - try { - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - throw new SignatureCardException("Error setting DST: " - + Integer.toHexString(resp.getSW())); - } - - } catch (CardException e) { - - throw new SignatureCardException("Error setting DST.", e); - } - - } - - private byte[] selectFile(CardChannel channel, byte[] fid) - throws CardException, SignatureCardException { - - CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, - (byte) 0x08, (byte) 0x00, fid); - - ResponseAPDU resp = channel.transmit(apdu); - - if (resp.getSW() != 0x9000) { - - throw new SignatureCardException("Unexpected result from card: " - + Integer.toHexString(resp.getSW())); - } - - return resp.getData(); - } - - private byte[] executeReadBinary(CardChannel channel, int bytes2read) - throws CardException { - - ByteArrayOutputStream bof = new ByteArrayOutputStream(); - - int bytesRead = 0; - - boolean done = false; - - int offset = 0; - int len = 0; - - while (!done) { - - if (bytes2read - bytesRead > 0xef) { - len = 0xef; - } else { - len = bytes2read - bytesRead; - } - - byte[] offsetBytes = SMCCHelper.toByteArray(offset); - ResponseAPDU resp = readFromCard(channel, offsetBytes[0], - offsetBytes[1], (byte) len); - - if (resp.getSW1() == (byte) 0x6C) { - - // handle case: card returns 6CXX (wrong number of bytes - // requested) - - resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], - (byte) resp.getSW2()); - - // this has to be the final iteration - done = true; - } - - try { - bof.write(resp.getData()); - } catch (IOException e) { - log.error("Error executing secure read binary.", e); - throw new CardException("Error reading data from card", e); - } - - bytesRead = bytesRead + resp.getData().length; - offset = bytesRead; - - if (bytesRead == bytes2read) { - - done = true; - } - } - - return bof.toByteArray(); - } - - private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, - byte offsetLo, byte numBytes) throws CardException { - - byte[] apdu = new byte[] { - - (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; - - CommandAPDU command = new CommandAPDU(apdu); - ResponseAPDU resp = channel.transmit(command); - - return resp; - - } - - protected void verifyPINLoop(CardChannel channel, PinInfo spec, - PINGUI provider) throws LockedException, NotActivatedException, - SignatureCardException, InterruptedException, CardException { - - int retries = -1; - do { - retries = verifyPIN(channel, spec, provider, retries); - } while (retries >= -1); - } - - protected int verifyPIN(CardChannel channel, PinInfo pinSpec, - PINGUI 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) 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, provider, pinSpec, - retries); - - if (resp.getSW() == 0x9000) { - return -2; - } - if (resp.getSW() >> 4 == 0x63c) { - return 0x0f & resp.getSW(); - } - - switch (resp.getSW()) { - case 0x6300: - // incorrect PIN, number of retries not provided - return -1; - case 0x6400: - // ? - throw new TimeoutException(); - 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); - } - - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; + +import at.gv.egiz.smcc.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.SMCCHelper; + +// TODO: This class uses predefined IDs and path to communicate with the Swedish e-ID card. +// Key and certificate IDs / paths should instead be read out from files defined by ISO 7816-15 + +public class SEIdentityCard extends AbstractSignatureCard implements + SignatureCard { + + private static final byte[] SIGDATA_PREFIX = 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 }; + + private static final PinInfo PIN_SPEC = new PinInfo(6, 8, ".", + "at/gv/egiz/smcc/SEIdentityCard", "pin", (byte) 0x82, null, + PinInfo.UNKNOWN_RETRIES); + + private final Logger log = LoggerFactory.getLogger(SEIdentityCard.class); + + @Override + public byte[] createSignature(InputStream input, KeyboxName keyboxName, + PINGUI pinGUI, String alg) throws SignatureCardException, + InterruptedException, IOException { + + log.debug("Trying to create signature.."); + + CardChannel channel = getCardChannel(); + + // SELECT FILE + try { + selectFile(channel, new byte[] { (byte) 0x50, (byte) 0x15, + (byte) 0x50, (byte) 0x16, (byte) 0x4B, (byte) 0x02 }); + } catch (CardException e) { + + throw new SignatureCardException("Error selecting file.", e); + } + + // VERIFY PIN + try { + verifyPINLoop(channel, PIN_SPEC, pinGUI); + } catch (CardException e1) { + + throw new SignatureCardException("Error verifying PIN.", e1); + } + + // SET MSE + setMSE(channel); + + // CREATE SIGNATURE + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get MessageDigest.", e); + throw new SignatureCardException(e); + } + // calculate message digest + try { + byte[] digest = new byte[md.getDigestLength()]; + for (int l; (l = input.read(digest)) != -1;) { + md.update(digest, 0, l); + } + digest = md.digest(); + + byte[] sigData = new byte[SIGDATA_PREFIX.length + digest.length]; + System.arraycopy(SIGDATA_PREFIX, 0, sigData, 0, SIGDATA_PREFIX.length); + System.arraycopy(digest, 0, sigData, SIGDATA_PREFIX.length, digest.length); + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x2A, + (byte) 0x9E, (byte) 0x9A, sigData); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException("Error creating signature: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + + + } catch (IOException e) { + throw new SignatureCardException("Error creating signature.", e); + } catch (CardException e) { + throw new SignatureCardException("Error creating signature.", e); + } + } + + @Override + public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) + throws SignatureCardException, InterruptedException { + + log.debug("Trying to fetch certificate.."); + + CardChannel channel = getCardChannel(); + + byte[] fci = null; + + try { + fci = selectFile(channel, new byte[] { (byte) 0x50, (byte) 0x15, + (byte) 0x50, (byte) 0x16, (byte) 0x43, (byte) 0x32 }); + } catch (CardException e) { + + throw new SignatureCardException("Error selecting card file.", e); + } + + if (fci == null) { + throw new SignatureCardException( + "Could not retireve FCI for certificate file."); + } + + byte[] cert = null; + + try { + cert = executeReadBinary(channel, ISO7816Utils + .getLengthFromFCx(fci)); + } catch (CardException e) { + throw new SignatureCardException( + "Error reading certificate from card.", e); + } + + return cert; + } + + @Override + public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId) + throws SignatureCardException, InterruptedException { + + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + private void setMSE(CardChannel channel) throws SignatureCardException { + + byte[] dst = new byte[] { (byte) 0x80, (byte) 0x01, (byte) 0x02, + (byte) 0x81, (byte) 0x02, (byte) 0x4B, (byte) 0x02 }; + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0x22, + (byte) 0x41, (byte) 0xB6, dst); + + try { + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("Error setting DST: " + + Integer.toHexString(resp.getSW())); + } + + } catch (CardException e) { + + throw new SignatureCardException("Error setting DST.", e); + } + + } + + private byte[] selectFile(CardChannel channel, byte[] fid) + throws CardException, SignatureCardException { + + CommandAPDU apdu = new CommandAPDU((byte) 0x00, (byte) 0xA4, + (byte) 0x08, (byte) 0x00, fid); + + ResponseAPDU resp = channel.transmit(apdu); + + if (resp.getSW() != 0x9000) { + + throw new SignatureCardException("Unexpected result from card: " + + Integer.toHexString(resp.getSW())); + } + + return resp.getData(); + } + + private byte[] executeReadBinary(CardChannel channel, int bytes2read) + throws CardException { + + ByteArrayOutputStream bof = new ByteArrayOutputStream(); + + int bytesRead = 0; + + boolean done = false; + + int offset = 0; + int len = 0; + + while (!done) { + + if (bytes2read - bytesRead > 0xef) { + len = 0xef; + } else { + len = bytes2read - bytesRead; + } + + byte[] offsetBytes = SMCCHelper.toByteArray(offset); + ResponseAPDU resp = readFromCard(channel, offsetBytes[0], + offsetBytes[1], (byte) len); + + if (resp.getSW1() == (byte) 0x6C) { + + // handle case: card returns 6CXX (wrong number of bytes + // requested) + + resp = readFromCard(channel, offsetBytes[0], offsetBytes[1], + (byte) resp.getSW2()); + + // this has to be the final iteration + done = true; + } + + try { + bof.write(resp.getData()); + } catch (IOException e) { + log.error("Error executing secure read binary.", e); + throw new CardException("Error reading data from card", e); + } + + bytesRead = bytesRead + resp.getData().length; + offset = bytesRead; + + if (bytesRead == bytes2read) { + + done = true; + } + } + + return bof.toByteArray(); + } + + private ResponseAPDU readFromCard(CardChannel channel, byte offsetHi, + byte offsetLo, byte numBytes) throws CardException { + + byte[] apdu = new byte[] { + + (byte) 0x00, (byte) 0xB0, offsetHi, offsetLo, numBytes }; + + CommandAPDU command = new CommandAPDU(apdu); + ResponseAPDU resp = channel.transmit(command); + + return resp; + + } + + protected void verifyPINLoop(CardChannel channel, PinInfo spec, + PINGUI provider) throws LockedException, NotActivatedException, + SignatureCardException, InterruptedException, CardException { + + int retries = -1; + do { + retries = verifyPIN(channel, spec, provider, retries); + } while (retries >= -1); + } + + protected int verifyPIN(CardChannel channel, PinInfo pinSpec, + PINGUI 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) 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, provider, pinSpec, + retries); + + if (resp.getSW() == 0x9000) { + return -2; + } + if (resp.getSW() >> 4 == 0x63c) { + return 0x0f & resp.getSW(); + } + + switch (resp.getSW()) { + case 0x6300: + // incorrect PIN, number of retries not provided + return -1; + case 0x6400: + // ? + throw new TimeoutException(); + 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); + } + + } + +} 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 a606df50..da016d29 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; 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 cfb96998..a0a7523d 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; import java.io.ByteArrayOutputStream; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java b/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java index bf0af76c..fa6e3c26 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class SecurityStatusNotSatisfiedException extends SignatureCardException { 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 10125e57..ea389d41 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; 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 48b4646a..67b9a6fe 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; 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 257a6696..a1fd92c2 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java @@ -1,20 +1,28 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc; import java.util.ArrayList; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SuisseIDCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SuisseIDCard.java index e625b250..6dcf9184 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SuisseIDCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SuisseIDCard.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/T0CardChannel.java b/smcc/src/main/java/at/gv/egiz/smcc/T0CardChannel.java index 9b0ef657..9ae85d04 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/T0CardChannel.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/T0CardChannel.java @@ -1,86 +1,110 @@ -package at.gv.egiz.smcc; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; - -public class T0CardChannel extends LogCardChannel { - - public T0CardChannel(CardChannel channel) { - - super(channel); - } - - @Override - public ResponseAPDU transmit(CommandAPDU command) throws CardException { - - ResponseAPDU resp = super.transmit(command); - - if (resp.getSW1() == (byte) 0x61) { - - byte[] initData = resp.getData(); - byte[] data = executeGetResponse((byte) resp.getSW2()); - - byte[] result = new byte[initData.length + data.length + 2]; - System.arraycopy(initData, 0, result, 0, initData.length); - System.arraycopy(data, 0, result, initData.length, data.length); - - // add SW "90 00" - result[result.length - 2] = (byte) 0x90; - result[result.length - 1] = (byte) 0x00; - - return new ResponseAPDU(result); - } else { - - return resp; - } - } - - private byte[] executeGetResponse(byte sw2) throws CardException { - - boolean done = false; - ByteArrayOutputStream bof = new ByteArrayOutputStream(); - - while (!done) { - - CommandAPDU command = new CommandAPDU(new byte[] { (byte) 0x00, - (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) sw2 }); - // ResponseAPDU resp = channel.transmit(command); - ResponseAPDU resp = super.transmit(command); - - try { - bof.write(resp.getData()); - } catch (IOException e) { - - throw new CardException( - "Error during fetching gesponse from card.", e); - } - - if (resp.getSW1() == (byte) 0x61) { - - // more data to be read - sw2 = (byte) resp.getSW2(); - continue; - } - - if (resp.getSW() == 0x9000) { - - // all data read - done = true; - } else { - - throw new CardException( - "An error has occured during fetching response from card: " - + Integer.toHexString(resp.getSW())); - } - - } - - return bof.toByteArray(); - } - -} +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.smcc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +public class T0CardChannel extends LogCardChannel { + + public T0CardChannel(CardChannel channel) { + + super(channel); + } + + @Override + public ResponseAPDU transmit(CommandAPDU command) throws CardException { + + ResponseAPDU resp = super.transmit(command); + + if (resp.getSW1() == (byte) 0x61) { + + byte[] initData = resp.getData(); + byte[] data = executeGetResponse((byte) resp.getSW2()); + + byte[] result = new byte[initData.length + data.length + 2]; + System.arraycopy(initData, 0, result, 0, initData.length); + System.arraycopy(data, 0, result, initData.length, data.length); + + // add SW "90 00" + result[result.length - 2] = (byte) 0x90; + result[result.length - 1] = (byte) 0x00; + + return new ResponseAPDU(result); + } else { + + return resp; + } + } + + private byte[] executeGetResponse(byte sw2) throws CardException { + + boolean done = false; + ByteArrayOutputStream bof = new ByteArrayOutputStream(); + + while (!done) { + + CommandAPDU command = new CommandAPDU(new byte[] { (byte) 0x00, + (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) sw2 }); + // ResponseAPDU resp = channel.transmit(command); + ResponseAPDU resp = super.transmit(command); + + try { + bof.write(resp.getData()); + } catch (IOException e) { + + throw new CardException( + "Error during fetching gesponse from card.", e); + } + + if (resp.getSW1() == (byte) 0x61) { + + // more data to be read + sw2 = (byte) resp.getSW2(); + continue; + } + + if (resp.getSW() == 0x9000) { + + // all data read + done = true; + } else { + + throw new CardException( + "An error has occured during fetching response from card: " + + Integer.toHexString(resp.getSW())); + } + + } + + return bof.toByteArray(); + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java b/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java index d14a4c15..ea51a5f9 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class TimeoutException extends SignatureCardException { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java index 23c1f0fd..9c6414e0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/VerifyAPDUSpec.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc; public class VerifyAPDUSpec { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIO.java b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIO.java index a7ffb9c7..792b1727 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIO.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIO.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.cio; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificate.java b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificate.java index 1a9090ad..8e2129f0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificate.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificate.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.cio; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificateDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificateDirectory.java index 67e183fd..088e7f9f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificateDirectory.java @@ -1,20 +1,28 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.cio; import at.gv.egiz.smcc.SignatureCardException; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIODirectoryFile.java b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIODirectoryFile.java index 2d2fd03d..c267fe79 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/cio/CIODirectoryFile.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIODirectoryFile.java @@ -1,20 +1,28 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.cio; import at.gv.egiz.smcc.SignatureCardException; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/cio/LIEZertifikatCertificateDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/cio/LIEZertifikatCertificateDirectory.java index 40d5c7b9..209f2af2 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/cio/LIEZertifikatCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/LIEZertifikatCertificateDirectory.java @@ -1,19 +1,27 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.cio; import at.gv.egiz.smcc.cio.CIOCertificateDirectory; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/cio/ObjectDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/cio/ObjectDirectory.java index d1bd6144..f42d55b6 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/cio/ObjectDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/ObjectDirectory.java @@ -1,20 +1,28 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.cio; import at.gv.egiz.smcc.SignatureCardException; 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 136ca283..89027bf0 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 @@ -1,20 +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 - * + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.conf; /** diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java index 2e0de76b..05386690 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java index 7933214b..5a29e6ce 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java index 92b9f14d..06d5df60 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java index e8641797..ef954dd8 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.pin.gui; import at.gv.egiz.smcc.CancelledException; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java index 392f2fc2..c3d950a7 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java @@ -1,19 +1,27 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.reader; import javax.smartcardio.CardChannel; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java index cc25a63c..fef60e2b 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java @@ -1,19 +1,27 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.reader; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java index 3f5343a6..d41da179 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java @@ -1,19 +1,27 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.reader; import java.io.ByteArrayOutputStream; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java index e8f657f7..8b49f1a9 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java @@ -1,20 +1,28 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.reader; import at.gv.egiz.smcc.conf.SMCCConfiguration; 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 index 44045d3c..9145c987 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java @@ -1,19 +1,27 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.util; import java.io.ByteArrayOutputStream; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java b/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java index fd58964d..e4259346 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.util; import java.math.BigInteger; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java b/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java index 14ee7549..08a1ea39 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java @@ -1,19 +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. -*/ + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + package at.gv.egiz.smcc.util; import java.security.NoSuchAlgorithmException; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/TLV.java b/smcc/src/main/java/at/gv/egiz/smcc/util/TLV.java index 1e158e75..f469677f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/TLV.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/TLV.java @@ -1,24 +1,29 @@ -package at.gv.egiz.smcc.util; - - - /* - * Copyright 2009 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 + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + +package at.gv.egiz.smcc.util; + public class TLV { private byte[] bytes; diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/TLVSequence.java b/smcc/src/main/java/at/gv/egiz/smcc/util/TLVSequence.java index 00639545..e6e4abb1 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/TLVSequence.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/TLVSequence.java @@ -1,19 +1,27 @@ /* - * Copyright 2009 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.util; import java.util.Iterator; 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 index 2da17354..950dc1f6 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java @@ -1,19 +1,27 @@ /* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the 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 + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the Licence 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. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. */ + + package at.gv.egiz.smcc.util; import java.io.IOException; -- cgit v1.2.3