James Moger
2012-09-10 fabe060d3a435f116128851f828e35c2af5fde67
commit | author | age
f13c4c 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
a92997 16 package com.gitblit;
JM 17
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.FileOutputStream;
21 import java.math.BigInteger;
22 import java.security.KeyPair;
23 import java.security.KeyPairGenerator;
24 import java.security.KeyStore;
25 import java.security.SecureRandom;
26 import java.security.Security;
27 import java.security.cert.X509Certificate;
28 import java.util.Date;
29
30 import javax.security.auth.x500.X500Principal;
31
32 import org.bouncycastle.asn1.x500.X500NameBuilder;
33 import org.bouncycastle.asn1.x500.style.BCStyle;
34 import org.bouncycastle.cert.X509v3CertificateBuilder;
35 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
36 import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
37 import org.bouncycastle.operator.ContentSigner;
38 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
39
40 import com.beust.jcommander.JCommander;
41 import com.beust.jcommander.Parameter;
42 import com.beust.jcommander.ParameterException;
43 import com.beust.jcommander.Parameters;
2a7306 44 import com.gitblit.utils.TimeUtils;
a92997 45
892570 46 /**
JM 47  * Utility class to generate self-signed certificates.
48  * 
49  * @author James Moger
88598b 50  * 
892570 51  */
a92997 52 public class MakeCertificate {
db653a 53
2a7306 54     private static final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
a92997 55
JM 56     public static void main(String... args) {
57         Params params = new Params();
58         JCommander jc = new JCommander(params);
59         try {
60             jc.parse(args);
61         } catch (ParameterException t) {
2a7306 62             System.err.println(t.getMessage());
a92997 63             jc.usage();
JM 64         }
65         File keystore = new File("keystore");
88598b 66         generateSelfSignedCertificate(params.hostname, keystore, params.storePassword,
JM 67                 params.subject);
a92997 68     }
2a7306 69
JM 70     public static void generateSelfSignedCertificate(String hostname, File keystore,
71             String keystorePassword) {
a92997 72         try {
JM 73             Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
74
75             KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
76             kpGen.initialize(1024, new SecureRandom());
77             KeyPair pair = kpGen.generateKeyPair();
78
79             // Generate self-signed certificate
80             X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
81             builder.addRDN(BCStyle.OU, Constants.NAME);
82             builder.addRDN(BCStyle.O, Constants.NAME);
83             builder.addRDN(BCStyle.CN, hostname);
84
2a7306 85             Date notBefore = new Date(System.currentTimeMillis() - TimeUtils.ONEDAY);
JM 86             Date notAfter = new Date(System.currentTimeMillis() + 10 * TimeUtils.ONEYEAR);
a92997 87             BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
JM 88
2a7306 89             X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),
JM 90                     serial, notBefore, notAfter, builder.build(), pair.getPublic());
91             ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
92                     .setProvider(BC).build(pair.getPrivate());
93             X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC)
94                     .getCertificate(certGen.build(sigGen));
a92997 95             cert.checkValidity(new Date());
JM 96             cert.verify(cert.getPublicKey());
97
2a7306 98             // Save to keystore
a92997 99             KeyStore store = KeyStore.getInstance("JKS");
JM 100             if (keystore.exists()) {
101                 FileInputStream fis = new FileInputStream(keystore);
102                 store.load(fis, keystorePassword.toCharArray());
2a7306 103                 fis.close();
a92997 104             } else {
JM 105                 store.load(null);
106             }
2a7306 107             store.setKeyEntry(hostname, pair.getPrivate(), keystorePassword.toCharArray(),
JM 108                     new java.security.cert.Certificate[] { cert });
109             FileOutputStream fos = new FileOutputStream(keystore);
110             store.store(fos, keystorePassword.toCharArray());
111             fos.close();
a92997 112         } catch (Throwable t) {
JM 113             t.printStackTrace();
114             throw new RuntimeException("Failed to generate self-signed certificate!", t);
115         }
116     }
2a7306 117
JM 118     public static void generateSelfSignedCertificate(String hostname, File keystore,
119             String keystorePassword, String info) {
a92997 120         try {
JM 121             Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
122
123             KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
124             kpGen.initialize(1024, new SecureRandom());
125             KeyPair pair = kpGen.generateKeyPair();
126
127             // Generate self-signed certificate
128             X500Principal principal = new X500Principal(info);
2a7306 129
JM 130             Date notBefore = new Date(System.currentTimeMillis() - TimeUtils.ONEDAY);
131             Date notAfter = new Date(System.currentTimeMillis() + 10 * TimeUtils.ONEYEAR);
a92997 132             BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
JM 133
2a7306 134             X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(principal, serial,
JM 135                     notBefore, notAfter, principal, pair.getPublic());
136             ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
137                     .setProvider(BC).build(pair.getPrivate());
138             X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC)
139                     .getCertificate(certGen.build(sigGen));
a92997 140             cert.checkValidity(new Date());
JM 141             cert.verify(cert.getPublicKey());
142
2a7306 143             // Save to keystore
a92997 144             KeyStore store = KeyStore.getInstance("JKS");
JM 145             if (keystore.exists()) {
146                 FileInputStream fis = new FileInputStream(keystore);
147                 store.load(fis, keystorePassword.toCharArray());
2a7306 148                 fis.close();
a92997 149             } else {
JM 150                 store.load(null);
151             }
2a7306 152             store.setKeyEntry(hostname, pair.getPrivate(), keystorePassword.toCharArray(),
JM 153                     new java.security.cert.Certificate[] { cert });
154             FileOutputStream fos = new FileOutputStream(keystore);
155             store.store(fos, keystorePassword.toCharArray());
156             fos.close();
a92997 157         } catch (Throwable t) {
JM 158             t.printStackTrace();
159             throw new RuntimeException("Failed to generate self-signed certificate!", t);
160         }
161     }
2a7306 162
88598b 163     /**
JM 164      * JCommander Parameters class for MakeCertificate.
165      */
a92997 166     @Parameters(separators = " ")
JM 167     private static class Params {
168
28d6b2 169         private static final FileSettings FILESETTINGS = new FileSettings(Constants.PROPERTIES_FILE);
db653a 170
d39680 171         @Parameter(names = { "--hostname" }, description = "Server Hostname", required = true)
JM 172         public String hostname;
2a7306 173
a92997 174         @Parameter(names = { "--subject" }, description = "Certificate subject", required = true)
2a7306 175         public String subject;
a92997 176
JM 177         @Parameter(names = "--storePassword", description = "Password for SSL (https) keystore.")
2a7306 178         public String storePassword = FILESETTINGS.getString(Keys.server.storePassword, "");
a92997 179     }
JM 180 }