diff options
author | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2010-12-23 19:24:55 +0000 |
---|---|---|
committer | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2010-12-23 19:24:55 +0000 |
commit | ab05cb01a6c76fb280120246a5dd20ebc552aaa7 (patch) | |
tree | 862285031cc8aea277bfe715e1f60b193858ab3f | |
parent | 4d5495bf16ce4135abb7317503cf5fd8d0a44cde (diff) | |
download | mocca-ab05cb01a6c76fb280120246a5dd20ebc552aaa7.tar.gz mocca-ab05cb01a6c76fb280120246a5dd20ebc552aaa7.tar.bz2 mocca-ab05cb01a6c76fb280120246a5dd20ebc552aaa7.zip |
refactor ObjectDirectory
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@855 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
14 files changed, 670 insertions, 454 deletions
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 a9886e80..122c4e7d 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificateDirectory.java @@ -17,6 +17,7 @@ package at.gv.egiz.smcc; +import at.gv.egiz.smcc.cio.CIOCertificate; import at.gv.egiz.smcc.util.ISO7816Utils; import at.gv.egiz.smcc.util.TLVSequence; import iaik.me.asn1.ASN1; @@ -32,13 +33,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * + * TODO To be replaced by at.gv.egiz.smcc.cio.CIOCertificateDirectory + * * @author clemens */ public class CIOCertificateDirectory { - protected static final boolean RETRIEVE_AUTH_ID_FROM_ASN1 = Boolean.TRUE; - protected static final Logger log = LoggerFactory.getLogger(CIOCertificateDirectory.class); protected byte[] fid; protected List<CIOCertificate> cios; @@ -127,29 +127,8 @@ public class CIOCertificateDirectory { } protected void addCIOCertificate(byte[] cio) throws IOException { - - ASN1 x509Certificate = new ASN1(cio); - - CIOCertificate cioCert = new CIOCertificate(); - cioCert.setLabel(x509Certificate.getElementAt(0).getElementAt(0).gvString()); - if(retrieveAuthIdFromASN1()) { - cioCert.setAuthId(x509Certificate.getElementAt(0).getElementAt(2).gvByteArray()); - } - cioCert.setiD(x509Certificate.getElementAt(1).getElementAt(0).gvByteArray()); - //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)); - - cioCert.setEfidOrPath(x509CertificateAttributes.getElementAt(0).getElementAt(0).gvByteArray()); - - } else { - log.warn("expected CONTEXTSPECIFIC, got 0x{}", - Integer.toHexString(ctxSpecific[0])); - } + CIOCertificate cioCert = new CIOCertificate(cio); log.debug("adding {}", cioCert); cios.add(cioCert); @@ -160,8 +139,4 @@ public class CIOCertificateDirectory { return cios; } - protected boolean retrieveAuthIdFromASN1() { - - return RETRIEVE_AUTH_ID_FROM_ASN1; - } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/EFObjectDirectory.java b/smcc/src/main/java/at/gv/egiz/smcc/EFObjectDirectory.java deleted file mode 100644 index dfa70d91..00000000 --- a/smcc/src/main/java/at/gv/egiz/smcc/EFObjectDirectory.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package at.gv.egiz.smcc; - -import at.gv.egiz.smcc.util.ISO7816Utils; -import at.gv.egiz.smcc.util.TLV; -import at.gv.egiz.smcc.util.TLVSequence; - -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; - -/** - * - * @author clemens - */ -public class EFObjectDirectory { - - protected static final Logger log = LoggerFactory - .getLogger(EFObjectDirectory.class); - - protected byte[] fid; - private byte[] ef_prkd; - private byte[] ef_pukd; - private byte[] ef_aod; - - private List<byte[]> ef_cd_list = new ArrayList<byte[]>();; - - private Integer padding; - - public EFObjectDirectory() { - fid = new byte[] { (byte) 0x50, (byte) 0x31 }; - } - - public EFObjectDirectory(byte[] fid) { - this.fid = fid; - } - - public EFObjectDirectory(int padding) { - - fid = new byte[] { (byte) 0x50, (byte) 0x31 }; - this.padding = padding; - - } - - /** - * assume DF.CIA selected EF.OD selected afterwards - * - * @param channel - * @throws CardException - * @throws SignatureCardException - */ - public void selectAndRead(CardChannel channel) throws CardException, - SignatureCardException { - - executeSelect(channel); - - byte[] efod = ISO7816Utils.readTransparentFile(channel, -1); - - for (TLV cio : new TLVSequence(efod)) { - int tag = cio.getTag(); - - if (padding != null && tag == padding) { - // reached padding - quit record extraction - break; - } - - byte[] seq = cio.getValue(); - - if ((tag & 0xf0) == 0xa0 && seq.length >= 4) { - - byte[] path = Arrays.copyOfRange(seq, 4, 4 + seq[3]); - - switch (cio.getTag() & 0x0f) { - case 0: - setEf_prkd(path); - break; - case 1: - setEf_pukd(path); - break; - case 4: - addCdToEf_cd_list(path); - break; - case 8: - setEf_aod(path); - break; - default: - log.warn("CIOChoice 0x{} not supported: ", - (cio.getTag() & 0x0f)); - } - } else { - log.trace("ignoring invalid CIO reference entry: {}", seq); - } - } - } - - protected void executeSelect(CardChannel channel) - throws SignatureCardException, CardException { - - CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x02, 0x00, fid, 256); - ResponseAPDU resp = channel.transmit(cmd); - - if (resp.getSW() != 0x9000) { - throw new SignatureCardException("SELECT EF.OD failed: SW=0x" - + Integer.toHexString(resp.getSW())); - } - - } - - /** - * @return the ef_prkd - */ - public byte[] getEf_prkd() { - return ef_prkd; - } - - /** - * @param ef_prkd - * the ef_prkd to set - */ - public void setEf_prkd(byte[] ef_prkd) { - this.ef_prkd = ef_prkd; - } - - /** - * @return the ef_pukd - */ - public byte[] getEf_pukd() { - return ef_pukd; - } - - /** - * @param ef_pukd - * the ef_pukd to set - */ - public void setEf_pukd(byte[] ef_pukd) { - this.ef_pukd = ef_pukd; - } - - /** - * @return the ef_aod - */ - public byte[] getEf_aod() { - return ef_aod; - } - - public List<byte[]> getEf_cd_list() { - return ef_cd_list; - } - - public void setEf_cd_list(List<byte[]> ef_cd_list) { - this.ef_cd_list = ef_cd_list; - } - - public void addCdToEf_cd_list(byte[] ef_cd) { - - this.ef_cd_list.add(ef_cd); - } - - /** - * @param ef_aod - * the ef_aod to set - */ - public void setEf_aod(byte[] ef_aod) { - this.ef_aod = ef_aod; - } - -} 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 a0d426c7..4f1c7610 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ESDNIeCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ESDNIeCard.java @@ -1,5 +1,7 @@ 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;
@@ -66,11 +68,11 @@ public class ESDNIeCard extends AbstractSignatureCard implements SignatureCard { // Select DF.CIA
executeSelectDFCIA(channel);
- EFObjectDirectory efOd = new EFObjectDirectory();
+ ObjectDirectory efOd = new ObjectDirectory();
efOd.selectAndRead(channel);
DNIeCIOCertificateDirectory efPrkd = new DNIeCIOCertificateDirectory(
- efOd.getEf_prkd());
+ efOd.getPrKDReferences().get(0));
efPrkd.selectAndRead(channel);
byte[] efKey = null;
@@ -155,11 +157,11 @@ public class ESDNIeCard extends AbstractSignatureCard implements SignatureCard { byte[] efQcert = null;
- EFObjectDirectory efOd = new EFObjectDirectory();
+ ObjectDirectory efOd = new ObjectDirectory();
efOd.selectAndRead(channel);
DNIeCIOCertificateDirectory efCd = new DNIeCIOCertificateDirectory(
- efOd.getEf_cd_list().get(0));
+ efOd.getCDReferences().get(0));
try {
efCd.selectAndRead(channel);
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 0de2b3c1..537154c7 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOCertificateDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCIOCertificateDirectory.java @@ -27,8 +27,6 @@ import at.gv.egiz.smcc.util.TLVSequence; public class FINEIDCIOCertificateDirectory extends CIOCertificateDirectory {
- protected static final boolean RETRIEVE_AUTH_ID_FROM_ASN1 = Boolean.FALSE;
-
public FINEIDCIOCertificateDirectory(byte[] fid) {
super(fid);
@@ -46,11 +44,4 @@ public class FINEIDCIOCertificateDirectory extends CIOCertificateDirectory { return fd;
}
-
- @Override
- 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 32272af8..92371d8e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDCard.java @@ -17,6 +17,7 @@ package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.cio.CIOCertificate;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
@@ -63,7 +64,7 @@ public class FINEIDCard extends AbstractSignatureCard implements SignatureCard { // read PRKD to find correct key
FINEIDCIOKeyDirectory ef_prkd = new FINEIDCIOKeyDirectory(ef_od
- .getEf_prkd());
+ .getPrKDReferences().get(0));
ef_prkd.selectAndRead(channel);
byte[] efKey = null;
@@ -93,7 +94,7 @@ public class FINEIDCard extends AbstractSignatureCard implements SignatureCard { }
// read AOD to find the associated PIN (authId must match)
- FINEIDAODirectory ef_aod = new FINEIDAODirectory(ef_od.getEf_aod());
+ FINEIDAODirectory ef_aod = new FINEIDAODirectory(ef_od.getAODReferences().get(0));
ef_aod.selectAndRead(channel);
byte[] pinPath = null;
@@ -181,10 +182,10 @@ public class FINEIDCard extends AbstractSignatureCard implements SignatureCard { byte[] certPath = null;
- for (int i = 0; i < ef_od.getEf_cd_list().size(); i++) {
+ for (int i = 0; i < ef_od.getCDReferences().size(); i++) {
FINEIDCIOCertificateDirectory ef_cd = new FINEIDCIOCertificateDirectory(
- ef_od.getEf_cd_list().get(i));
+ ef_od.getCDReferences().get(i));
try {
ef_cd.selectAndRead(channel);
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 2690d694..ce44a892 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/FINEIDEFObjectDirectory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/FINEIDEFObjectDirectory.java @@ -17,28 +17,12 @@ 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.cio.ObjectDirectory;
-public class FINEIDEFObjectDirectory extends EFObjectDirectory {
+public class FINEIDEFObjectDirectory extends ObjectDirectory {
public FINEIDEFObjectDirectory(int padding) {
- super(padding);
+ super(padding, 0x00);
}
-
- @Override
- protected void executeSelect(CardChannel channel)
- throws SignatureCardException, CardException {
-
- CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x00, 0x00, fid, 256);
- ResponseAPDU resp = channel.transmit(cmd);
-
- if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("SELECT EF.OD failed: SW=0x"
- + Integer.toHexString(resp.getSW()));
- }
- }
}
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 434f35a1..d84b3228 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java @@ -18,6 +18,8 @@ package at.gv.egiz.smcc; +import at.gv.egiz.smcc.cio.CIOCertificate; +import at.gv.egiz.smcc.cio.ObjectDirectory; import at.gv.egiz.smcc.pin.gui.PINGUI; import at.gv.egiz.smcc.util.ISO7816Utils; @@ -26,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.List; import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; @@ -36,7 +39,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.smcc.util.SMCCHelper; -import iaik.me.asn1.ASN1; import java.util.Arrays; import javax.smartcardio.Card; import javax.smartcardio.CardTerminal; @@ -58,13 +60,6 @@ public class LIEZertifikatCard extends AbstractSignatureCard implements Signatur public static final byte[] EF_CD = new byte[] { (byte) 0x44, (byte) 0x04}; - public static final byte[] CRT_AT = new byte[] { - // key 0x81??? (EF.PrKD defines 0x84 and 0x85) - (byte) 0x84, (byte) 0x01, (byte) 0x81, - //RSA Authentication - (byte) 0x89, (byte) 0x02, (byte) 0x23, (byte) 0x13 - }; - public static final byte[] PKCS1_PADDING = new byte[] { (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x05, (byte) 0x2b, (byte) 0x0e, (byte) 0x03, (byte) 0x02, @@ -80,6 +75,9 @@ public class LIEZertifikatCard extends AbstractSignatureCard implements Signatur "at/gv/egiz/smcc/LIEZertifikatCard", "pin", KID, AID_SIG, 3); protected String name = "LIEZertifikat"; + ObjectDirectory ef_od = new ObjectDirectory(); + CIOCertificate cioQCert; + @Override public void init(Card card, CardTerminal cardTerminal) { super.init(card, cardTerminal); @@ -106,41 +104,10 @@ public class LIEZertifikatCard extends AbstractSignatureCard implements Signatur // SELECT DF.CIA execSELECT_AID(channel, AID_SIG); - EFObjectDirectory ef_od = new EFObjectDirectory(); - ef_od.selectAndRead(channel); - - CIOCertificateDirectory ef_cd = new CIOCertificateDirectory(ef_od.getEf_cd_list().get(0)); - ef_cd.selectAndRead(channel); - - byte[] ef_qcert = null; - for (CIOCertificate cioCertificate : ef_cd.getCIOs()) { - String label = cioCertificate.getLabel(); - //"Name (qualified signature" - if (label != null && label.toLowerCase() - .contains("qualified signature")) { - ef_qcert = cioCertificate.getEfidOrPath(); - log.debug("found certificate: {} (fid={})", label, ef_qcert); - } - } - - if (ef_qcert == null) { - for (CIOCertificate cioCertificate : ef_cd.getCIOs()) { - String label = cioCertificate.getLabel(); - //"TEST LLV APO 2s Liechtenstein Post Qualified CA ID" - if (label != null && label.toLowerCase() - .contains("liechtenstein post qualified ca id")) { - ef_qcert = cioCertificate.getEfidOrPath(); - log.debug("found certificate: {} (fid={})", label, ef_qcert); - } - } - } - - if (ef_qcert == null) { - throw new NotActivatedException(); - } + ensureCIOQCertificate(channel); // SELECT CERT, assume efid - execSELECT_EF(channel, ef_qcert); + execSELECT_EF(channel, cioQCert.getEfidOrPath()); // READ BINARY byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30); @@ -217,7 +184,7 @@ public class LIEZertifikatCard extends AbstractSignatureCard implements Signatur // VERIFY verifyPINLoop(channel, pinInfo, provider); // MANAGE SECURITY ENVIRONMENT : SET SE - execMSE_SET(channel, CRT_AT); + execMSE_SET(channel, getCRT_AT(channel)); // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE return execINTERNAL_AUTHENTICATE(channel, data.toByteArray()); @@ -301,83 +268,6 @@ public class LIEZertifikatCard extends AbstractSignatureCard implements Signatur } - protected byte[] execSELECT_MF(CardChannel channel) - throws SignatureCardException, CardException { - - // don't add Ne, causes 67:00 - ResponseAPDU resp = channel.transmit( - new CommandAPDU(0x00, 0xA4, 0x00, 0x0c, MF)); - - if (resp.getSW() == 0x6A82) { - String msg = "File or application not found FID=" - + SMCCHelper.toString(MF) + " SW=" - + Integer.toHexString(resp.getSW()) + "."; - log.info(msg); - throw new FileNotFoundException(msg); - } else if (resp.getSW() != 0x9000) { - String msg = "Failed to select FID=" - + SMCCHelper.toString(MF) + " SW=" - + Integer.toHexString(resp.getSW()) + "."; - log.error(msg); - throw new SignatureCardException(msg); - } else { - return resp.getBytes(); - } - - } - - - /** - * - * @return null if not found - */ - protected byte[] getFID_QCERT(CardChannel channel) - throws SignatureCardException, CardException { - - execSELECT_EF(channel, EF_CD); - byte[] cio_cd = ISO7816Utils.readTransparentFile(channel, -1); - - //assume first 'record' is qcert - int length = 0; - if ((cio_cd[1] & 0xf0) == 0x80) { - int ll = cio_cd[1] & 0x7f; - for (int i= 0; i < ll; i++) { - length = (length << 8) + (cio_cd[2+i] & 0xff); - } - length += ll + 2; - } else { - length = (cio_cd[1] & 0xff) + 2; - } - - log.trace("reading CIO.CD[0-{}]", length-1); - - try { - ASN1 certificateObj = new ASN1(Arrays.copyOfRange(cio_cd, 0, length)); - byte[] contextSpecific = certificateObj.getElementAt(2).getEncoded(); - if ((contextSpecific[0] & 0xff) != 0xa1) { - log.warn("expected X509CertificateAttributes (CONTEXTSPECIFIC 0xa1), got {}", - (contextSpecific[0] & 0xff)); - } - int ll = ((contextSpecific[1] & 0xf0) == 0x80) - ? (contextSpecific[1] & 0x7f) + 2 : 2; - - ASN1 x509CertificateAttributes = new ASN1( - Arrays.copyOfRange(contextSpecific, ll, contextSpecific.length)); - - byte[] fid = x509CertificateAttributes.getElementAt(0).getElementAt(0) - .gvByteArray(); - - log.debug("reading certificate {} from file {}", - certificateObj.getElementAt(0).getElementAt(0).gvString(), - toString(fid)); - - return fid; - } catch (IOException ex) { - log.error("failed to get certificate path: " + ex.getMessage(), ex); - return null; - } - } - protected byte[] execSELECT_EF(CardChannel channel, byte[] fid) throws SignatureCardException, CardException { @@ -415,16 +305,6 @@ public class LIEZertifikatCard extends AbstractSignatureCard implements Signatur } } - protected void execMSE_RESTORE(CardChannel channel, byte seid) - throws CardException, SignatureCardException { - ResponseAPDU resp = channel.transmit( - new CommandAPDU(0x00, 0x22, 0xf3, seid)); - if (resp.getSW() != 0x9000) { - throw new SignatureCardException("MSE:RESTORE failed: SW=" - + Integer.toHexString(resp.getSW())); - } - } - protected byte[] execINTERNAL_AUTHENTICATE(CardChannel channel, byte[] AI) throws CardException, SignatureCardException { ResponseAPDU resp; @@ -443,4 +323,69 @@ public class LIEZertifikatCard extends AbstractSignatureCard implements Signatur } } + private void ensureCIOQCertificate(CardChannel channel) throws IOException, CardException, NotActivatedException, SignatureCardException { + + if (cioQCert != null) { + return; + } + + List<CIOCertificate> certCIOs = ef_od.getCD(channel).getCIOs(channel); + + for (CIOCertificate cio : certCIOs) { + + String label = cio.getLabel(); + //"Name (qualified signature" + if (label != null && label.toLowerCase().contains("qualified signature")) { + log.debug("found certificate: {} (fid={})", label, + toString(cio.getEfidOrPath())); + cioQCert = cio; + } + } + //fallback for old cards + if (cioQCert == null) { + for (CIOCertificate cio : certCIOs) { + String label = cio.getLabel(); + //"TEST LLV APO 2s Liechtenstein Post Qualified CA ID" + if (label != null && label.toLowerCase().contains("liechtenstein post qualified ca id")) { + log.debug("found certificate: {} (fid={})", label, + toString(cio.getEfidOrPath())); + cioQCert = cio; + } + } + } + + if (cioQCert == null) { + throw new NotActivatedException(); + } + } + + protected byte[] getCRT_AT(CardChannel channel) throws CardException, SignatureCardException, IOException { + + ensureCIOQCertificate(channel); + List<CIOCertificate> keyCIOs = ef_od.getPrKD(channel).getCIOs(channel); + + int i = 1; + for (CIOCertificate cio : keyCIOs) { + if (Arrays.equals(cio.getiD(), cioQCert.getiD())) { + + byte[] CRT_AT = new byte[] { + // 1-byte keyReference + (byte) 0x84, (byte) 0x01, (byte) (0x80 | (0x7f & i)), + // 3-byte keyReference + // (byte) 0x84, (byte) 0x03, (byte) 0x80, (byte) 0x01, (byte) 0xff, + //RSA Authentication + (byte) 0x89, (byte) 0x02, (byte) 0x23, (byte) 0x13 + }; + + return CRT_AT; + } + i++; + } + + log.error("no PrK CIO corresponding to QCert {} found", toString(cioQCert.getiD())); + throw new SignatureCardException("could not determine PrK for QCert " + toString(cioQCert.getiD())); + + } + + } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificate.java b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIO.java index 6a778245..a7ffb9c7 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/CIOCertificate.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIO.java @@ -15,33 +15,31 @@ * limitations under the License. */ -package at.gv.egiz.smcc; +package at.gv.egiz.smcc.cio; /** * * @author clemens */ -public class CIOCertificate { +public abstract class CIO { /** CommonObjectAttributes */ - private String label; - private byte[] authId; - - /** CommonCertificateAttributes */ - private byte[] iD; - - /** X509CertificateAttributes*/ - private byte[] efidOrPath; - private int serialNumber; + protected String label; + protected byte[] authId; /** - * @return the label + * @return the authId */ + public byte[] getAuthId() { + return authId; + } + public String getLabel() { return label; } /** + * @deprecated * @param label the label to set */ public void setLabel(String label) { @@ -49,66 +47,16 @@ public class CIOCertificate { } /** - * @return the authId - */ - public byte[] getAuthId() { - return authId; - } - - /** + * @deprecated * @param authId the authId to set */ public void setAuthId(byte[] authId) { this.authId = authId; } - /** - * @return the iD - */ - public byte[] getiD() { - return iD; - } - - /** - * @param iD the iD to set - */ - public void setiD(byte[] iD) { - this.iD = iD; - } - - /** - * @return the efidOrPath - */ - public byte[] getEfidOrPath() { - return efidOrPath; - } - - /** - * @param efidOrPath the efidOrPath to set - */ - public void setEfidOrPath(byte[] efidOrPath) { - this.efidOrPath = efidOrPath; - } - - /** - * @return the serialNumber - */ - public int getSerialNumber() { - return serialNumber; - } - - /** - * @param serialNumber the serialNumber to set - */ - public void setSerialNumber(int serialNumber) { - this.serialNumber = serialNumber; - } - @Override public String toString() { - return "CIOCertificate " + label; + return "CIO " + label; } - - } 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 new file mode 100644 index 00000000..1a9090ad --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificate.java @@ -0,0 +1,118 @@ +/* +* 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.cio; + +import iaik.me.asn1.ASN1; +import java.io.IOException; +import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author clemens + */ +public class CIOCertificate extends CIO { + + protected static final Logger log = LoggerFactory.getLogger(CIOCertificate.class); + + /** CommonCertificateAttributes */ + private byte[] iD; + + /** X509CertificateAttributes*/ + private byte[] efidOrPath; + private int serialNumber; + + public CIOCertificate(byte[] cio) throws IOException { + + ASN1 x509Certificate = new ASN1(cio); + ASN1 commonObjAttrs = x509Certificate.getElementAt(0); + label = commonObjAttrs.getElementAt(0).gvString(); + try { + // FINeID does not provide authId + authId = commonObjAttrs.getElementAt(2).gvByteArray(); + } catch (IOException e) { + log.info("failed to get authId from CommonObjectAttributes: {}", e.getMessage()); + } + + iD = x509Certificate.getElementAt(1).getElementAt(0).gvByteArray(); + + //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)); + + efidOrPath = x509CertificateAttributes.getElementAt(0).getElementAt(0).gvByteArray(); + + } else { + log.warn("expected CONTEXTSPECIFIC, got 0x{}", + Integer.toHexString(ctxSpecific[0])); + } + + } + + /** + * @return the iD + */ + public byte[] getiD() { + return iD; + } + + /** + * @param iD the iD to set + */ + public void setiD(byte[] iD) { + this.iD = iD; + } + + /** + * @return the efidOrPath + */ + public byte[] getEfidOrPath() { + return efidOrPath; + } + + /** + * @deprecated + * @param efidOrPath the efidOrPath to set + */ + public void setEfidOrPath(byte[] efidOrPath) { + this.efidOrPath = efidOrPath; + } + + /** + * @deprecated + * @return the serialNumber + */ + public int getSerialNumber() { + return serialNumber; + } + + /** + * @deprecated + * @param serialNumber the serialNumber to set + */ + public void setSerialNumber(int serialNumber) { + this.serialNumber = serialNumber; + } + + + +} 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 new file mode 100644 index 00000000..67e183fd --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIOCertificateDirectory.java @@ -0,0 +1,57 @@ +/* + * 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.cio; + +import at.gv.egiz.smcc.SignatureCardException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; + +/** + * + * @author clemens + */ +public abstract class CIOCertificateDirectory extends CIODirectoryFile { + + protected List<CIOCertificate> cios; + + public CIOCertificateDirectory(List<byte[]> DF_FIDs) { + super(DF_FIDs); + } + + @Override + protected void addCIO(byte[] cio) throws IOException { + + CIOCertificate cioCert = new CIOCertificate(cio); + + log.debug("adding {}", cioCert); + cios.add(cioCert); + + } + + @Override + public List<CIOCertificate> getCIOs(CardChannel channel) throws CardException, SignatureCardException, IOException { + if (cios == null) { + cios = new ArrayList<CIOCertificate>(); + readCIOs(channel); + } + return cios; + } +} 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 new file mode 100644 index 00000000..2d2fd03d --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/CIODirectoryFile.java @@ -0,0 +1,128 @@ +/* + * 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.cio; + +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.TLVSequence; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author clemens + */ +public abstract class CIODirectoryFile { + + protected static final Logger log = LoggerFactory.getLogger(CIODirectoryFile.class); + + protected List<byte[]> DF_FIDs; + + public CIODirectoryFile(List<byte[]> DF_FIDs) { + this.DF_FIDs = DF_FIDs; + } + + /** + * assume DF.CIA selected + * (one of) CIO.CD selected afterwards + * + * TODO: make abstract, implementation knows how to read file. only provide utility methods + * + * @param channel + * @throws CardException + * @throws SignatureCardException + * @throws IOException if ASN.1 structure cannot be parsed + */ + public void readCIOs(CardChannel channel) + throws CardException, SignatureCardException, IOException { + + for (byte[] fid : DF_FIDs) { + byte[] fd = selectDirectoryFile(channel, fid); + if ((fd[0] & 0x04) > 0) { + readCIOsFromRecords(channel, fd); + } else if ((fd[0] & 0x05) == 0x01) { + readCIOsFromTransparentFile(channel); + } + } + } + + /** + * card specific implementation to select a CIO DF file and return its file descriptor + * @param channel + * @param fid + * @return file descriptor + * @throws CardException + */ + protected abstract byte[] selectDirectoryFile(CardChannel channel, byte[] fid) throws CardException; + + + protected void readCIOsFromRecords(CardChannel channel, byte[] fd) throws CardException, SignatureCardException, IOException { + + for (int r = 1; r < fd[fd.length - 1]; r++) { + log.trace("read CIO record {}", r); + byte[] record = ISO7816Utils.readRecord(channel, r); + addCIO(record); + } + } + + + protected void readCIOsFromTransparentFile(CardChannel channel) throws CardException, SignatureCardException, IOException { + + byte[] ef = ISO7816Utils.readTransparentFile(channel, -1); + + 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 CIO transparent file entry: tag 0x{}, length 0x{}", + Integer.toHexString(ef[i]), + Integer.toHexString(length)); + + j = i + 2 + ll + length; + addCIO(Arrays.copyOfRange(ef, i, j)); + i = j; + } while (i < ef.length && ef[i] > 0); + + } + + + + /** + * CIO specific (Cert/PrK/AO/... CIO) + * @param cio + */ + protected abstract void addCIO(byte[] cio) throws IOException; + + public abstract List<? extends CIO> getCIOs(CardChannel channel) throws CardException, SignatureCardException, IOException; +} 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 new file mode 100644 index 00000000..40d5c7b9 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/LIEZertifikatCertificateDirectory.java @@ -0,0 +1,48 @@ +/* + * 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.cio; + +import at.gv.egiz.smcc.cio.CIOCertificateDirectory; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.TLVSequence; +import java.util.List; +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +/** + * + * @author clemens + */ +public class LIEZertifikatCertificateDirectory extends CIOCertificateDirectory { + + public LIEZertifikatCertificateDirectory(List<byte[]> DF_FIDs) { + super(DF_FIDs); + } + + @Override + protected byte[] selectDirectoryFile(CardChannel channel, byte[] fid) throws CardException { + + CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, 0x02, ISO7816Utils.P2_FCP, fid, 256); + ResponseAPDU resp = channel.transmit(cmd); + + byte[] fcp = new TLVSequence(resp.getBytes()).getValue(ISO7816Utils.TAG_FCP); + return new TLVSequence(fcp).getValue(0x82); + + } +} 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 new file mode 100644 index 00000000..3ab954ee --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/cio/ObjectDirectory.java @@ -0,0 +1,208 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package at.gv.egiz.smcc.cio; + +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.util.ISO7816Utils; +import at.gv.egiz.smcc.util.TLV; +import at.gv.egiz.smcc.util.TLVSequence; + +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; + +/** + * TODO ObjectDirectory has access to card filesystem (to readTransparentFile(fid)) + * + * @author clemens + */ +public class ObjectDirectory { + + protected static final Logger log = LoggerFactory + .getLogger(ObjectDirectory.class); + + protected byte[] fid; + + protected CIOCertificateDirectory efCD; + /** TODO */ + protected CIOCertificateDirectory efPrKD; + + /** References to CIO EFs */ + private List<byte[]> PrKD_refs; + private List<byte[]> PuKD_refs; + private List<byte[]> AOD_refs; + private List<byte[]> CD_refs; + + private Integer padding; + private int P1 = 0x02; + + public ObjectDirectory() { + fid = new byte[] { (byte) 0x50, (byte) 0x31 }; + } + + public ObjectDirectory(byte[] fid) { + this.fid = fid; + } + + /** + * @deprecated check while reading if tag is valid + * @param padding + */ + public ObjectDirectory(int padding, int p1) { + + fid = new byte[] { (byte) 0x50, (byte) 0x31 }; + this.padding = padding; + this.P1 = p1; + } + + /** + * assume DF.CIA selected EF.OD selected afterwards + * + * @deprecated will be made private, use getCD/... instead + * + * @param channel + * @throws CardException + * @throws SignatureCardException + */ + public void selectAndRead(CardChannel channel) throws CardException, + SignatureCardException { + + CommandAPDU cmd = new CommandAPDU(0x00, 0xA4, P1, 0x00, fid, 256); + ResponseAPDU resp = channel.transmit(cmd); + + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("SELECT EF.OD failed: SW=0x" + + Integer.toHexString(resp.getSW())); + } + + byte[] efod = ISO7816Utils.readTransparentFile(channel, -1); + + PrKD_refs = new ArrayList<byte[]>(); + PuKD_refs = new ArrayList<byte[]>(); + AOD_refs = new ArrayList<byte[]>(); + CD_refs = new ArrayList<byte[]>(); + + for (TLV cio : new TLVSequence(efod)) { + int tag = cio.getTag(); + + //TODO FIN EID: check if unknown tag and tag length > array + if (padding != null && tag == padding) { + // reached padding - quit record extraction + break; + } + + byte[] seq = cio.getValue(); + + if ((tag & 0xf0) == 0xa0 && seq.length >= 4) { + + byte[] path = Arrays.copyOfRange(seq, 4, 4 + seq[3]); + + switch (cio.getTag() & 0x0f) { + case 0: + PrKD_refs.add(path); + break; + case 1: + PuKD_refs.add(path); + break; + case 4: + CD_refs.add(path); + break; + case 8: + AOD_refs.add(path); + break; + default: + log.warn("CIOChoice 0x{} not supported: ", + (cio.getTag() & 0x0f)); + } + } else { + log.trace("ignoring invalid CIO reference entry: {}", seq); + } + } + } + + /** + * + * @return the CertificateDirectory CIO file referenced in this EF.OD. + * If multiple directory files are referenced, the returned CD covers + * all of them. + */ + public CIOCertificateDirectory getCD(CardChannel channel) throws CardException, SignatureCardException { + + if (efCD == null) { + + if (CD_refs == null) { + selectAndRead(channel); + } + efCD = new LIEZertifikatCertificateDirectory(CD_refs); + } + return efCD; + } + + public CIOCertificateDirectory getPrKD(CardChannel channel) throws CardException, SignatureCardException { + + if (efPrKD == null) { + + if (PrKD_refs == null) { + selectAndRead(channel); + } + efPrKD = new LIEZertifikatCertificateDirectory(PrKD_refs); + } + return efPrKD; + } + + + + /** + * @deprecated use getPrKD instead + * @return the references (FIDs) of the CIO files + */ + public List<byte[]> getPrKDReferences() { + return PrKD_refs; + } + + /** + * @deprecated use getPuKD instead + * @return the references (FIDs) of the CIO files + */ + public List<byte[]> getPuKDReferences() { + return PuKD_refs; + } + + /** + * @deprecated use getAOD instead + * @return the references (FIDs) of the CIO files + */ + public List<byte[]> getAODReferences() { + return AOD_refs; + } + + /** + * @deprecated use getCD instead + * @return the references (FIDs) of the CIO files + */ + public List<byte[]> getCDReferences() { + return CD_refs; + } +} diff --git a/smcc/src/test/java/at/gv/egiz/smcc/FINEIDTest.java b/smcc/src/test/java/at/gv/egiz/smcc/FINEIDTest.java index eef6f611..251728bd 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/FINEIDTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/FINEIDTest.java @@ -1,5 +1,6 @@ package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.cio.CIOCertificate;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -95,10 +96,10 @@ public class FINEIDTest extends AbstractSignatureCard { // **** READ CERT ****
- for (int i = 0; i < ef_od.getEf_cd_list().size(); i++) {
+ for (int i = 0; i < ef_od.getCDReferences().size(); i++) {
FINEIDCIOCertificateDirectory ef_cd = new FINEIDCIOCertificateDirectory(
- ef_od.getEf_cd_list().get(i));
+ ef_od.getCDReferences().get(i));
try {
ef_cd.selectAndRead(channel);
@@ -158,11 +159,11 @@ public class FINEIDTest extends AbstractSignatureCard { // **** VERIFY PIN ****
- byte[] prkdPath = ef_od.getEf_prkd();
+ byte[] prkdPath = ef_od.getPrKDReferences().get(0);
System.out.println("PRKD path: " + SMCCHelper.toString(prkdPath));
FINEIDCIOKeyDirectory ef_prkd = new FINEIDCIOKeyDirectory(ef_od
- .getEf_prkd());
+ .getPrKDReferences().get(0));
ef_prkd.selectAndRead(channel);
byte[] efKey = null;
@@ -181,10 +182,10 @@ public class FINEIDTest extends AbstractSignatureCard { System.out.println("Key path: " + SMCCHelper.toString(efKey));
- byte[] aod = ef_od.getEf_aod();
+ byte[] aod = ef_od.getAODReferences().get(0);
System.out.println("AOD path: " + SMCCHelper.toString(aod));
- FINEIDAODirectory ef_aod = new FINEIDAODirectory(ef_od.getEf_aod());
+ FINEIDAODirectory ef_aod = new FINEIDAODirectory(ef_od.getAODReferences().get(0));
ef_aod.selectAndRead(channel);
byte[] pinPath = null;
|