/**************************************************************************** * Copyright (C) 2012 HS Coburg. * All rights reserved. * Contact: ecsec GmbH (info@ecsec.de) * * This file is part of the Open eCard App. * * GNU General Public License Usage * This file may be used under the terms of the GNU General Public * License version 3.0 as published by the Free Software Foundation * and appearing in the file LICENSE.GPL included in the packaging of * this file. Please review the following information to ensure the * GNU General Public License version 3.0 requirements will be met: * http://www.gnu.org/copyleft/gpl.html. * * Other Usage * Alternatively, this file may be used in accordance with the terms * and conditions contained in a signed written agreement between * you and ecsec GmbH. * ***************************************************************************/ package org.openecard.sal.protocol.eac.anytype; import iso.std.iso_iec._24727.tech.schema.DIDAuthenticationDataType; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.openecard.common.anytype.AuthDataMap; import org.openecard.common.util.ByteUtils; import org.openecard.common.util.StringUtils; import org.openecard.crypto.common.asn1.cvc.CardVerifiableCertificate; import org.openecard.crypto.common.asn1.cvc.CardVerifiableCertificateChain; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; /** * Implements the EAC1InputType data structure. * See BSI-TR-03112, version 1.1.2, part 7, section 4.6.5. * * @author Dirk Petrautzki <petrautzki@hs-coburg.de> * @author Moritz Horsch <horsch@cdc.informatik.tu-darmstadt.de> */ public class EAC1InputType { private static final Logger logger = LoggerFactory.getLogger(EAC1InputType.class); public static final String CERTIFICATE = "Certificate"; public static final String CERTIFICATE_DESCRIPTION = "CertificateDescription"; public static final String REQUIRED_CHAT = "RequiredCHAT"; public static final String OPTIONAL_CHAT = "OptionalCHAT"; public static final String AUTHENTICATED_AUXILIARY_DATA = "AuthenticatedAuxiliaryData"; private final AuthDataMap authMap; private ArrayList<CardVerifiableCertificate> certificates; private byte[] certificateDescription; private byte[] requiredCHAT; private byte[] optionalCHAT; private byte[] authenticatedAuxiliaryData; /** * Creates a new EAC1InputType. * * @param baseType DIDAuthenticationDataType * @throws Exception */ public EAC1InputType(DIDAuthenticationDataType baseType) throws Exception { authMap = new AuthDataMap(baseType); certificateDescription = authMap.getContentAsBytes(CERTIFICATE_DESCRIPTION); certificates = new ArrayList<CardVerifiableCertificate>(); for (Element element : baseType.getAny()) { if (element.getLocalName().equals(CERTIFICATE)) { byte[] value = StringUtils.toByteArray(element.getTextContent()); CardVerifiableCertificate cvc = new CardVerifiableCertificate(value); certificates.add(cvc); } } requiredCHAT = authMap.getContentAsBytes(REQUIRED_CHAT); optionalCHAT = authMap.getContentAsBytes(OPTIONAL_CHAT); // HACK: this is only done because some eID Server vendors send raw CHAT values // if not present use chat from CVC if (requiredCHAT == null) { CardVerifiableCertificateChain certChain = new CardVerifiableCertificateChain(certificates); List<CardVerifiableCertificate> terminalCerts = certChain.getTerminalCertificates(); requiredCHAT = terminalCerts.get(0).getCHAT().toByteArray(); } else { requiredCHAT = fixChatValue(requiredCHAT); } // if not present, use required as optional if (optionalCHAT == null) { optionalCHAT = Arrays.copyOf(requiredCHAT, requiredCHAT.length); } else { optionalCHAT = fixChatValue(optionalCHAT); } authenticatedAuxiliaryData = authMap.getContentAsBytes(AUTHENTICATED_AUXILIARY_DATA); } /** * Returns the set of certificates. * * @return Certificates */ public ArrayList<CardVerifiableCertificate> getCertificates() { return certificates; } /** * Returns the certificate description. * * @return Certificate description */ public byte[] getCertificateDescription() { return certificateDescription; } /** * Returns the required CHAT. * * @return Required CHAT */ public byte[] getRequiredCHAT() { return requiredCHAT; } /** * Returns the optional CHAT. * * @return Optional CHAT */ public byte[] getOptionalCHAT() { return optionalCHAT; } /** * Returns the AuthenticatedAuxiliaryData. * * @return AuthenticatedAuxiliaryData */ public byte[] getAuthenticatedAuxiliaryData() { return authenticatedAuxiliaryData; } /** * Returns a new EAC1OutputType. * * @return EAC1OutputType */ public EAC1OutputType getOutputType() { return new EAC1OutputType(authMap); } /** * Adds ASN1 Structure to incomplete CHAT values. * Some eID servers only send the CHAT value itself, but there must an OID and a surrounding ASN1 structure. This * function completes the CHAT value with the AuthenticationTerminal OID. * * @param chat CHAT value, possibly without ASN1 structure. * @return CHAT value with ASN1 structure. */ private static byte[] fixChatValue(byte[] chat) { if (chat.length == 5) { logger.warn("Correcting invalid CHAT value '{}'.", ByteUtils.toHexString(chat)); String asn1Prefix = "7F4C12060904007F0007030102025305"; byte[] prefixBytes = StringUtils.toByteArray(asn1Prefix); byte[] result = ByteUtils.concatenate(prefixBytes, chat); return result; } else { return chat; } } }