Java tutorial
/******************************************************************************* * Implementation of the protocols PACE, Terminal Authentication and Chip * Authentication (client side) with respect to the according BSI standards. * * Copyright (C) 2013 Fraunhofer-Gesellschaft * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package de.fraunhofer.fokus.openeid.eac; import java.io.IOException; import java.util.List; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.DERObject; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.util.ASN1Dump; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.fraunhofer.fokus.openeid.ca.ChipAuthenticationDomainParameterInfo; import de.fraunhofer.fokus.openeid.ca.ChipAuthenticationInfo; import de.fraunhofer.fokus.openeid.ca.ChipAuthenticationOID; import de.fraunhofer.fokus.openeid.ca.SignedData; import de.fraunhofer.fokus.openeid.commands.UnsupportedProtocolException; import de.fraunhofer.fokus.openeid.device.NfcHandler; import de.fraunhofer.fokus.openeid.iso7816_4.Utils; import de.fraunhofer.fokus.openeid.pace.DerUtils; import de.fraunhofer.fokus.openeid.pace.InvalidDomainParameter; import de.fraunhofer.fokus.openeid.pace.PACEInfo; import de.fraunhofer.fokus.openeid.pace.PACEinfoProtocolOID; import de.fraunhofer.fokus.openeid.pace.Pace; import de.fraunhofer.fokus.openeid.ri.RestrictedIdentificationDomainParameterInfo; import de.fraunhofer.fokus.openeid.ri.RestrictedIdentificationInfo; import de.fraunhofer.fokus.openeid.ri.RestrictedIdentificationOID; import de.fraunhofer.fokus.openeid.ta.TerminalAuthenticationInfo; import de.fraunhofer.fokus.openeid.ta.TerminalAuthenticationInfoOID; public abstract class EfFile { protected static final Logger logger = LoggerFactory.getLogger("EfFile"); protected DERObject file; protected byte[] content; public abstract void readFile(NfcHandler device, Pace pace) throws Exception; protected void processContent() throws IOException { ASN1InputStream asn1InputStream = new ASN1InputStream(content); file = asn1InputStream.readObject(); asn1InputStream.close(); } public String dump() { // return DERDump.dumpAsString(file); return ASN1Dump.dumpAsString(file, true); } public byte[] getContent() { return content; } public void setContent(byte[] content) throws IOException { this.content = content; processContent(); } public DERObject getFile() { return file; } /** * get TerminalAuthenticationInfo from EF.CardAccess * @return PACEInfo structure containing essential parameters used in PACE * @throws UnsupportedProtocolException * @throws InvalidDomainParameter */ public TerminalAuthenticationInfo getTerminalAuthentionInfo() { List<DERObject> taInfos = DerUtils.getByOid(TerminalAuthenticationInfoOID.ID_TA, file); assert (taInfos.size() > 1); //heuristic: try to retrieve a pace info with version 2 (it is recommended in specs) for (DERObject taCandidate : taInfos) { assert (taCandidate instanceof DERSequence); try { TerminalAuthenticationInfo info = new TerminalAuthenticationInfo((DERSequence) taCandidate); if (info.getVersion() == 2) { return info; } } catch (Exception e) { } } //no version 2 found, try to take any (first element heuristic) return new TerminalAuthenticationInfo((DERSequence) taInfos.get(0)); } public SignedData getSecurityObject() throws IOException { DERSequence fileSequence = (DERSequence) file; DERTaggedObject level1 = (DERTaggedObject) fileSequence.getObjectAt(1); DERSequence level1_ = (DERSequence) level1.getObject(); DERSequence level2 = (DERSequence) level1_.getObjectAt(2); DERTaggedObject level3 = (DERTaggedObject) level2.getObjectAt(1); return new SignedData((DEROctetString) level3.getObject()); } /** * get PACEInfo from EF.CardAccess * @return PACEInfo structure containing essential parameters used in PACE * @throws UnsupportedProtocolException * @throws InvalidDomainParameter */ public PACEInfo getPaceInfo() throws UnsupportedProtocolException, InvalidDomainParameter { List<DERObject> paceInfos = DerUtils.getByOid(PACEinfoProtocolOID.ID_PACE, file); assert (paceInfos.size() >= 1); //heuristic: try to retrieve a pace info with version 2 (it is recommended in specs) for (DERObject paceCandidate : paceInfos) { assert (paceCandidate instanceof DERSequence); try { PACEInfo info = new PACEInfo((DERSequence) paceCandidate); if (info.getVersion() == 2) { return info; } } catch (Exception e) { } } //no version 2 found, try to take any (first element heuristic) return new PACEInfo((DERSequence) paceInfos.get(0)); } /** * get ChipAuthenticationInfo from EF.CardAccess * @return ChipAuthenticationInfo structure containing essential parameters used in PACE * @throws UnsupportedProtocolException * @throws InvalidDomainParameter */ public ChipAuthenticationInfo getChipAuthenticationInfo() { List<DERObject> caInfos = DerUtils.getByOid(ChipAuthenticationOID.ID_CA, file); assert (caInfos.size() > 1); //heuristic: try to retrieve a ca info with version 2 (it is recommended in specs) for (DERObject caCandidate : caInfos) { assert (caCandidate instanceof DERSequence); try { ChipAuthenticationInfo info = new ChipAuthenticationInfo((DERSequence) caCandidate); if (info.getVersion() == 2) { return info; } } catch (Exception e) { } } //no version 2 found, try to take any (first element heuristic) return new ChipAuthenticationInfo((DERSequence) caInfos.get(0)); } /** * get ChipAuthenticationInfo from EF.CardAccess, * @return CAinfo structure containing essential parameters used in TA/CA; null on errors * @throws UnsupportedProtocolException * @throws InvalidDomainParameter */ public ChipAuthenticationDomainParameterInfo getChipAuthenticationDomainParameterInfo() { List<DERObject> caInfos = DerUtils.getByOid(ChipAuthenticationOID.ID_CA, file); assert (caInfos.size() > 1); for (DERObject caCandidate : caInfos) { assert (caCandidate instanceof DERSequence); try { ChipAuthenticationDomainParameterInfo info = new ChipAuthenticationDomainParameterInfo( (DERSequence) caCandidate); return info; } catch (Exception e) { } } return null; } public RestrictedIdentificationInfo getRestrictedIdentificationInfo() throws IOException { List<DERObject> riInfos = DerUtils.getByOid(RestrictedIdentificationOID.ID_RI, getSecurityObject().getDerObject()); assert (riInfos.size() > 1); for (DERObject riCandidate : riInfos) { assert (riCandidate instanceof DERSequence); try { RestrictedIdentificationInfo info = new RestrictedIdentificationInfo((DERSequence) riCandidate); return info; } catch (Exception e) { } } return null; } public RestrictedIdentificationDomainParameterInfo getRestrictedIdentificationDomainParameterInfo() throws IOException { List<DERObject> riInfos = DerUtils.getByOid(RestrictedIdentificationOID.ID_RI, getSecurityObject().getDerObject()); assert (riInfos.size() > 1); for (DERObject riCandidate : riInfos) { assert (riCandidate instanceof DERSequence); try { RestrictedIdentificationDomainParameterInfo info = new RestrictedIdentificationDomainParameterInfo( (DERSequence) riCandidate); return info; } catch (Exception e) { } } return null; } @Override public String toString() { if (file != null) { return Utils.byteArrayToHexString(content); } else { return "no data"; } } }