diff options
Diffstat (limited to 'smcc')
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;
 | 
