]> source.dussan.org Git - gitblit.git/commitdiff
Automatically generate a self-signed certificate with BouncyCastle.
authorJames Moger <james.moger@gitblit.com>
Thu, 5 May 2011 22:40:39 +0000 (18:40 -0400)
committerJames Moger <james.moger@gitblit.com>
Thu, 5 May 2011 22:40:39 +0000 (18:40 -0400)
.classpath
src/com/gitblit/Build.java
src/com/gitblit/GitBlitServer.java

index 26484c28063126cb6d1274ac93be64c96d4cb5be..5cddd2099e8797d9730e7b5e5ea830334457db05 100644 (file)
                        <attribute name="javadoc_location" value="jar:platform:/resource/gitblit/ext/bcprov-jdk16-1.46-javadoc.jar!/"/>\r
                </attributes>\r
        </classpathentry>\r
+       <classpathentry kind="lib" path="ext/bcmail-jdk16-1.46.jar" sourcepath="ext/bcmail-jdk16-1.46-sources.jar">\r
+               <attributes>\r
+                       <attribute name="javadoc_location" value="jar:platform:/resource/gitblit/ext/bcmail-jdk16-1.46-javadoc.jar!/"/>\r
+               </attributes>\r
+       </classpathentry>\r
        <classpathentry kind="output" path="bin"/>\r
 </classpath>\r
index 8b7fe3c1cc0d5167c180db6a0a35ac83f9423572..89527260c612769b97b8c33c89c40bff595079e5 100644 (file)
@@ -43,6 +43,7 @@ public class Build {
                downloadFromApache(MavenObject.WICKET_GOOGLE_CHARTS, BuildType.RUNTIME);\r
                downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.RUNTIME);\r
                downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.RUNTIME);\r
+               downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.RUNTIME);\r
 \r
                downloadFromEclipse(MavenObject.JGIT, BuildType.RUNTIME);\r
                downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.RUNTIME);\r
@@ -62,6 +63,7 @@ public class Build {
                downloadFromApache(MavenObject.WICKET_GOOGLE_CHARTS, BuildType.COMPILETIME);\r
                downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.COMPILETIME);\r
                downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.COMPILETIME);\r
+               downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.COMPILETIME);\r
                \r
                downloadFromEclipse(MavenObject.JGIT, BuildType.COMPILETIME);\r
                downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.COMPILETIME);\r
@@ -289,6 +291,8 @@ public class Build {
                public static final MavenObject MARKDOWNPAPERS = new MavenObject("MarkdownPapers", "org/tautua/markdownpapers", "markdownpapers-core", "1.0.0", 87000, 58000, 278000, "feda63bd149f3315da210e397d45d02277038ad5", "a9a6c4d163af81e265a15138fcaeafa9829c6054", "f932656266a7f9593488d3f89e815d0af44d0853");\r
                \r
                public static final MavenObject BOUNCYCASTLE = new MavenObject("BouncyCastle", "org/bouncycastle", "bcprov-jdk16", "1.46", 1900000, 1400000, 4670000, "ce091790943599535cbb4de8ede84535b0c1260c", "d2b70567594225923450d7e3f80cd022c852725e", "873a6fe765f33fc27df498a5d1f5bf077e503b2f");\r
+               \r
+               public static final MavenObject BOUNCYCASTLE_MAIL = new MavenObject("BouncyCastle Mail", "org/bouncycastle", "bcmail-jdk16", "1.46", 502000, 420000, 482000, "08a9233bfd6ad38ea32df5e6ff91035b650584b9", "3ebd62bc56854767512dc5deec0a17795f2e671d", "3b7c5f3938f202311bdca0bf7ed46bc0118af081");\r
 \r
                public static final MavenObject JGIT = new MavenObject("JGit", "org/eclipse/jgit", "org.eclipse.jgit", "0.12.1", 1318000, 1354000, 2993000, "fd77699699b9651d2fc31c7ed63af98b14fc1975", "c8b3d84922c7802cfe6a661e13a002641a78583d", "5609aa3ce3ac3d52030befd27ddd2941f6c07570");\r
 \r
index 9a9f63e20ff1c5273851e7470b613c91ad7e1135..b5acd3df2a7183d0062d625e58e5cf4e5874d545 100644 (file)
@@ -2,23 +2,40 @@ package com.gitblit;
 \r
 import java.io.BufferedReader;\r
 import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
 import java.io.IOException;\r
 import java.io.InputStreamReader;\r
 import java.io.OutputStream;\r
+import java.math.BigInteger;\r
 import java.net.InetAddress;\r
 import java.net.ServerSocket;\r
 import java.net.Socket;\r
 import java.net.URL;\r
 import java.net.UnknownHostException;\r
+import java.security.KeyPair;\r
+import java.security.KeyPairGenerator;\r
+import java.security.KeyStore;\r
 import java.security.ProtectionDomain;\r
+import java.security.SecureRandom;\r
+import java.security.Security;\r
+import java.security.cert.X509Certificate;\r
 import java.text.MessageFormat;\r
 import java.util.ArrayList;\r
+import java.util.Date;\r
 import java.util.List;\r
 \r
 import org.apache.log4j.ConsoleAppender;\r
 import org.apache.log4j.PatternLayout;\r
 import org.apache.wicket.protocol.http.ContextParamWebApplicationFactory;\r
 import org.apache.wicket.protocol.http.WicketFilter;\r
+import org.bouncycastle.asn1.x500.X500NameBuilder;\r
+import org.bouncycastle.asn1.x500.style.BCStyle;\r
+import org.bouncycastle.cert.X509v3CertificateBuilder;\r
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;\r
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;\r
+import org.bouncycastle.operator.ContentSigner;\r
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;\r
 import org.eclipse.jetty.http.security.Constraint;\r
 import org.eclipse.jetty.security.ConstraintMapping;\r
 import org.eclipse.jetty.security.ConstraintSecurityHandler;\r
@@ -144,23 +161,28 @@ public class GitBlitServer {
                        Connector httpConnector = createConnector(params.useNIO, params.port);\r
                        String bindInterface = fileSettings.getString(Keys.server.httpBindInterface, null);\r
                        if (!StringUtils.isEmpty(bindInterface)) {\r
-                               logger.warn(MessageFormat.format("Binding port {0} to {1}", params.port, bindInterface));\r
+                               logger.warn(MessageFormat.format("Binding connector on port {0} to {1}", params.port, bindInterface));\r
                                httpConnector.setHost(bindInterface);\r
                        }\r
                        connectors.add(httpConnector);\r
                }\r
 \r
                if (params.securePort > 0) {\r
-                       if (new File("keystore").exists()) {\r
-                               Connector secureConnector = createSSLConnector(params.useNIO, params.securePort, params.storePassword);\r
+                       File keystore = new File("keystore");\r
+                       if (!keystore.exists()) {\r
+                               logger.info("Generating self-signed ssl certificate");\r
+                               generateSelfSignedCertificate("localhost", keystore, params.storePassword);\r
+                       }\r
+                       if (keystore.exists()) {\r
+                               Connector secureConnector = createSSLConnector(keystore, params.storePassword, params.useNIO, params.securePort);\r
                                String bindInterface = fileSettings.getString(Keys.server.httpsBindInterface, null);\r
                                if (!StringUtils.isEmpty(bindInterface)) {\r
-                                       logger.warn(MessageFormat.format("Binding port {0} to {1}", params.port, bindInterface));\r
+                                       logger.warn(MessageFormat.format("Binding ssl connector on port {0} to {1}", params.securePort, bindInterface));\r
                                        secureConnector.setHost(bindInterface);\r
                                }\r
                                connectors.add(secureConnector);\r
                        } else {\r
-                               logger.warn("Failed to find Keystore?  Did you run \"makekeystore\"?");\r
+                               logger.warn("Failed to find or load Keystore?");\r
                                logger.warn("SSL connector DISABLED.");\r
                        }\r
                }\r
@@ -296,25 +318,68 @@ public class GitBlitServer {
                return connector;\r
        }\r
 \r
-       private static Connector createSSLConnector(boolean useNIO, int port, String password) {\r
+       private static Connector createSSLConnector(File keystore, String password, boolean useNIO, int port) {\r
                SslConnector connector;\r
                if (useNIO) {\r
                        logger.info("Setting up NIO SslSelectChannelConnector on port " + port);\r
                        SslSelectChannelConnector ssl = new SslSelectChannelConnector();\r
                        ssl.setSoLingerTime(-1);\r
-                       ssl.setThreadPool(new QueuedThreadPool(20));\r
+                       ssl.setThreadPool(new QueuedThreadPool(20));                    \r
                        connector = ssl;\r
                } else {\r
                        logger.info("Setting up NIO SslSocketConnector on port " + port);\r
                        SslSocketConnector ssl = new SslSocketConnector();\r
                        connector = ssl;\r
                }\r
-               connector.setKeystore("keystore");\r
+               connector.setAllowRenegotiate(true);\r
+               connector.setKeystore(keystore.getAbsolutePath());\r
                connector.setPassword(password);\r
                connector.setPort(port);\r
                connector.setMaxIdleTime(30000);\r
                return connector;\r
        }\r
+       \r
+       private static void generateSelfSignedCertificate(String hostname, File keystore, String keystorePassword) {\r
+               try {\r
+                       Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());\r
+\r
+                       final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;\r
+                       \r
+                       KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");\r
+                       kpGen.initialize(1024, new SecureRandom());\r
+                       KeyPair pair = kpGen.generateKeyPair();\r
+\r
+                       // Generate self-signed certificate\r
+                       X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);\r
+                       builder.addRDN(BCStyle.OU, Constants.NAME);\r
+                       builder.addRDN(BCStyle.O, Constants.NAME);\r
+                       builder.addRDN(BCStyle.CN, hostname);\r
+\r
+                       Date notBefore = new Date(System.currentTimeMillis() - 1*24*60*60*1000l);\r
+                       Date notAfter = new Date(System.currentTimeMillis() + 10*365*24*60*60*1000l);\r
+                       BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());\r
+\r
+                       X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), serial, notBefore, notAfter, builder.build(), pair.getPublic());\r
+                       ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(pair.getPrivate());\r
+                       X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));\r
+                       cert.checkValidity(new Date());\r
+                       cert.verify(cert.getPublicKey());\r
+\r
+                       // Save to keystore                     \r
+                       KeyStore store = KeyStore.getInstance("JKS");\r
+                       if (keystore.exists()) {\r
+                               FileInputStream fis = new FileInputStream(keystore);\r
+                               store.load(fis, keystorePassword.toCharArray());\r
+                       } else {\r
+                               store.load(null);\r
+                       }\r
+                       store.setKeyEntry(hostname, pair.getPrivate(), keystorePassword.toCharArray(), new java.security.cert.Certificate[] { cert });\r
+                       store.store(new FileOutputStream(keystore), keystorePassword.toCharArray());\r
+               } catch (Throwable t) {\r
+                       t.printStackTrace();\r
+                       throw new RuntimeException("Failed to generate self-signed certificate!", t);\r
+               }\r
+       }\r
 \r
        /**\r
         * Recursively delete a folder and its contents.\r