mitm.common.security.certificate.AltNamesInspector.java Source code

Java tutorial

Introduction

Here is the source code for mitm.common.security.certificate.AltNamesInspector.java

Source

/*
 * Copyright (c) 2008-2012, Martijn Brinkers, Djigzo.
 * 
 * This file is part of Djigzo email encryption.
 *
 * Djigzo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3, 19 November 2007 as published by the Free Software 
 * Foundation.
 *
 * Djigzo 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public 
 * License along with Djigzo. If not, see <http://www.gnu.org/licenses/>
 *
 * Additional permission under GNU AGPL version 3 section 7
 * 
 * If you modify this Program, or any covered work, by linking or 
 * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, 
 * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, 
 * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, 
 * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, 
 * wsdl4j-1.6.1.jar (or modified versions of these libraries), 
 * containing parts covered by the terms of Eclipse Public License, 
 * tyrex license, freemarker license, dom4j license, mx4j license,
 * Spice Software License, Common Development and Distribution License
 * (CDDL), Common Public License (CPL) the licensors of this Program grant 
 * you additional permission to convey the resulting work.
 */
package mitm.common.security.certificate;

import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import mitm.common.security.asn1.ASN1Utils;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.X509Extension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper for getting all the AltNames from a altName collection.
 * 
 * TODO: Add support for other AltNames
 */
public class AltNamesInspector {
    private final static Logger logger = LoggerFactory.getLogger(AltNamesInspector.class);

    /*
     *  GeneralNames :: = SEQUENCE SIZE (1..MAX) OF GeneralName
     *
     *  GeneralName ::= CHOICE {
     *    otherName                       [0]     OtherName,
     *    rfc822Name                      [1]     IA5String,
     *    dNSName                         [2]     IA5String,
     *    x400Address                     [3]     ORAddress,
     *    directoryName                   [4]     Name,
     *    ediPartyName                    [5]     EDIPartyName,
     *    uniformResourceIdentifier       [6]     IA5String,
     *    iPAddress                       [7]     OCTET STRING,
     *    registeredID                    [8]     OBJECT IDENTIFIER}
    */
    private static final int otherNameTag = 0;
    private static final int rfc822NameTag = 1;
    private static final int dnsNameTag = 2;
    private static final int x400AddressTag = 3;
    private static final int directoryNameTag = 4;
    private static final int ediPartyNameTag = 5;
    private static final int uniformResourceIdentifierTag = 6;
    private static final int iPAddressTag = 7;
    private static final int registeredIDTag = 8;

    private final List<String> rfc822Names = new LinkedList<String>();
    private final List<String> dnsNames = new LinkedList<String>();

    /**
     * Use this constructor for X509certificate.getSubjectAlternativeNames()
     * @param altNames
     */
    public AltNamesInspector(Collection<List<?>> altNames) {
        parseAltNames(altNames);
    }

    /**
     * Use this constructor for ASN1Utils.getExtensionValue(X509Extension, String)
     * @param altName
     */
    public AltNamesInspector(ASN1Sequence altName) {
        if (altName != null) {
            Collection<List<?>> altNames = new LinkedList<List<?>>();

            for (int i = 0; i < altName.size(); i++) {
                GeneralName generalName = GeneralName.getInstance(altName.getObjectAt(i));

                ASN1Encodable obj = generalName.getName();

                String value;

                switch (generalName.getTagNo()) {
                case rfc822NameTag:
                case dnsNameTag:
                case uniformResourceIdentifierTag:
                    value = DERIA5String.getInstance(obj).getString();
                    break;
                default:
                    value = obj.toString();
                }

                List<Object> list = new LinkedList<Object>();

                list.add(generalName.getTagNo());
                list.add(value);

                altNames.add(list);
            }

            parseAltNames(altNames);
        }
    }

    public AltNamesInspector(X509Certificate certificate) throws IOException {
        this((ASN1Sequence) ASN1Utils.getExtensionValue(certificate, X509Extension.subjectAlternativeName.getId()));
    }

    private List<String> toStringList(List<?> items, List<String> list) {
        /* skip the first element because it contains the tag */
        for (int i = 1; i < items.size(); i++) {
            Object item = items.get(i);

            if (!(item instanceof String)) {
                logger.warn("String expected.");
                continue;
            }

            list.add((String) item);
        }

        return list;
    }

    private void parseOtherName(List<?> items) {
        /* not-yet implemented */
    }

    private void parseRFC822Name(List<?> items) {
        if ((Integer) items.get(0) != rfc822NameTag) {
            throw new IllegalStateException("rfc822NameTag expected.");
        }

        toStringList(items, rfc822Names);
    }

    private void parseDNSName(List<?> items) {
        if ((Integer) items.get(0) != dnsNameTag) {
            throw new IllegalStateException("dnsNameTag expected.");
        }

        toStringList(items, dnsNames);
    }

    private void parseX400Address(List<?> items) {
        /* not-yet implemented */
    }

    private void parseDirectoryName(List<?> items) {
        /* not-yet implemented */
    }

    private void parseEDIPatyName(List<?> items) {
        /* not-yet implemented */
    }

    private void parseUniformResourceIdentifier(List<?> items) {
        /* not-yet implemented */
    }

    private void parseIPAddress(List<?> items) {
        /* not-yet implemented */
    }

    private void parseRegisteredID(List<?> items) {
        /* not-yet implemented */
    }

    private void parseAltNames(Collection<List<?>> altNames) {
        if (altNames != null) {
            for (List<?> choice : altNames) {
                Object tagObject = choice.get(0);

                /* the tag object should be an integer */
                if (!(tagObject instanceof Integer)) {
                    logger.warn("The tag should be an integer");
                    continue;
                }
                int tag = (Integer) tagObject;

                switch (tag) {
                case otherNameTag:
                    parseOtherName(choice);
                    break;
                case rfc822NameTag:
                    parseRFC822Name(choice);
                    break;
                case dnsNameTag:
                    parseDNSName(choice);
                    break;
                case x400AddressTag:
                    parseX400Address(choice);
                    break;
                case directoryNameTag:
                    parseDirectoryName(choice);
                    break;
                case ediPartyNameTag:
                    parseEDIPatyName(choice);
                    break;
                case uniformResourceIdentifierTag:
                    parseUniformResourceIdentifier(choice);
                    break;
                case iPAddressTag:
                    parseIPAddress(choice);
                    break;
                case registeredIDTag:
                    parseRegisteredID(choice);
                    break;
                default:
                    logger.warn("Unknown tag: " + tag);
                }
            }
        }
    }

    public List<String> getRFC822Names() {
        return Collections.unmodifiableList(rfc822Names);
    }

    public List<String> getDNSNames() {
        return Collections.unmodifiableList(dnsNames);
    }
}