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
This commit is contained in:
parent
ed4928f62a
commit
c116c35ed0
@ -31,8 +31,9 @@ import java.security.PrivateKey;
|
|||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.cert.X509Certificate;
|
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 <a href="http://www.bouncycastle.org/">Bouncy Castle</a>.
|
* Generates a self-signed certificate using <a href="http://www.bouncycastle.org/">Bouncy Castle</a>.
|
||||||
@ -41,13 +42,14 @@ final class BouncyCastleSelfSignedCertGenerator {
|
|||||||
|
|
||||||
private static final Provider PROVIDER = new BouncyCastleProvider();
|
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();
|
PrivateKey key = keypair.getPrivate();
|
||||||
|
|
||||||
// Prepare the information required for generating an X.509 certificate.
|
// Prepare the information required for generating an X.509 certificate.
|
||||||
X500Name owner = new X500Name("CN=" + fqdn);
|
X500Name owner = new X500Name("CN=" + fqdn);
|
||||||
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
|
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);
|
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(key);
|
||||||
X509CertificateHolder certHolder = builder.build(signer);
|
X509CertificateHolder certHolder = builder.build(signer);
|
||||||
|
@ -28,6 +28,7 @@ import sun.security.x509.X500Name;
|
|||||||
import sun.security.x509.X509CertImpl;
|
import sun.security.x509.X509CertImpl;
|
||||||
import sun.security.x509.X509CertInfo;
|
import sun.security.x509.X509CertInfo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
@ -41,7 +42,8 @@ import static io.netty.handler.ssl.util.SelfSignedCertificate.*;
|
|||||||
*/
|
*/
|
||||||
final class OpenJdkSelfSignedCertGenerator {
|
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();
|
PrivateKey key = keypair.getPrivate();
|
||||||
|
|
||||||
// Prepare the information required for generating an X.509 certificate.
|
// Prepare the information required for generating an X.509 certificate.
|
||||||
@ -59,7 +61,7 @@ final class OpenJdkSelfSignedCertGenerator {
|
|||||||
} catch (CertificateException ignore) {
|
} catch (CertificateException ignore) {
|
||||||
info.set(X509CertInfo.ISSUER, owner);
|
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.KEY, new CertificateX509Key(keypair.getPublic()));
|
||||||
info.set(X509CertInfo.ALGORITHM_ID,
|
info.set(X509CertInfo.ALGORITHM_ID,
|
||||||
new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.sha1WithRSAEncryption_oid)));
|
new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.sha1WithRSAEncryption_oid)));
|
||||||
|
@ -19,6 +19,7 @@ package io.netty.handler.ssl.util;
|
|||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.handler.codec.base64.Base64;
|
import io.netty.handler.codec.base64.Base64;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
@ -59,9 +60,11 @@ public final class SelfSignedCertificate {
|
|||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(SelfSignedCertificate.class);
|
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 */
|
/** 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 */
|
/** 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 certificate;
|
||||||
private final File privateKey;
|
private final File privateKey;
|
||||||
@ -72,6 +75,15 @@ public final class SelfSignedCertificate {
|
|||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*/
|
*/
|
||||||
public SelfSignedCertificate() throws CertificateException {
|
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");
|
this("example.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,9 +93,20 @@ public final class SelfSignedCertificate {
|
|||||||
* @param fqdn a fully qualified domain name
|
* @param fqdn a fully qualified domain name
|
||||||
*/
|
*/
|
||||||
public SelfSignedCertificate(String fqdn) throws CertificateException {
|
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.
|
// Bypass entrophy collection by using insecure random generator.
|
||||||
// We just want to generate it without any delay because it's for testing purposes only.
|
// 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
|
* @param bits the number of bits of the generated private key
|
||||||
*/
|
*/
|
||||||
public SelfSignedCertificate(String fqdn, SecureRandom random, int bits) throws CertificateException {
|
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.
|
// Generate an RSA key pair.
|
||||||
final KeyPair keypair;
|
final KeyPair keypair;
|
||||||
try {
|
try {
|
||||||
@ -108,12 +145,12 @@ public final class SelfSignedCertificate {
|
|||||||
String[] paths;
|
String[] paths;
|
||||||
try {
|
try {
|
||||||
// Try the OpenJDK's proprietary implementation.
|
// Try the OpenJDK's proprietary implementation.
|
||||||
paths = OpenJdkSelfSignedCertGenerator.generate(fqdn, keypair, random);
|
paths = OpenJdkSelfSignedCertGenerator.generate(fqdn, keypair, random, notBefore, notAfter);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.debug("Failed to generate a self-signed X.509 certificate using sun.security.x509:", t);
|
logger.debug("Failed to generate a self-signed X.509 certificate using sun.security.x509:", t);
|
||||||
try {
|
try {
|
||||||
// Try Bouncy Castle if the current JVM didn't have sun.security.x509.
|
// 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) {
|
} catch (Throwable t2) {
|
||||||
logger.debug("Failed to generate a self-signed X.509 certificate using Bouncy Castle:", t2);
|
logger.debug("Failed to generate a self-signed X.509 certificate using Bouncy Castle:", t2);
|
||||||
throw new CertificateException(
|
throw new CertificateException(
|
||||||
|
Loading…
Reference in New Issue
Block a user