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

Java tutorial

Introduction

Here is the source code for mitm.common.security.certificate.GenerateTestCA.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 static org.junit.Assert.assertNotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.Set;
import java.util.TreeSet;

import javax.security.auth.x500.X500Principal;

import mitm.common.security.SecurityFactory;
import mitm.common.security.SecurityFactoryFactory;
import mitm.test.TestUtils;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.PropertyConfigurator;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.junit.BeforeClass;
import org.junit.Test;

public class GenerateTestCA {
    private static SecurityFactory securityFactory;
    private static KeyFactory keyFactory;
    private static KeyStore keyStore;

    private static X509Certificate rootCertificate;
    private static X509Certificate intermediateCertificate;

    private static PrivateKey rootPrivateKey;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        PropertyConfigurator.configure("conf/log4j.properties");

        securityFactory = SecurityFactoryFactory.getSecurityFactory();

        keyFactory = securityFactory.createKeyFactory("RSA");

        keyStore = securityFactory.createKeyStore("PKCS12");
    }

    private PrivateKey decodePrivateKey(String encoded) throws Exception {
        byte[] rawKey = Hex.decodeHex(encoded.toCharArray());

        KeySpec keySpec = new PKCS8EncodedKeySpec(rawKey);

        return keyFactory.generatePrivate(keySpec);
    }

    private PublicKey decodePublicKey(String encoded) throws Exception {
        byte[] rawKey = Hex.decodeHex(encoded.toCharArray());

        KeySpec keySpec = new X509EncodedKeySpec(rawKey);

        return keyFactory.generatePublic(keySpec);
    }

    private void generateRoot() throws Exception {
        X509CertificateBuilder certificateBuilder = securityFactory.createX509CertificateBuilder();

        String encodedPrivateKey = "308204bf020100300d06092a864886f70d0101010500048204a9308204a5"
                + "0201000282010100b7c0b5ac2250390fe9da9b800bdb0a1b7f21614d1e7c"
                + "5db67438a9d1f793c0cf0403a3523981f17885e145dbc0e4c927a184c024"
                + "6e7a79ae29f7ad4e1a36db1db567c793547b96a8275e93d37ad17006ca51"
                + "6f3ed4bfbff9883e2a351d8c5c76a24502344e8711e76843b3ba05f7a551"
                + "5287dba46b05033c7756b531512034845fc7ae350ebc720ed83e7df7ebd8"
                + "ade16b0d961c15277fd5802b724c3d9392a7e99d2d06bf55b5d2516152b1"
                + "d9c249561e3887f075e2bebe8e331cdc3fe5de60af36285e514b14163b34"
                + "af15e6bb48e6b232366f05d73ad261714854833305ba06f1430d5b0c8383"
                + "7c49c9408c8e4d674b9a9494a6b0dc66e0b4d2107d78f26f020301000102"
                + "82010100a857d3d8bca2f47420d1d74e6b0e2467668425496ad9935d5982"
                + "a40a29a062af05c573761c1b7126f2b89cb0a43ab61329c59de68294902f"
                + "c0611994092e22764840a8b5d05b5d7df67b8e40dc2f4e4bda44daff1c18"
                + "03ffcf12ecc636a8e5f905d6e51b18aa63fbb628f85a3fa74efc7ef8da7f"
                + "fa4fe054201cfee90ca2cd98be5ab0de6f631ac574433573a05f797a6c67"
                + "f5f2ebac8abe4acb64ea926971ec6055cd3fffee636146199932f6868fbe"
                + "e39eab7e93c97c930bc8a92c75714459c74d0dc44d6a33660aec06735fa1"
                + "65d18b3511e28a225b513865c881ceb7b968379119a54e4f92c37abfb110"
                + "f760a0e3bc1b6d57141a20877dbd46819686f4f902818100e9188525d800"
                + "37f73d4f3d90a330911820228c29f80a3a63fddb09df82766d6cfdb46bdd"
                + "d163b780246edda6a4e2ec5c65453740e6cd191702afc2178b13123031ae"
                + "fd384383825d8fa60024f9b78d9c9ff1bf6f53e49528e1aba515a91f8066"
                + "54cd9488092a8f730133340dcc402d0b2cea149a3a6fdb1702f1890462a8"
                + "8f6d02818100c9cef9be785397ffbda7df90d7e6bc1d5a607950c4323114"
                + "9636e0b6c0a5ebc281fd0027463cc858fb94f8084baa0f93f1f33f18c40d"
                + "8a47666b7190efff38f869229b8e84eea8fcd559b2349873d96e187b9933"
                + "35ae63034ec926c341eaede9ac696c4b6029969fbeb8194c9f2b44e2c831"
                + "bb7c3a07c1dd5cadbf81f9deb3cb02818073e7e96d63f6d7dd6cf3161df1"
                + "c7989e727c3b4e333482cc6dd2991a36f9447849bf895387671a3bf1e1de"
                + "fd9a47ec58155351a24821fc33e0f61c81307a8f34bfbfcfd2466002571b"
                + "b2e3a77f34b28a0b4e5e6eb13c9c9ef37832628ef2471a9b588e5f068fcf"
                + "3cd47fed865ee61a7fd019a59cfb29dbbb998f191ec1202811028181008e"
                + "753c1937a992f7e632b5fff2589fdc7caaf3988f16fb4c94096331bee6a1"
                + "79a9f725ff93765edb69a52c3df6e3b2a1763f86fffd8dad5a5fb362f4b4"
                + "664f1a146568b7ffa0d5cbbcf3d7778752e85eee8b79870bd2f174294e97"
                + "bd682fe608793be6458339786985e14182b42d803032afe0b07dea71f0c8"
                + "76a264a7358d6702818100b2a67f02d933b860a2675f616a8f163eea3ef9"
                + "d23bc29416fe8b02582635a56b3278af0d98a4a8d7367c1bf21cf06841b8"
                + "f5e7f53e08062d90355aa90c4ff4e07d3eb2a5d356a5b4617e2ff114db1c"
                + "3c429ffaa552264a670b24b12b372558997b8f1fbd6df41efac697c5c9f3"
                + "2571eef344416eb642818b3886a16ec45381a3";

        String encodedPublicKey = "30820122300d06092a864886f70d01010105000382010f003082010a0282"
                + "010100b7c0b5ac2250390fe9da9b800bdb0a1b7f21614d1e7c5db67438a9"
                + "d1f793c0cf0403a3523981f17885e145dbc0e4c927a184c0246e7a79ae29"
                + "f7ad4e1a36db1db567c793547b96a8275e93d37ad17006ca516f3ed4bfbf"
                + "f9883e2a351d8c5c76a24502344e8711e76843b3ba05f7a5515287dba46b"
                + "05033c7756b531512034845fc7ae350ebc720ed83e7df7ebd8ade16b0d96"
                + "1c15277fd5802b724c3d9392a7e99d2d06bf55b5d2516152b1d9c249561e"
                + "3887f075e2bebe8e331cdc3fe5de60af36285e514b14163b34af15e6bb48"
                + "e6b232366f05d73ad261714854833305ba06f1430d5b0c83837c49c9408c"
                + "8e4d674b9a9494a6b0dc66e0b4d2107d78f26f0203010001";

        PrivateKey privateKey = decodePrivateKey(encodedPrivateKey);
        PublicKey publicKey = decodePublicKey(encodedPublicKey);

        X500PrincipalBuilder issuerBuilder = new X500PrincipalBuilder();

        String email = "root@example.com";

        issuerBuilder.setCommonName("MITM Test Root");
        issuerBuilder.setCountryCode("NL");
        issuerBuilder.setEmail(email);
        issuerBuilder.setLocality("Amsterdam");
        issuerBuilder.setState("NH");

        AltNamesBuilder altNamesBuider = new AltNamesBuilder();

        altNamesBuider.setRFC822Names(email);

        X500Principal issuer = issuerBuilder.buildPrincipal();
        GeneralNames altNames = altNamesBuider.buildAltNames();

        // use TreeSet because we want a deterministic certificate (ie. hash should not change)
        Set<KeyUsageType> keyUsage = new TreeSet<KeyUsageType>();

        keyUsage.add(KeyUsageType.KEYCERTSIGN);
        keyUsage.add(KeyUsageType.CRLSIGN);

        Set<ExtendedKeyUsageType> extendedKeyUsage = new TreeSet<ExtendedKeyUsageType>();

        extendedKeyUsage.add(ExtendedKeyUsageType.EMAILPROTECTION);
        extendedKeyUsage.add(ExtendedKeyUsageType.OCSPSIGNING);

        BigInteger serialNumber = new BigInteger("115fcac409fb2022b7d06920a00fe42", 16);

        Date now = TestUtils.parseDate("16-Nov-2007 07:38:35 GMT");

        certificateBuilder.setSubject(issuer);
        certificateBuilder.setIssuer(issuer);
        certificateBuilder.setAltNames(altNames, true);
        certificateBuilder.setKeyUsage(keyUsage, true);
        certificateBuilder.setExtendedKeyUsage(extendedKeyUsage, false);
        certificateBuilder.setNotBefore(DateUtils.addDays(now, -20));
        certificateBuilder.setNotAfter(DateUtils.addYears(now, 20));
        certificateBuilder.setPublicKey(publicKey);
        certificateBuilder.setSerialNumber(serialNumber);
        certificateBuilder.setSignatureAlgorithm("SHA1WithRSAEncryption");
        certificateBuilder.setIsCA(true, true);
        certificateBuilder.addSubjectKeyIdentifier(true);

        // generate self signed certificate
        rootCertificate = certificateBuilder.generateCertificate(privateKey, null);

        assertNotNull(rootCertificate);

        Certificate[] chain = new Certificate[] { rootCertificate };

        keyStore.setKeyEntry("root", privateKey, null, chain);

        rootPrivateKey = privateKey;
    }

    private void generateIntermediate() throws Exception {
        assertNotNull(rootCertificate);
        assertNotNull(rootPrivateKey);

        X509CertificateBuilder certificateBuilder = securityFactory.createX509CertificateBuilder();

        String encodedPrivateKey = "30820275020100300d06092a864886f70d01010105000482025f3082025b"
                + "02010002818100885ea4a4890e6ceee8cca888bf9a95954217bf5f13a0c2"
                + "07f15d1e1e23eb72742c0c5fa1e9b5c68d91d2c8ad85a194f9396c751ead"
                + "6d4d015568260eb03a1e4ceae77ea7995f2e301443a5ccb1d37c09715dd7"
                + "f43445728583cc8eb3331c021ed11afd60a5286ca0bb33fb236ee61ac291"
                + "d5c3e5bb8fdf95dc4bc3b4a7391d070203010001028180380f18059f65f3"
                + "b7feb16b32d3f93b36a175dbb0bd03dfdf9e0416867363ada83e175414de"
                + "5b606500263362c9c553d5641ac6c6b6aa70f674629d0a7abd5988d16f2f"
                + "4f3abaf16c1a95bee5a7f95b3349185f0d43e60bce272fb8575540469306"
                + "072d1aad5efd286322763f9c4129adc9e1fe1a32cb3405fcd55c21007ee3"
                + "31024100c14b80e4f08ca60070eff8d0e2e15ee08c8eeb0c6d73b845b522"
                + "8a014d2f519ab70da6d2a26958f361b95e6905a9f2a2d025cbe18c85bf4c"
                + "f272642956b0444f024100b49bb08a8c5efbb45637b24f8160f996346e4e"
                + "2055a0235c775487f7ca813af38eb0b57e39155a2bb52607727bda1f6934"
                + "20001c45dea066db3da907f7f715c90240710564e8787ec4d19d37b394f0"
                + "143715b51a1bf5b849e18560d4413d61943972ed75de056b518de14152d2"
                + "11366e98a0fa741f3252a821a32c601690d54f5ba102407afa7c468af86e"
                + "29c87f5a521ac5be8d519c3e6474097baa8db2a876c894206111ab2f9a08"
                + "228ae8b20b780cb35abe02b3b48a7eb5f0b685f309545c91b2d44902403d"
                + "cca6f96e93dfd0db083ad41eb22ea8a34a7ecd617357ceb02b653f76f39b"
                + "32b0ea3d7596760f00bb45969d3ccd131c63bb9d1b803c73839ee37e52e1" + "b27e1d";

        String encodedPublicKey = "30819f300d06092a864886f70d010101050003818d003081890281810088"
                + "5ea4a4890e6ceee8cca888bf9a95954217bf5f13a0c207f15d1e1e23eb72"
                + "742c0c5fa1e9b5c68d91d2c8ad85a194f9396c751ead6d4d015568260eb0"
                + "3a1e4ceae77ea7995f2e301443a5ccb1d37c09715dd7f43445728583cc8e"
                + "b3331c021ed11afd60a5286ca0bb33fb236ee61ac291d5c3e5bb8fdf95dc" + "4bc3b4a7391d070203010001";

        PrivateKey privateKey = decodePrivateKey(encodedPrivateKey);
        PublicKey publicKey = decodePublicKey(encodedPublicKey);

        X500PrincipalBuilder subjectBuilder = new X500PrincipalBuilder();

        String email = "ca@example.com";

        subjectBuilder.setCommonName("MITM Test CA");
        subjectBuilder.setCountryCode("NL");
        subjectBuilder.setEmail(email);
        subjectBuilder.setLocality("Amsterdam");
        subjectBuilder.setState("NH");

        AltNamesBuilder altNamesBuider = new AltNamesBuilder();

        altNamesBuider.setRFC822Names(email);

        X500Principal subject = subjectBuilder.buildPrincipal();
        GeneralNames altNames = altNamesBuider.buildAltNames();

        Set<KeyUsageType> keyUsage = new TreeSet<KeyUsageType>();

        keyUsage.add(KeyUsageType.KEYCERTSIGN);
        keyUsage.add(KeyUsageType.CRLSIGN);

        Set<ExtendedKeyUsageType> extendedKeyUsage = new TreeSet<ExtendedKeyUsageType>();

        extendedKeyUsage.add(ExtendedKeyUsageType.EMAILPROTECTION);
        extendedKeyUsage.add(ExtendedKeyUsageType.OCSPSIGNING);

        BigInteger serialNumber = new BigInteger("115fcad6b536fd8d49e72922cd1f0da", 16);

        Date now = TestUtils.parseDate("21-Nov-2007 07:38:35 GMT");

        X500Principal issuer = rootCertificate.getSubjectX500Principal();

        certificateBuilder.setSubject(subject);
        certificateBuilder.setIssuer(issuer);
        certificateBuilder.setAltNames(altNames, true);
        certificateBuilder.setKeyUsage(keyUsage, true);
        certificateBuilder.setExtendedKeyUsage(extendedKeyUsage, false);
        certificateBuilder.setNotBefore(DateUtils.addDays(now, -20));
        certificateBuilder.setNotAfter(DateUtils.addYears(now, 20));
        certificateBuilder.setPublicKey(publicKey);
        certificateBuilder.setSerialNumber(serialNumber);
        certificateBuilder.setSignatureAlgorithm("SHA1WithRSAEncryption");
        certificateBuilder.setIsCA(true, true);
        certificateBuilder.addSubjectKeyIdentifier(true);

        // generate certificate signed by root
        intermediateCertificate = certificateBuilder.generateCertificate(rootPrivateKey, rootCertificate);

        assertNotNull(intermediateCertificate);

        Certificate[] chain = new Certificate[] { intermediateCertificate, rootCertificate };

        keyStore.setKeyEntry("ca", privateKey, null, chain);
    }

    @Test
    public void testGenerateTestCA() throws Exception {
        // initialize key store
        keyStore.load(null);

        generateRoot();
        generateIntermediate();

        File p12File = new File("test/tmp/testCA.p12");

        FileOutputStream output = new FileOutputStream(p12File);

        keyStore.store(output, "test".toCharArray());

        CertificateUtils.writeCertificate(rootCertificate, new File("test/tmp/mitm-test-root.cer"));
        CertificateUtils.writeCertificate(intermediateCertificate, new File("test/tmp/mitm-test-ca.cer"));
    }
}