Browse Source

Revised Gitblit GO certificate generation to use new X509 utility functions

tags/v1.2.0
James Moger 11 years ago
parent
commit
d8a0f1e6e9

+ 7
- 4
.gitignore View File

@@ -25,7 +25,10 @@
/build-demo.xml
/users.conf
*.directory
/.gradle
/projects.conf
/pom.xml
/deploy
/.gradle
/projects.conf
/pom.xml
/deploy
/*.jks
/x509test
/certs

+ 18
- 0
build.xml View File

@@ -111,6 +111,14 @@
<include name="users.conf" />
</fileset>
</copy>
<!-- copy required distribution files to project folder -->
<mkdir dir="${basedir}/certs" />
<copy todir="${basedir}/certs" overwrite="false">
<fileset dir="${basedir}/distrib">
<include name="authority.conf" />
</fileset>
</copy>
<!-- copy gitblit.properties to the WEB-INF folder.
this file is only used for parsing setting descriptions. -->
@@ -174,10 +182,20 @@
<include name="**/*" />
<exclude name="federation.properties" />
<exclude name="openshift.mkd" />
<exclude name="authority.conf" />
</fileset>
<fileset dir="${basedir}">
<include name="LICENSE" />
<include name="NOTICE" />
<include name="authority*.jar" />
</fileset>
</copy>
<!-- Certificate templates -->
<mkdir dir="${project.deploy.dir}/certs"/>
<copy todir="${project.deploy.dir}/certs">
<fileset dir="${basedir}/distrib">
<include name="authority.conf" />
</fileset>
</copy>

+ 6
- 0
distrib/authority.conf View File

@@ -0,0 +1,6 @@
[new]
duration = 365
organizationalUnit = Gitblit
organization = Gitblit
locality = Gitblit
stateProvince = NY

+ 14
- 0
distrib/gitblit.properties View File

@@ -1137,6 +1137,20 @@ server.ajpBindInterface = localhost
# RESTART REQUIRED
server.storePassword = gitblit
# If serving over https (recommended) you might consider requiring clients to
# authenticate with ssl certificates. If enabled, only https clients with the
# a valid client certificate will be able to access Gitblit.
#
# If disabled, client certificate authentication is optional and will be tried
# first before falling-back to form authentication or basic authentication.
#
# Requiring client certificates to access any of Gitblit may be too extreme,
# consider this carefully.
#
# SINCE 1.2.0
# RESTART REQUIRED
server.requireClientCertificates = false
# Port for shutdown monitor to listen on.
#
# SINCE 0.5.0

+ 1
- 1
distrib/makekeystore.cmd View File

@@ -2,5 +2,5 @@
@REM Set HOSTNAME to the server's hostname
@REM --------------------------------------------------------------------------
@SET HOSTNAME=localhost
@del keystore
@del serverKeyStore.jks
@java -cp gitblit.jar;"%CD%\ext\*" com.gitblit.MakeCertificate --hostname %HOSTNAME% --subject "CN=%HOSTNAME%, OU=Gitblit, O=Gitblit, L=Some Town, ST=Some State, C=US"

+ 2
- 2
distrib/makekeystore_jdk.cmd View File

@@ -2,5 +2,5 @@
@REM Set HOSTNAME to the server's hostname
@REM --------------------------------------------------------------------------
@SET HOSTNAME=localhost
@del keystore
@keytool -keystore keystore -alias %HOSTNAME% -genkey -keyalg RSA -dname "CN=%HOSTNAME%, OU=Gitblit, O=Gitblit, L=Some Town, ST=Some State, C=US"
@del serverKeyStore.jks
@keytool -keystore serverKeyStore.jks -alias %HOSTNAME% -genkey -keyalg RSA -dname "CN=%HOSTNAME%, OU=Gitblit, O=Gitblit, L=Some Town, ST=Some State, C=US"

+ 4
- 0
docs/04_releases.mkd View File

@@ -52,6 +52,10 @@ You can require all git servlet access be authenticated by a client certificate.
**New:** *git.requireClientCertificates = false*
**New:** *git.enforceCertificateValidity = true*
**New:** *git.certificateUsernameOIDs = CN*
- Revised clean install certificate generation to create a Gitblit GO Certificate Authority certificate; an SSL certificate signed by the CA certificate; and to create distinct server key and server trust stores. <u>The store files have been renamed!</u>
- Added support for Gitblit GO to require usage of client certificates to access the entire server.
This is extreme and should be considered carefully since it affects every https access. The default is to **want** client certificates. Setting this value to *true* changes that to **need** client certificates.
**New:** *server.requireClientCertificates = false*
- Added setting to control length of shortened commit ids
**New:** *web.shortCommitIdLength=8*
- Added simple project pages. A project is a subfolder off the *git.repositoriesFolder*.

+ 58
- 17
src/com/gitblit/GitBlitServer.java View File

@@ -29,6 +29,7 @@ import java.net.UnknownHostException;
import java.security.ProtectionDomain;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Scanner;
@@ -41,8 +42,11 @@ import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.ssl.SslConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,7 +55,11 @@ import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.Parameters;
import com.gitblit.authority.NewCertificateConfig;
import com.gitblit.utils.StringUtils;
import com.gitblit.utils.TimeUtils;
import com.gitblit.utils.X509Utils;
import com.gitblit.utils.X509Utils.X509Metadata;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
@@ -186,15 +194,32 @@ public class GitBlitServer {
// conditionally configure the https connector
if (params.securePort > 0) {
File keystore = new File("keystore");
if (!keystore.exists()) {
logger.info("Generating self-signed SSL certificate for localhost");
MakeCertificate.generateSelfSignedCertificate("localhost", keystore,
params.storePassword);
File folder = new File(System.getProperty("user.dir"));
File certificatesConf = new File(folder, X509Utils.CA_CONFIG);
File serverKeyStore = new File(folder, X509Utils.SERVER_KEY_STORE);
File serverTrustStore = new File(folder, X509Utils.SERVER_TRUST_STORE);
File caRevocationList = new File(folder, X509Utils.CA_REVOCATION_LIST);
// generate CA & web certificates, create certificate stores
X509Metadata metadata = new X509Metadata("localhost", params.storePassword);
// set default certificate values from config file
if (certificatesConf.exists()) {
FileBasedConfig config = new FileBasedConfig(certificatesConf, FS.detect());
try {
config.load();
} catch (Exception e) {
logger.error("Error parsing " + certificatesConf, e);
}
NewCertificateConfig certificateConfig = NewCertificateConfig.KEY.parse(config);
certificateConfig.update(metadata);
}
if (keystore.exists()) {
Connector secureConnector = createSSLConnector(keystore, params.storePassword,
params.useNIO, params.securePort);
metadata.notAfter = new Date(System.currentTimeMillis() + 10*TimeUtils.ONEYEAR);
X509Utils.prepareX509Infrastructure(metadata, folder);
if (serverKeyStore.exists()) {
Connector secureConnector = createSSLConnector(serverKeyStore, serverTrustStore, params.storePassword,
caRevocationList, params.useNIO, params.securePort, params.requireClientCertificates);
String bindInterface = settings.getString(Keys.server.httpsBindInterface, null);
if (!StringUtils.isEmpty(bindInterface)) {
logger.warn(MessageFormat.format(
@@ -364,24 +389,34 @@ public class GitBlitServer {
* SSL renegotiation will be enabled if the JVM is 1.6.0_22 or later.
* oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html
*
* @param keystore
* @param password
* @param keyStore
* @param clientTrustStore
* @param storePassword
* @param caRevocationList
* @param useNIO
* @param port
* @param requireClientCertificates
* @return an https connector
*/
private static Connector createSSLConnector(File keystore, String password, boolean useNIO,
int port) {
private static Connector createSSLConnector(File keyStore, File clientTrustStore,
String storePassword, File caRevocationList, boolean useNIO, int port,
boolean requireClientCertificates) {
SslContextFactory sslContext = new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH);
SslConnector connector;
if (useNIO) {
logger.info("Setting up NIO SslSelectChannelConnector on port " + port);
SslSelectChannelConnector ssl = new SslSelectChannelConnector();
SslSelectChannelConnector ssl = new SslSelectChannelConnector(sslContext);
ssl.setSoLingerTime(-1);
if (requireClientCertificates) {
sslContext.setNeedClientAuth(true);
} else {
sslContext.setWantClientAuth(true);
}
ssl.setThreadPool(new QueuedThreadPool(20));
connector = ssl;
} else {
logger.info("Setting up NIO SslSocketConnector on port " + port);
SslSocketConnector ssl = new SslSocketConnector();
SslSocketConnector ssl = new SslSocketConnector(sslContext);
connector = ssl;
}
// disable renegotiation unless this is a patched JVM
@@ -400,10 +435,13 @@ public class GitBlitServer {
}
if (allowRenegotiation) {
logger.info(" allowing SSL renegotiation on Java " + v);
connector.setAllowRenegotiate(allowRenegotiation);
sslContext.setAllowRenegotiate(allowRenegotiation);
}
connector.setKeystore(keystore.getAbsolutePath());
connector.setPassword(password);
sslContext.setKeyStorePath(keyStore.getAbsolutePath());
sslContext.setKeyStorePassword(storePassword);
sslContext.setTrustStore(clientTrustStore.getAbsolutePath());
sslContext.setTrustStorePassword(storePassword);
sslContext.setCrlPath(caRevocationList.getAbsolutePath());
connector.setPort(port);
connector.setMaxIdleTime(30000);
return connector;
@@ -540,6 +578,9 @@ public class GitBlitServer {
@Parameter(names = "--shutdownPort", description = "Port for Shutdown Monitor to listen on. (port <= 0 will disable this monitor)")
public Integer shutdownPort = FILESETTINGS.getInteger(Keys.server.shutdownPort, 8081);
@Parameter(names = "--requireClientCertificates", description = "Require client X509 certificates for https connections.")
public Boolean requireClientCertificates = FILESETTINGS.getBoolean(Keys.server.requireClientCertificates, false);
/*
* Setting overrides
*/

+ 2
- 52
src/com/gitblit/MakeCertificate.java View File

@@ -29,8 +29,6 @@ import java.util.Date;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
@@ -62,65 +60,17 @@ public class MakeCertificate {
System.err.println(t.getMessage());
jc.usage();
}
File keystore = new File("keystore");
File keystore = new File("serverKeyStore.jks");
generateSelfSignedCertificate(params.hostname, keystore, params.storePassword,
params.subject);
}
public static void generateSelfSignedCertificate(String hostname, File keystore,
String keystorePassword) {
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
kpGen.initialize(1024, new SecureRandom());
KeyPair pair = kpGen.generateKeyPair();
// Generate self-signed certificate
X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
builder.addRDN(BCStyle.OU, Constants.NAME);
builder.addRDN(BCStyle.O, Constants.NAME);
builder.addRDN(BCStyle.CN, hostname);
Date notBefore = new Date(System.currentTimeMillis() - TimeUtils.ONEDAY);
Date notAfter = new Date(System.currentTimeMillis() + 10 * TimeUtils.ONEYEAR);
BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),
serial, notBefore, notAfter, builder.build(), pair.getPublic());
ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
.setProvider(BC).build(pair.getPrivate());
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC)
.getCertificate(certGen.build(sigGen));
cert.checkValidity(new Date());
cert.verify(cert.getPublicKey());
// Save to keystore
KeyStore store = KeyStore.getInstance("JKS");
if (keystore.exists()) {
FileInputStream fis = new FileInputStream(keystore);
store.load(fis, keystorePassword.toCharArray());
fis.close();
} else {
store.load(null);
}
store.setKeyEntry(hostname, pair.getPrivate(), keystorePassword.toCharArray(),
new java.security.cert.Certificate[] { cert });
FileOutputStream fos = new FileOutputStream(keystore);
store.store(fos, keystorePassword.toCharArray());
fos.close();
} catch (Throwable t) {
t.printStackTrace();
throw new RuntimeException("Failed to generate self-signed certificate!", t);
}
}
public static void generateSelfSignedCertificate(String hostname, File keystore,
String keystorePassword, String info) {
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
kpGen.initialize(1024, new SecureRandom());
KeyPair pair = kpGen.generateKeyPair();

Loading…
Cancel
Save