From 8bc39643cf046eb6dff05f0780129afe332cdf5a Mon Sep 17 00:00:00 2001 From: Scott Mitchell Date: Tue, 22 Sep 2015 11:25:48 -0700 Subject: [PATCH] SelfSignedCertificate configurable valid dates Motivation: Users may want to control the valid dates for SelfSignedCertificate. Modifications: - Allow NOT_BEFORE and NOT_AFTER to be controlled via java system properties. Result: Fixes https://github.com/netty/netty/issues/3978 --- .../BouncyCastleSelfSignedCertGenerator.java | 8 ++-- .../util/OpenJdkSelfSignedCertGenerator.java | 6 ++- .../ssl/util/SelfSignedCertificate.java | 47 +++++++++++++++++-- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java b/handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java index 88a7c9dbab..eacffec7bc 100644 --- a/handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java +++ b/handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java @@ -31,8 +31,9 @@ import java.security.PrivateKey; import java.security.Provider; import java.security.SecureRandom; import java.security.cert.X509Certificate; +import java.util.Date; -import static io.netty.handler.ssl.util.SelfSignedCertificate.*; +import static io.netty.handler.ssl.util.SelfSignedCertificate.newSelfSignedCertificate; /** * Generates a self-signed certificate using Bouncy Castle. @@ -41,13 +42,14 @@ final class BouncyCastleSelfSignedCertGenerator { private static final Provider PROVIDER = new BouncyCastleProvider(); - static String[] generate(String fqdn, KeyPair keypair, SecureRandom random) throws Exception { + static String[] generate(String fqdn, KeyPair keypair, SecureRandom random, Date notBefore, Date notAfter) + throws Exception { PrivateKey key = keypair.getPrivate(); // Prepare the information required for generating an X.509 certificate. X500Name owner = new X500Name("CN=" + fqdn); X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder( - owner, new BigInteger(64, random), NOT_BEFORE, NOT_AFTER, owner, keypair.getPublic()); + owner, new BigInteger(64, random), notBefore, notAfter, owner, keypair.getPublic()); ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(key); X509CertificateHolder certHolder = builder.build(signer); diff --git a/handler/src/main/java/io/netty/handler/ssl/util/OpenJdkSelfSignedCertGenerator.java b/handler/src/main/java/io/netty/handler/ssl/util/OpenJdkSelfSignedCertGenerator.java index d1559eb70d..07a6fb91eb 100644 --- a/handler/src/main/java/io/netty/handler/ssl/util/OpenJdkSelfSignedCertGenerator.java +++ b/handler/src/main/java/io/netty/handler/ssl/util/OpenJdkSelfSignedCertGenerator.java @@ -28,6 +28,7 @@ import sun.security.x509.X500Name; import sun.security.x509.X509CertImpl; import sun.security.x509.X509CertInfo; +import java.util.Date; import java.math.BigInteger; import java.security.KeyPair; import java.security.PrivateKey; @@ -41,7 +42,8 @@ import static io.netty.handler.ssl.util.SelfSignedCertificate.*; */ final class OpenJdkSelfSignedCertGenerator { - static String[] generate(String fqdn, KeyPair keypair, SecureRandom random) throws Exception { + static String[] generate(String fqdn, KeyPair keypair, SecureRandom random, Date notBefore, Date notAfter) + throws Exception { PrivateKey key = keypair.getPrivate(); // Prepare the information required for generating an X.509 certificate. @@ -59,7 +61,7 @@ final class OpenJdkSelfSignedCertGenerator { } catch (CertificateException ignore) { info.set(X509CertInfo.ISSUER, owner); } - info.set(X509CertInfo.VALIDITY, new CertificateValidity(NOT_BEFORE, NOT_AFTER)); + info.set(X509CertInfo.VALIDITY, new CertificateValidity(notBefore, notAfter)); info.set(X509CertInfo.KEY, new CertificateX509Key(keypair.getPublic())); info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.sha1WithRSAEncryption_oid))); diff --git a/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java b/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java index d97992bacb..1730324c12 100644 --- a/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java +++ b/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java @@ -19,6 +19,7 @@ package io.netty.handler.ssl.util; import io.netty.buffer.Unpooled; import io.netty.handler.codec.base64.Base64; import io.netty.util.CharsetUtil; +import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -59,9 +60,11 @@ public final class SelfSignedCertificate { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SelfSignedCertificate.class); /** Current time minus 1 year, just in case software clock goes back due to time synchronization */ - static final Date NOT_BEFORE = new Date(System.currentTimeMillis() - 86400000L * 365); + private static final Date DEFAULT_NOT_BEFORE = new Date(SystemPropertyUtil.getLong( + "io.netty.selfSignedCertificate.defaultNotBefore", System.currentTimeMillis() - 86400000L * 365)); /** The maximum possible value in X.509 specification: 9999-12-31 23:59:59 */ - static final Date NOT_AFTER = new Date(253402300799000L); + private static final Date DEFAULT_NOT_AFTER = new Date(SystemPropertyUtil.getLong( + "io.netty.selfSignedCertificate.defaultNotAfter", 253402300799000L)); private final File certificate; private final File privateKey; @@ -72,6 +75,15 @@ public final class SelfSignedCertificate { * Creates a new instance. */ public SelfSignedCertificate() throws CertificateException { + this(DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER); + } + + /** + * Creates a new instance. + * @param notBefore Certificate is not valid before this time + * @param notAfter Certificate is not valid after this time + */ + public SelfSignedCertificate(Date notBefore, Date notAfter) throws CertificateException { this("example.com"); } @@ -81,9 +93,20 @@ public final class SelfSignedCertificate { * @param fqdn a fully qualified domain name */ public SelfSignedCertificate(String fqdn) throws CertificateException { + this(fqdn, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER); + } + + /** + * Creates a new instance. + * + * @param fqdn a fully qualified domain name + * @param notBefore Certificate is not valid before this time + * @param notAfter Certificate is not valid after this time + */ + public SelfSignedCertificate(String fqdn, Date notBefore, Date notAfter) throws CertificateException { // Bypass entrophy collection by using insecure random generator. // We just want to generate it without any delay because it's for testing purposes only. - this(fqdn, ThreadLocalInsecureRandom.current(), 1024); + this(fqdn, ThreadLocalInsecureRandom.current(), 1024, notBefore, notAfter); } /** @@ -94,6 +117,20 @@ public final class SelfSignedCertificate { * @param bits the number of bits of the generated private key */ public SelfSignedCertificate(String fqdn, SecureRandom random, int bits) throws CertificateException { + this(fqdn, random, bits, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER); + } + + /** + * Creates a new instance. + * + * @param fqdn a fully qualified domain name + * @param random the {@link java.security.SecureRandom} to use + * @param bits the number of bits of the generated private key + * @param notBefore Certificate is not valid before this time + * @param notAfter Certificate is not valid after this time + */ + public SelfSignedCertificate(String fqdn, SecureRandom random, int bits, Date notBefore, Date notAfter) + throws CertificateException { // Generate an RSA key pair. final KeyPair keypair; try { @@ -108,12 +145,12 @@ public final class SelfSignedCertificate { String[] paths; try { // Try the OpenJDK's proprietary implementation. - paths = OpenJdkSelfSignedCertGenerator.generate(fqdn, keypair, random); + paths = OpenJdkSelfSignedCertGenerator.generate(fqdn, keypair, random, notBefore, notAfter); } catch (Throwable t) { logger.debug("Failed to generate a self-signed X.509 certificate using sun.security.x509:", t); try { // Try Bouncy Castle if the current JVM didn't have sun.security.x509. - paths = BouncyCastleSelfSignedCertGenerator.generate(fqdn, keypair, random); + paths = BouncyCastleSelfSignedCertGenerator.generate(fqdn, keypair, random, notBefore, notAfter); } catch (Throwable t2) { logger.debug("Failed to generate a self-signed X.509 certificate using Bouncy Castle:", t2); throw new CertificateException(