org.jmrtd.lds.SecurityInfo.java Source code

Java tutorial

Introduction

Here is the source code for org.jmrtd.lds.SecurityInfo.java

Source

/*
 * JMRTD - A Java API for accessing machine readable travel documents.
 *
 * Copyright (C) 2006 - 2015  The JMRTD team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * $Id$
 */

package org.jmrtd.lds;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Logger;

import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;

/* FIXME: dependency on BC in interface? */

/**
 * Abstract base class for security info structure.
 * See the BSI EAC 1.11 specification.
 * See the ICAO TR - SAC v1.1 specification.
 *
 * @author Wojciech Mostowski (woj@cs.ru.nl)
 * @author Martijn Oostdijk (martijn.oostdijk@gmail.com)
 * 
 * @version $Revision$
 */
public abstract class SecurityInfo extends AbstractLDSInfo {

    private static final long serialVersionUID = -7919854443619069808L;

    private static final Logger LOGGER = Logger.getLogger("org.jmrtd");

    /**
     * Used in ECDSA based Active Authentication.
     * <code>{joint-iso-itu-t(2) international-organizations(23) 136 mrtd(1) security(1) aaProtocolObject(5)}</code>.
     */
    public static final String ID_AA_OID = "2.23.136.1.1.5";

    public static final String ID_PK_DH_OID = EACObjectIdentifiers.id_PK_DH.getId(),
            ID_PK_ECDH_OID = EACObjectIdentifiers.id_PK_ECDH.getId(),
            ID_TA_OID = EACObjectIdentifiers.id_TA.getId(),
            ID_CA_DH_3DES_CBC_CBC_OID = EACObjectIdentifiers.id_CA_DH_3DES_CBC_CBC.getId(),
            ID_CA_ECDH_3DES_CBC_CBC_OID = EACObjectIdentifiers.id_CA_ECDH_3DES_CBC_CBC.getId();

    public static final String ID_CA_DH_AES_CBC_CMAC_128_OID = "0.4.0.127.0.7.2.2.3.1.2",
            ID_CA_DH_AES_CBC_CMAC_192_OID = "0.4.0.127.0.7.2.2.3.1.3",
            ID_CA_DH_AES_CBC_CMAC_256_OID = "0.4.0.127.0.7.2.2.3.1.4",
            ID_CA_ECDH_AES_CBC_CMAC_128_OID = "0.4.0.127.0.7.2.2.3.2.2",
            ID_CA_ECDH_AES_CBC_CMAC_192_OID = "0.4.0.127.0.7.2.2.3.2.3",
            ID_CA_ECDH_AES_CBC_CMAC_256_OID = "0.4.0.127.0.7.2.2.3.2.4";

    public static final String ID_EC_PUBLIC_KEY_TYPE = X9ObjectIdentifiers.id_publicKeyType.getId(),
            ID_EC_PUBLIC_KEY = X9ObjectIdentifiers.id_ecPublicKey.getId();

    private static final String ID_BSI = "0.4.0.127.0.7";

    /* protocols (2), smartcard (2), PACE (4) */
    public static final String ID_PACE = ID_BSI + ".2.2.4";

    public static final String ID_PACE_DH_GM = ID_PACE + ".1";

    public static final String ID_PACE_ECDH_GM = ID_PACE + ".2";

    public static final String ID_PACE_DH_IM = ID_PACE + ".3";

    public static final String ID_PACE_ECDH_IM = ID_PACE + ".4";

    public static final String ID_PACE_ECDH_CAM = ID_PACE + ".6";

    public static final String ID_PACE_DH_GM_3DES_CBC_CBC = ID_PACE_DH_GM
            + ".1", /* 0.4.0.127.0.7.2.2.4.1.1, id-PACE-DH-GM-3DES-CBC-CBC */
            ID_PACE_DH_GM_AES_CBC_CMAC_128 = ID_PACE_DH_GM
                    + ".2", /* 0.4.0.127.0.7.2.2.4.1.2, id-PACE-DH-GM-AES-CBC-CMAC-128 */
            ID_PACE_DH_GM_AES_CBC_CMAC_192 = ID_PACE_DH_GM
                    + ".3", /* 0.4.0.127.0.7.2.2.4.1.3, id-PACE-DH-GM-AES-CBC-CMAC-192 */
            ID_PACE_DH_GM_AES_CBC_CMAC_256 = ID_PACE_DH_GM
                    + ".4"; /* 0.4.0.127.0.7.2.2.4.1.4, id-PACE-DH-GM-AES-CBC-CMAC-256 */

    public static final String ID_PACE_ECDH_GM_3DES_CBC_CBC = ID_PACE_ECDH_GM
            + ".1", /* 0.4.0.127.0.7.2.2.4.2.1, id-PACE-ECDH-GM-3DES-CBC-CBC */
            ID_PACE_ECDH_GM_AES_CBC_CMAC_128 = ID_PACE_ECDH_GM
                    + ".2", /* 0.4.0.127.0.7.2.2.4.2.2, id-PACE-ECDH-GM-AES-CBC-CMAC-128 */
            ID_PACE_ECDH_GM_AES_CBC_CMAC_192 = ID_PACE_ECDH_GM
                    + ".3", /* 0.4.0.127.0.7.2.2.4.2.3, id-PACE-ECDH-GM-AES-CBC-CMAC-192 */
            ID_PACE_ECDH_GM_AES_CBC_CMAC_256 = ID_PACE_ECDH_GM
                    + ".4"; /* 0.4.0.127.0.7.2.2.4.2.4, id-PACE-ECDH-GM-AES-CBC-CMAC-256 */

    public static final String ID_PACE_DH_IM_3DES_CBC_CBC = ID_PACE_DH_IM
            + ".1", /* 0.4.0.127.0.7.2.2.4.3.1, id-PACE-DH-IM-3DES-CBC-CBC */
            ID_PACE_DH_IM_AES_CBC_CMAC_128 = ID_PACE_DH_IM
                    + ".2", /* 0.4.0.127.0.7.2.2.4.3.2, id-PACE-DH-IM-AES-CBC-CMAC-128 */
            ID_PACE_DH_IM_AES_CBC_CMAC_192 = ID_PACE_DH_IM
                    + ".3", /* 0.4.0.127.0.7.2.2.4.3.3, id-PACE-DH-IM-AES-CBC-CMAC-192 */
            ID_PACE_DH_IM_AES_CBC_CMAC_256 = ID_PACE_DH_IM
                    + ".4"; /* 0.4.0.127.0.7.2.2.4.3.4, id-PACE-DH-IM-AES-CBC-CMAC-256 */

    public static final String ID_PACE_ECDH_IM_3DES_CBC_CBC = ID_PACE_ECDH_IM
            + ".1", /* 0.4.0.127.0.7.2.2.4.4.1, id-PACE-ECDH-IM-3DES-CBC-CBC */
            ID_PACE_ECDH_IM_AES_CBC_CMAC_128 = ID_PACE_ECDH_IM
                    + ".2", /* 0.4.0.127.0.7.2.2.4.4.2, id-PACE-ECDH-IM-AES-CBC-CMAC-128 */
            ID_PACE_ECDH_IM_AES_CBC_CMAC_192 = ID_PACE_ECDH_IM
                    + ".3", /* 0.4.0.127.0.7.2.2.4.4.3, id-PACE-ECDH-IM-AES-CBC-CMAC-192 */
            ID_PACE_ECDH_IM_AES_CBC_CMAC_256 = ID_PACE_ECDH_IM
                    + ".4"; /* 0.4.0.127.0.7.2.2.4.4.4, id-PACE-ECDH-IM-AES-CBC-CMAC-256 */

    public static final String ID_PACE_ECDH_CAM_AES_CBC_CMAC_128 = ID_PACE_ECDH_CAM
            + ".2", /* 0.4.0.127.0.7.2.2.4.6.2, id-PACE-ECDH-CAM-AES-CBC-CMAC-128 */
            ID_PACE_ECDH_CAM_AES_CBC_CMAC_192 = ID_PACE_ECDH_CAM
                    + ".3", /* 0.4.0.127.0.7.2.2.4.6.3, id-PACE-ECDH-CAM-AES-CBC-CMAC-192 */
            ID_PACE_ECDH_CAM_AES_CBC_CMAC_256 = ID_PACE_ECDH_CAM
                    + ".4"; /* 0.4.0.127.0.7.2.2.4.6.4, id-PACE-ECDH-CAM-AES-CBC-CMAC-256 */

    /**
     * Returns a DER object with this SecurityInfo data (DER sequence)
     *
     * @return a DER object with this SecurityInfo data
     *
     * @deprecated Remove this method from visible interface (because of dependency on BC API)
     */
    public abstract ASN1Primitive getDERObject();

    /**
     * Writes this SecurityInfo to output stream.
     *
     * @param outputStream an ouput stream
     *
     * @throws IOException if writing fails
     */
    public void writeObject(OutputStream outputStream) throws IOException {
        ASN1Primitive derEncoded = getDERObject();
        if (derEncoded == null) {
            throw new IOException("Could not decode from DER.");
        }
        byte[] derEncodedBytes = derEncoded.getEncoded(ASN1Encoding.DER);
        if (derEncodedBytes == null) {
            throw new IOException("Could not decode from DER.");
        }
        outputStream.write(derEncodedBytes);
    }

    /**
     * Returns the object identifier of this SecurityInfo.
     *
     * @return this SecurityInfo object identifier
     */
    public abstract String getObjectIdentifier();

    /**
     * Factory method for creating security info objects given an input.
     *
     * @param obj the input
     *
     * @return a concrete security info object
     */
    public static SecurityInfo getInstance(ASN1Primitive obj) {
        try {
            ASN1Sequence sequence = (ASN1Sequence) obj;
            String oid = ((ASN1ObjectIdentifier) sequence.getObjectAt(0)).getId();
            ASN1Primitive requiredData = sequence.getObjectAt(1).toASN1Primitive();
            ASN1Primitive optionalData = null;
            if (sequence.size() == 3) {
                optionalData = sequence.getObjectAt(2).toASN1Primitive();
            }

            if (ActiveAuthenticationInfo.checkRequiredIdentifier(oid)) {
                int version = ((ASN1Integer) requiredData).getValue().intValue();
                if (optionalData == null) {
                    return new ActiveAuthenticationInfo(oid, version, null);
                } else {
                    String signatureAlgorithmOID = ((ASN1ObjectIdentifier) optionalData).getId();
                    return new ActiveAuthenticationInfo(oid, version, signatureAlgorithmOID);
                }
            } else if (ChipAuthenticationPublicKeyInfo.checkRequiredIdentifier(oid)) {
                SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo((ASN1Sequence) requiredData);
                if (optionalData == null) {
                    return new ChipAuthenticationPublicKeyInfo(oid, subjectPublicKeyInfo);
                } else {
                    ASN1Integer optionalDataAsASN1Integer = (ASN1Integer) optionalData;
                    BigInteger keyId = optionalDataAsASN1Integer.getValue();
                    return new ChipAuthenticationPublicKeyInfo(oid, subjectPublicKeyInfo, keyId);
                }
            } else if (ChipAuthenticationInfo.checkRequiredIdentifier(oid)) {
                int version = ((ASN1Integer) requiredData).getValue().intValue();
                if (optionalData == null) {
                    return new ChipAuthenticationInfo(oid, version);
                } else {
                    ASN1Integer optionalDataAsASN1Integer = (ASN1Integer) optionalData;
                    BigInteger keyId = optionalDataAsASN1Integer.getValue();
                    return new ChipAuthenticationInfo(oid, version, keyId);
                }
            } else if (TerminalAuthenticationInfo.checkRequiredIdentifier(oid)) {
                int version = ((ASN1Integer) requiredData).getValue().intValue();
                if (optionalData == null) {
                    return new TerminalAuthenticationInfo(oid, version);
                } else {
                    ASN1Sequence efCVCA = (ASN1Sequence) optionalData;
                    return new TerminalAuthenticationInfo(oid, version, efCVCA);
                }
            } else if (PACEInfo.checkRequiredIdentifier(oid)) {
                int version = ((ASN1Integer) requiredData).getValue().intValue();
                int parameterId = -1;
                if (optionalData != null) {
                    parameterId = ((ASN1Integer) optionalData).getValue().intValue();
                }
                return new PACEInfo(oid, version, parameterId);
            } else if (PACEDomainParameterInfo.checkRequiredIdentifier(oid)) {
                AlgorithmIdentifier domainParameters = AlgorithmIdentifier.getInstance(requiredData);
                if (optionalData != null) {
                    int parameterId = ((ASN1Integer) optionalData).getValue().intValue();
                    return new PACEDomainParameterInfo(oid, domainParameters, parameterId);
                }
                return new PACEDomainParameterInfo(oid, domainParameters);
            }
            //         throw new IllegalArgumentException("Malformed input stream.");
            LOGGER.warning("Unsupported SecurityInfo, oid = " + oid);
            return null;
        } catch (Exception e) {
            LOGGER.severe("Exception: " + e.getMessage());
            throw new IllegalArgumentException("Malformed input stream.");
        }
    }

    protected static String lookupMnemonicByOID(String oid) throws NoSuchAlgorithmException {
        if (ID_PK_DH_OID.equals(oid)) {
            return "id-PK-DH";
        }
        if (ID_PK_ECDH_OID.equals(oid)) {
            return "id-PK-ECDH";
        }
        if (ID_TA_OID.equals(oid)) {
            return "id-TA";
        }
        throw new NoSuchAlgorithmException("Unknown OID " + oid);
    }
}