Java tutorial
/* * 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")); } }