From 5c002cd206ae4a024e445a16747d80fe8a5535e2 Mon Sep 17 00:00:00 2001 From: tzefferer Date: Mon, 8 Nov 2010 14:07:45 +0000 Subject: git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@822 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- smcc/src/main/java/at/gv/egiz/smcc/DNIeCard.java | 277 ++++++++++++++++++--- .../at/gv/egiz/smcc/DNIeCardSecureChannel.java | 88 ++++--- .../java/at/gv/egiz/smcc/SignatureCardFactory.java | 4 +- 3 files changed, 306 insertions(+), 63 deletions(-) diff --git a/smcc/src/main/java/at/gv/egiz/smcc/DNIeCard.java b/smcc/src/main/java/at/gv/egiz/smcc/DNIeCard.java index 768ac959..ccb463a5 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/DNIeCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/DNIeCard.java @@ -1,5 +1,25 @@ +/* +* 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 java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; @@ -25,6 +45,9 @@ public class DNIeCard extends AbstractSignatureCard implements SignatureCard { (byte) 0x72, (byte) 0x2E, (byte) 0x46, (byte) 0x69, (byte) 0x6C, (byte) 0x65 }; + private final String SIG_KEY_NAME = "KprivFirmaDigital"; + private final String SIG_CERT_NAME = "CertFirmaDigital"; + protected PinInfo pinInfo = new PinInfo(8, 16, "[0-9A-Za-z_<>!()?%\\-=&+\\.]", "at/gv/egiz/smcc/DNIeCard", "sig.pin", (byte) 0x00, new byte[] {}, PinInfo.UNKNOWN_RETRIES); @@ -52,9 +75,13 @@ public class DNIeCard extends AbstractSignatureCard implements SignatureCard { } try { + + byte[] prKdf = executeReadPrKDF(channel); + byte[] keyId = getKeyIdFromASN1File(prKdf); + verifyPINLoop(channel, pinInfo, pinGUI); - secureChannel.executeSecureManageSecurityEnvironment(channel); + secureChannel.executeSecureManageSecurityEnvironment(channel, keyId); MessageDigest md; try { @@ -88,14 +115,30 @@ public class DNIeCard extends AbstractSignatureCard implements SignatureCard { CardChannel channel = getCardChannel(); - if (!secureChannel.isEstablished()) + if (!secureChannel.isEstablished()) { try { secureChannel.establish(channel); } catch (CardException e) { log.debug("Error establishing secure channel to card.", e); } + } + byte[] certId = null; + + try { + // read CDF file + byte[] cdf = executeReadCDF(channel); + + // extract certificate id from ASN1 data structure + certId = getCertIdFromASN1File(cdf); + + } catch (CardException e1) { + + log.error("Error reading ASN.1 data!"); + e1.printStackTrace(); + } + log.debug("Try to read certificate.."); try { @@ -112,11 +155,11 @@ public class DNIeCard extends AbstractSignatureCard implements SignatureCard { secureChannel.executeSecureSelect(channel, apdu); - // select 7005 + // select cert id byte[] apdu2 = new byte[] { (byte) 0x00, (byte) 0xA4, (byte) 0x00, (byte) 0x00, (byte) 0x02, - (byte) 0x70, (byte) 0x05 }; + certId[certId.length-2], certId[certId.length-1] }; byte[] fci = secureChannel.executeSecureSelect(channel, apdu2); @@ -126,14 +169,11 @@ public class DNIeCard extends AbstractSignatureCard implements SignatureCard { byte[] data = secureChannel.executeSecureReadBinary(channel, sizeHi, sizeLo); - int uncompressedDataLen = getUncompressedDataLength(data); - byte[] compressedWithoutHeader = new byte[data.length - 8]; System.arraycopy(data, 8, compressedWithoutHeader, 0, compressedWithoutHeader.length); - result = decompressData(compressedWithoutHeader, - uncompressedDataLen); + result = decompressData(compressedWithoutHeader); } catch (CardException e) { @@ -218,37 +258,218 @@ public class DNIeCard extends AbstractSignatureCard implements SignatureCard { secureChannel.executeSecureSelect(channel, apdu); } - private int getUncompressedDataLength(byte[] data) { - - byte len0 = data[0]; - byte len1 = data[1]; - byte len2 = data[2]; - byte len3 = data[3]; + private byte[] executeReadCDF(CardChannel channel) throws CardException { + + return executeReadFile(channel, new byte[]{(byte)0x50,(byte)0x15,(byte)0x60,(byte)0x04}); + } + + private byte[] executeReadPrKDF(CardChannel channel) throws CardException { + + return executeReadFile(channel, new byte[]{(byte)0x50,(byte)0x15,(byte)0x60,(byte)0x01}); + } + + private byte[] getKeyIdFromASN1File(byte[] file) throws CardException { + + // split file in two records + int record1Length = getRecordLength(file, 1); + + byte[] record1 = new byte[record1Length]; + byte[] record2 = new byte[file.length - record1.length]; + + System.arraycopy(file, 0, record1, 0, record1.length); + System.arraycopy(file, record1.length, record2, 0, record2.length); + + byte[] keyId = new byte[2]; + + try { + ASN1 asn1_1 = new ASN1(record1); + ASN1 asn1_2 = new ASN1(record2); + + if(asn1_1.getElementAt(0).getElementAt(0).gvString().equalsIgnoreCase(SIG_KEY_NAME)) { + + byte[] data = asn1_1.getElementAt(2).gvByteArray(); + + keyId[0] = data[9]; + keyId[1] = data[10]; + } - int a = len0; - int b = len1 * 256; - int c = len2 * 256 * 256; - int d = len3 * 256 * 256 * 256; + else if(asn1_2.getElementAt(0).getElementAt(0).gvString().equalsIgnoreCase(SIG_KEY_NAME)) { + + byte[] data = asn1_2.getElementAt(2).gvByteArray(); + + keyId[0] = data[9]; + keyId[1] = data[10]; + } + + } catch (Exception e) { - return a + b + c + d; + throw new CardException("Error getting ASN1 data.", e); + } + + return keyId; } - - private byte[] decompressData(byte[] input, int len) throws CardException { + + private byte[] getCertIdFromASN1File(byte[] file) throws CardException { + + int record1Length = getRecordLength(file, 1); + + // split file in two records + byte[] record1 = new byte[record1Length]; + byte[] record2 = new byte[file.length - record1.length]; + + System.arraycopy(file, 0, record1, 0, record1.length); + System.arraycopy(file, record1.length, record2, 0, record2.length); + + byte[] certId = null; + + try { + ASN1 asn1_1 = new ASN1(record1); + ASN1 asn1_2 = new ASN1(record2); + + if(asn1_1.getElementAt(0).getElementAt(0).gvString().equalsIgnoreCase(SIG_CERT_NAME)) { + + certId = retrieveCertId(asn1_1.getElementAt(2).gvByteArray()); + } + + if(asn1_2.getElementAt(0).getElementAt(0).gvString().equalsIgnoreCase(SIG_CERT_NAME)) { + + certId = retrieveCertId(asn1_2.getElementAt(2).gvByteArray()); + } + + } catch (Exception e) { + + throw new CardException("Error getting ASN1 data.", e); + } + + return certId; + } + + private byte[] retrieveCertId(byte[] data) throws CardException { + + ASN1 contextSpecific = getASN1WithinContextSpecific(data); + try { + return contextSpecific.getElementAt(0).getElementAt(0).gvByteArray(); + } catch (IOException e) { + throw new CardException("Error retrieving certificate ID from ASN1 data.", e); + } + } + + private ASN1 getASN1WithinContextSpecific(byte[] data) throws CardException { + + byte first = data[0]; + byte lengthOfLength = 0; + + if(first < 0) { + + lengthOfLength = (byte)(first & (byte)0x7F); + lengthOfLength = (byte)(lengthOfLength +1); + } else { + + lengthOfLength = 1; + } + + byte[] asn1data = new byte[data.length - lengthOfLength]; + System.arraycopy(data, lengthOfLength, asn1data, 0, asn1data.length); + + try { + return new ASN1(asn1data); + } catch (IOException e) { + throw new CardException("Error getting ASN1 structure.", e); + } + } + + private int getRecordLength(byte[] data, int startOfLength) { + + byte lengthStartByte = data[startOfLength]; + + if(lengthStartByte < 0) { + // we have more than one length byte + byte lengthOfLength = (byte)(lengthStartByte & (byte)0x7F); + + byte[] lengthValues = new byte[lengthOfLength]; + System.arraycopy(data, startOfLength+1, lengthValues, 0, lengthOfLength); + + int result = 0; + + for(int i=0; i