You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by va...@apache.org on 2023/05/24 06:30:03 UTC
[qpid-broker-j] branch main updated: QPID-8624: [Broker-J] Unable to auto generate self signed certificate on Java17 (#181)
This is an automated email from the ASF dual-hosted git repository.
vavrtom pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git
The following commit(s) were added to refs/heads/main by this push:
new ad7b4189df QPID-8624: [Broker-J] Unable to auto generate self signed certificate on Java17 (#181)
ad7b4189df is described below
commit ad7b4189dfc6b05c3eb599c0731c7a01e28ea607
Author: Daniil Kirilyuk <da...@gmail.com>
AuthorDate: Wed May 24 08:29:57 2023 +0200
QPID-8624: [Broker-J] Unable to auto generate self signed certificate on Java17 (#181)
---
.../dependency-verification/DEPENDENCIES_REFERENCE | 6 +
broker-core/pom.xml | 10 +
.../AutoGeneratedSelfSignedKeyStoreImpl.java | 159 +++---
.../transport/network/security/ssl/SSLUtil.java | 581 ++++++++-------------
.../network/security/ssl/SSLUtilTest.java | 41 ++
.../engine/retriever/CertificateRetriever.java | 2 +-
qpid-test-utils/pom.xml | 6 +
7 files changed, 356 insertions(+), 449 deletions(-)
diff --git a/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE b/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
index 10bd48ce8e..dc517ced5c 100644
--- a/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
+++ b/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
@@ -41,6 +41,12 @@ From: 'an unknown organization'
License: The Apache Software License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.txt)
- Prometheus Java Span Context Supplier - OpenTelemetry Agent (http://github.com/prometheus/client_java/simpleclient_tracer/simpleclient_tracer_otel_agent) io.prometheus:simpleclient_tracer_otel_agent:bundle:0.16.0
License: The Apache Software License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.txt)
+ - Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (https://www.bouncycastle.org/java.html) org.bouncycastle:bcpkix-jdk18on:jar:1.72
+ License: Bouncy Castle Licence (https://www.bouncycastle.org/licence.html)
+ - Bouncy Castle Provider (https://www.bouncycastle.org/java.html) org.bouncycastle:bcprov-jdk18on:jar:1.72
+ License: Bouncy Castle Licence (https://www.bouncycastle.org/licence.html)
+ - Bouncy Castle ASN.1 Extension and Utility APIs (https://www.bouncycastle.org/java.html) org.bouncycastle:bcutil-jdk18on:jar:1.72
+ License: Bouncy Castle Licence (https://www.bouncycastle.org/licence.html)
- dgrid (https://www.webjars.org) org.webjars.bower:dgrid:jar:1.3.3
License: BSD 3-Clause (https://spdx.org/licenses/BSD 3-Clause#licenseText)
- dstore (http://webjars.org) org.webjars.bower:dstore:jar:1.1.2
diff --git a/broker-core/pom.xml b/broker-core/pom.xml
index 873405b3ec..d47c9c3a20 100644
--- a/broker-core/pom.xml
+++ b/broker-core/pom.xml
@@ -60,6 +60,16 @@
<artifactId>guava</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk18on</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk18on</artifactId>
+ </dependency>
+
<!-- test dependencies -->
<dependency>
<groupId>org.apache.qpid</groupId>
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java
index 41a9c48cb4..1790b0e6fa 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java
@@ -25,10 +25,10 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
-import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
+import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
@@ -42,24 +42,29 @@ import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Base64;
-import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
-import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import org.bouncycastle.cert.CertIOException;
+import org.bouncycastle.operator.OperatorCreationException;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
-import org.apache.qpid.server.logging.EventLogger;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.Content;
import org.apache.qpid.server.model.CustomRestHeaders;
@@ -75,12 +80,8 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
extends AbstractKeyStore<AutoGeneratedSelfSignedKeyStoreImpl>
implements AutoGeneratedSelfSignedKeyStore<AutoGeneratedSelfSignedKeyStoreImpl>
{
-
private static final SecureRandom RANDOM = new SecureRandom();
- private final Broker<?> _broker;
- private final EventLogger _eventLogger;
-
@ManagedAttributeField
private volatile String _keyAlgorithm;
@ManagedAttributeField
@@ -97,19 +98,16 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
private volatile boolean _generated;
private volatile boolean _created;
-
@ManagedObjectFactoryConstructor(conditionallyAvailable = true)
public AutoGeneratedSelfSignedKeyStoreImpl(final Map<String, Object> attributes, Broker<?> broker)
{
super(attributes, broker);
- _broker = broker;
- _eventLogger = _broker.getEventLogger();
}
@Override
public KeyManager[] getKeyManagers() throws GeneralSecurityException
{
- KeyManager[] keyManagers = _keyManagers;
+ final KeyManager[] keyManagers = _keyManagers;
return keyManagers == null ? new KeyManager[0] : Arrays.copyOf(keyManagers, keyManagers.length);
}
@@ -160,7 +158,8 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
protected void postResolve()
{
super.postResolve();
- if(getActualAttributes().containsKey(ENCODED_PRIVATE_KEY) && getActualAttributes().containsKey(ENCODED_CERTIFICATE))
+ if (getActualAttributes().containsKey(ENCODED_PRIVATE_KEY) &&
+ getActualAttributes().containsKey(ENCODED_CERTIFICATE))
{
loadPrivateKeyAndCertificate();
}
@@ -169,17 +168,15 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
generatePrivateKeyAndCertificate();
}
generateKeyManagers();
-
}
private void loadPrivateKeyAndCertificate()
{
- byte[] privateKeyEncoded = Strings.decodeBase64((String) getActualAttributes().get(ENCODED_PRIVATE_KEY));
- byte[] certificateEncoded = Strings.decodeBase64((String) getActualAttributes().get(
- ENCODED_CERTIFICATE));
+ final byte[] privateKeyEncoded = Strings.decodeBase64((String) getActualAttributes().get(ENCODED_PRIVATE_KEY));
+ final byte[] certificateEncoded = Strings.decodeBase64((String) getActualAttributes()
+ .get(ENCODED_CERTIFICATE));
-
- try(ByteArrayInputStream input = new ByteArrayInputStream(certificateEncoded))
+ try (final ByteArrayInputStream input = new ByteArrayInputStream(certificateEncoded))
{
_certificate = (X509Certificate) SSLUtil.getCertificateFactory().generateCertificate(input);
}
@@ -215,7 +212,7 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
@StateTransition(currentState = { State.UNINITIALIZED, State.STOPPED, State.ERRORED}, desiredState = State.ACTIVE)
protected ListenableFuture<Void> activate()
{
- if(!_created)
+ if (!_created)
{
saveDerivedAttributesIfNecessary();
}
@@ -226,7 +223,7 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
private void saveDerivedAttributesIfNecessary()
{
- if(_generated)
+ if (_generated)
{
final Object encodedCertificate = getEncodedCertificate();
@@ -243,71 +240,50 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
{
try
{
+ final Set<InetAddress> addresses = Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
+ .flatMap(networkInterface -> networkInterface.getInterfaceAddresses().stream())
+ .map(InterfaceAddress::getAddress)
+ .collect(Collectors.toSet());
+ final Set<String> dnsNames = addresses.stream()
+ .map(address -> address.getHostName() != null ? address.getHostName() : address.getCanonicalHostName())
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
- Set<InetAddress> addresses = new HashSet<>();
- for (NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces()))
- {
- for (InterfaceAddress inetAddress : networkInterface.getInterfaceAddresses())
- {
- addresses.add(inetAddress.getAddress());
- }
- }
+ final long startTime = Instant.now().toEpochMilli();
+ final long endTime = LocalDateTime.now().plusMonths(_durationInMonths).toInstant(ZoneOffset.UTC)
+ .toEpochMilli();
- Set<String> dnsNames = new HashSet<>();
-
- for(InetAddress address : addresses)
- {
-
- String hostName = address.getHostName();
- if (hostName != null)
- {
- dnsNames.add(hostName);
- }
- String canonicalHostName = address.getCanonicalHostName();
- if (canonicalHostName != null)
- {
- dnsNames.add(canonicalHostName);
- }
- }
-
- long startTime = System.currentTimeMillis();
- Calendar calendar = Calendar.getInstance();
- calendar.setTimeInMillis(startTime);
- calendar.add(Calendar.MONTH, _durationInMonths);
- long duration = (calendar.getTimeInMillis() - startTime)/1000;
-
- final SSLUtil.KeyCertPair keyCertPair = SSLUtil.generateSelfSignedCertificate(_keyAlgorithm,
- _signatureAlgorithm,
- _keyLength,
- startTime,
- duration,
- "CN=Qpid",
- dnsNames,
- addresses);
+ final SSLUtil.KeyCertPair keyCertPair = SSLUtil.generateSelfSignedCertificate(_keyAlgorithm,
+ _signatureAlgorithm, _keyLength, startTime, endTime, "CN=Qpid", dnsNames, addresses);
_privateKey = keyCertPair.getPrivateKey();
_certificate = keyCertPair.getCertificate();
_generated = true;
}
- catch (InstantiationException | IllegalAccessException | InvocationTargetException | IOException e)
+ catch (SocketException | NoSuchAlgorithmException | OperatorCreationException | CertificateException |
+ CertIOException e)
{
throw new IllegalConfigurationException("Unable to construct keystore", e);
}
}
+ @Override
+ public List<CertificateDetails> getCertificateDetails()
+ {
+ return List.of(new CertificateDetailsImpl(_certificate, getName()));
+ }
+
@Override
protected void checkCertificateExpiry()
{
- int expiryWarning = getCertificateExpiryWarnPeriod();
- if(expiryWarning > 0)
+ final int expiryWarning = getCertificateExpiryWarnPeriod();
+ if (expiryWarning > 0)
{
- long currentTime = System.currentTimeMillis();
- Date expiryTestDate = new Date(currentTime + (ONE_DAY * (long) expiryWarning));
-
- checkCertificatesExpiry(currentTime, expiryTestDate,
- new X509Certificate[]{_certificate});
+ final long currentTime = System.currentTimeMillis();
+ final Date expiryTestDate = new Date(currentTime + (ONE_DAY * (long) expiryWarning));
+ checkCertificatesExpiry(currentTime, expiryTestDate, new X509Certificate[]{_certificate});
}
}
@@ -317,24 +293,23 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
return Collections.singleton(_certificate);
}
-
private void generateKeyManagers()
{
try
{
- X509Certificate[] certs = new X509Certificate[] { _certificate };
-
+ final X509Certificate[] certs = new X509Certificate[] { _certificate };
- java.security.KeyStore inMemoryKeyStore = java.security.KeyStore.getInstance(java.security.KeyStore.getDefaultType());
+ final java.security.KeyStore inMemoryKeyStore =
+ java.security.KeyStore.getInstance(java.security.KeyStore.getDefaultType());
- byte[] bytes = new byte[64];
- char[] chars = "".toCharArray();
+ final byte[] bytes = new byte[64];
+ final char[] chars = "".toCharArray();
RANDOM.nextBytes(bytes);
StandardCharsets.US_ASCII.decode(ByteBuffer.wrap(bytes)).get(chars);
inMemoryKeyStore.load(null, chars);
inMemoryKeyStore.setKeyEntry("1", _privateKey, chars, certs);
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(inMemoryKeyStore, chars);
_keyManagers = kmf.getKeyManagers();
@@ -345,8 +320,6 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
}
}
-
-
static boolean isAvailable()
{
return SSLUtil.canGenerateCerts();
@@ -360,13 +333,11 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
}
@Override
- public Content getClientTrustStore(String password)
+ public Content getClientTrustStore(final String password)
{
-
try
{
- KeyStore inMemoryKeyStore =
- KeyStore.getInstance(KeyStore.getDefaultType());
+ final KeyStore inMemoryKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
inMemoryKeyStore.load(null, null);
inMemoryKeyStore.setCertificateEntry(getName(), _certificate);
@@ -379,7 +350,6 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
}
}
-
@Override
public Content getCertificate()
{
@@ -391,7 +361,6 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
{
throw new IllegalArgumentException("Cannot decode encode the certificate");
}
-
}
private static class TrustStoreContent implements Content, CustomRestHeaders
@@ -400,8 +369,7 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
private final char[] _password;
private final String _disposition;
- public TrustStoreContent(final KeyStore inMemoryKeyStore,
- final String name, final char[] password)
+ public TrustStoreContent(final KeyStore inMemoryKeyStore, final String name, final char[] password)
{
_keyStore = inMemoryKeyStore;
_password = password;
@@ -432,17 +400,16 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
return "application/octet-stream";
}
+ @SuppressWarnings("unused")
@RestContentHeader("Content-Disposition")
public String getContentDisposition()
{
return _disposition;
}
-
}
private static class CertificateContent implements Content, CustomRestHeaders
{
-
private final String _disposition;
private final String _certString;
@@ -450,12 +417,12 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
throws CertificateEncodingException
{
_disposition = "attachment; filename=\"" + name + ".pem\"";
- StringBuilder certStringBuffer = new StringBuilder("-----BEGIN CERTIFICATE-----\n");
- String cert = Base64.getEncoder().encodeToString(certificate.getEncoded());
+ final StringBuilder certStringBuffer = new StringBuilder("-----BEGIN CERTIFICATE-----\n");
+ final String cert = Base64.getEncoder().encodeToString(certificate.getEncoded());
int offset = 0;
- while(cert.length()-offset > 64)
+ while (cert.length() - offset > 64)
{
- certStringBuffer.append(cert.substring(offset, offset+64));
+ certStringBuffer.append(cert, offset, offset + 64);
offset+=64;
certStringBuffer.append("\n");
}
@@ -467,9 +434,9 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
@Override
public void write(final OutputStream outputStream) throws IOException
{
- Writer w = new OutputStreamWriter(outputStream);
- w.write(_certString);
- w.flush();
+ final Writer writer = new OutputStreamWriter(outputStream);
+ writer.write(_certString);
+ writer.flush();
}
@Override
@@ -483,13 +450,11 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
return "text/plain";
}
+ @SuppressWarnings("unused")
@RestContentHeader("Content-Disposition")
public String getContentDisposition()
{
return _disposition;
}
-
-
}
-
}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java b/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
index b11a9e6e46..65a4fc4eeb 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
@@ -27,9 +27,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.URL;
@@ -38,11 +35,16 @@ import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -63,6 +65,8 @@ import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
@@ -76,9 +80,24 @@ import javax.net.ssl.SSLSocket;
import javax.net.ssl.StandardConstants;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.cert.CertIOException;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.util.IPAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -92,108 +111,25 @@ public class SSLUtil
private static final Logger LOGGER = LoggerFactory.getLogger(SSLUtil.class);
private static final Integer DNS_NAME_TYPE = 2;
- private static final String[] TLS_PROTOCOL_PREFERENCES = new String[]{"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLS", "TLSv1"};
-
-
- private static final Constructor<?> CONSTRUCTOR;
- private static final Method GENERATE_METHOD;
- private static final Method GET_PRIVATE_KEY_METHOD;
- private static final Method GET_SELF_CERTIFICATE_METHOD;
- private static final Constructor<?> X500_NAME_CONSTRUCTOR;
- private static final Constructor<?> DNS_NAME_CONSTRUCTOR;
- private static final Constructor<?> IP_ADDR_NAME_CONSTRUCTOR;
- private static final Constructor<?> GENERAL_NAMES_CONSTRUCTOR;
- private static final Constructor<?> GENERAL_NAME_CONSTRUCTOR;
- private static final Method ADD_NAME_TO_NAMES_METHOD;
- private static final Constructor<?> ALT_NAMES_CONSTRUCTOR;
- private static final Constructor<?> CERTIFICATE_EXTENSIONS_CONSTRUCTOR;
- private static final Method SET_EXTENSION_METHOD;
- private static final Method EXTENSION_GET_NAME_METHOD;
- private static final boolean CAN_GENERATE_CERTS;
+ private static final String[] TLS_PROTOCOL_PREFERENCES = new String[] { "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLS", "TLSv1" };
+ private static final Pattern DNS_NAME_PATTERN = Pattern.compile("[\\w&&[^\\d]][\\w\\d.-]*");
+
+ private static final Provider PROVIDER = new BouncyCastleProvider();
+ private static final boolean CA_SIGNED = false;
+ private static final boolean CRITICAL = true;
private static final CertificateFactory CERTIFICATE_FACTORY;
static
{
- Constructor<?> constructor = null;
- Method generateMethod = null;
- Method getPrivateKeyMethod = null;
- Method getSelfCertificateMethod = null;
- Constructor<?> x500NameConstructor = null;
- Constructor<?> dnsNameConstructor = null;
- Constructor<?> ipAddrNameConstructor = null;
- Constructor<?> generalNamesConstructor = null;
- Constructor<?> generalNameConstructor = null;
- Method addNameToNamesMethod = null;
- Constructor<?> altNamesConstructor = null;
- Constructor<?> certificateExtensionsConstructor = null;
- Method setExtensionMethod = null;
- Method extensionGetNameMethod = null;
- boolean canGenerateCerts = false;
- CertificateFactory certificateFactory = null;
-
+ CertificateFactory certificateFactory;
try
{
certificateFactory = CertificateFactory.getInstance("X.509");
}
catch (CertificateException e)
{
- // ignore
+ certificateFactory = null;
}
-
- try
- {
- Class<?> certAndKeyGenClass;
- try
- {
- certAndKeyGenClass = Class.forName("sun.security.x509.CertAndKeyGen");
- }
- catch (ClassNotFoundException e)
- {
- certAndKeyGenClass = Class.forName("sun.security.tools.keytool.CertAndKeyGen");
- }
-
- final Class<?> x500NameClass = Class.forName("sun.security.x509.X500Name");
- final Class<?> certificateExtensionsClass = Class.forName("sun.security.x509.CertificateExtensions");
- final Class<?> generalNamesClass = Class.forName("sun.security.x509.GeneralNames");
- final Class<?> generalNameClass = Class.forName("sun.security.x509.GeneralName");
- final Class<?> extensionClass = Class.forName("sun.security.x509.SubjectAlternativeNameExtension");
-
- constructor = certAndKeyGenClass.getConstructor(String.class, String.class);
- generateMethod = certAndKeyGenClass.getMethod("generate", Integer.TYPE);
- getPrivateKeyMethod = certAndKeyGenClass.getMethod("getPrivateKey");
- getSelfCertificateMethod = certAndKeyGenClass.getMethod("getSelfCertificate", x500NameClass,
- Date.class, Long.TYPE, certificateExtensionsClass);
- x500NameConstructor = x500NameClass.getConstructor(String.class);
- dnsNameConstructor = Class.forName("sun.security.x509.DNSName").getConstructor(String.class);
- ipAddrNameConstructor = Class.forName("sun.security.x509.IPAddressName").getConstructor(String.class);
- generalNamesConstructor = generalNamesClass.getConstructor();
- generalNameConstructor = generalNameClass.getConstructor(Class.forName("sun.security.x509.GeneralNameInterface"));
- addNameToNamesMethod = generalNamesClass.getMethod("add", generalNameClass);
- altNamesConstructor = extensionClass.getConstructor(generalNamesClass);
- certificateExtensionsConstructor = certificateExtensionsClass.getConstructor();
- setExtensionMethod = certificateExtensionsClass.getMethod("set", String.class, Object.class);
- extensionGetNameMethod = extensionClass.getMethod("getName");
- canGenerateCerts = true;
- }
- catch (ClassNotFoundException | LinkageError | NoSuchMethodException e)
- {
- // ignore
- }
- GET_SELF_CERTIFICATE_METHOD = getSelfCertificateMethod;
- CONSTRUCTOR = constructor;
- GENERATE_METHOD = generateMethod;
- GET_PRIVATE_KEY_METHOD = getPrivateKeyMethod;
- X500_NAME_CONSTRUCTOR = x500NameConstructor;
- DNS_NAME_CONSTRUCTOR = dnsNameConstructor;
- IP_ADDR_NAME_CONSTRUCTOR = ipAddrNameConstructor;
- GENERAL_NAMES_CONSTRUCTOR = generalNamesConstructor;
- GENERAL_NAME_CONSTRUCTOR = generalNameConstructor;
- ADD_NAME_TO_NAMES_METHOD = addNameToNamesMethod;
- ALT_NAMES_CONSTRUCTOR = altNamesConstructor;
- CERTIFICATE_EXTENSIONS_CONSTRUCTOR = certificateExtensionsConstructor;
- SET_EXTENSION_METHOD = setExtensionMethod;
- EXTENSION_GET_NAME_METHOD = extensionGetNameMethod;
- CAN_GENERATE_CERTS = canGenerateCerts;
CERTIFICATE_FACTORY = certificateFactory;
}
@@ -210,11 +146,11 @@ public class SSLUtil
return CERTIFICATE_FACTORY;
}
- public static void verifyHostname(SSLEngine engine,String hostnameExpected)
+ public static void verifyHostname(final SSLEngine engine, final String hostnameExpected)
{
try
{
- Certificate cert = engine.getSession().getPeerCertificates()[0];
+ final Certificate cert = engine.getSession().getPeerCertificates()[0];
if (cert instanceof X509Certificate)
{
verifyHostname(hostnameExpected, (X509Certificate) cert);
@@ -222,10 +158,10 @@ public class SSLUtil
else
{
throw new TransportException("Cannot verify peer's hostname as peer does not present a X509Certificate. "
- + "Presented certificate : " + cert);
+ + "Presented certificate : " + cert);
}
}
- catch(SSLPeerUnverifiedException e)
+ catch (SSLPeerUnverifiedException e)
{
throw new TransportException("Failed to verify peer's hostname", e);
}
@@ -233,29 +169,27 @@ public class SSLUtil
public static void verifyHostname(final String hostnameExpected, final X509Certificate cert)
{
-
try
{
- SortedSet<String> names = getNamesFromCert(cert);
+ final SortedSet<String> names = getNamesFromCert(cert);
if (names.isEmpty())
{
throw new TransportException("SSL hostname verification failed. Certificate for did not contain CN or DNS subjectAlt");
}
- boolean match = verifyHostname(hostnameExpected, names);
+ final boolean match = verifyHostname(hostnameExpected, names);
if (!match)
{
- throw new TransportException("SSL hostname verification failed." +
- " Expected : " + hostnameExpected +
- " Found in cert : " + names);
+ throw new TransportException("SSL hostname verification failed. Expected : " +
+ hostnameExpected + " Found in cert : " + names);
}
}
catch (InvalidNameException e)
{
- Principal p = cert.getSubjectDN();
- String dn = p.getName();
+ final Principal p = cert.getSubjectX500Principal();
+ final String dn = p.getName();
throw new TransportException("SSL hostname verification failed. Could not parse name " + dn, e);
}
catch (CertificateParsingException e)
@@ -264,7 +198,7 @@ public class SSLUtil
}
}
- public static boolean checkHostname(String hostname, X509Certificate cert)
+ public static boolean checkHostname(final String hostname, final X509Certificate cert)
{
try
{
@@ -281,13 +215,11 @@ public class SSLUtil
boolean match = false;
final String hostName = hostnameExpected.trim().toLowerCase();
- for (String cn : names)
+ for (final String cn : names)
{
-
- boolean doWildcard = cn.startsWith("*.") &&
- cn.lastIndexOf('.') >= 3 &&
- !cn.matches("\\*\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
-
+ final boolean doWildcard = cn.startsWith("*.") &&
+ cn.lastIndexOf('.') >= 3 &&
+ !cn.matches("\\*\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
match = doWildcard
? hostName.endsWith(cn.substring(1)) && hostName.indexOf(".") == (1 + hostName.length() - cn.length())
@@ -305,11 +237,11 @@ public class SSLUtil
private static SortedSet<String> getNamesFromCert(final X509Certificate cert)
throws InvalidNameException, CertificateParsingException
{
- Principal p = cert.getSubjectDN();
- String dn = p.getName();
- SortedSet<String> names = new TreeSet<>();
- LdapName ldapName = new LdapName(dn);
- for (Rdn part : ldapName.getRdns())
+ final Principal p = cert.getSubjectX500Principal();
+ final String dn = p.getName();
+ final SortedSet<String> names = new TreeSet<>();
+ final LdapName ldapName = new LdapName(dn);
+ for (final Rdn part : ldapName.getRdns())
{
if (part.getType().equalsIgnoreCase("CN"))
{
@@ -318,9 +250,9 @@ public class SSLUtil
}
}
- if(cert.getSubjectAlternativeNames() != null)
+ if (cert.getSubjectAlternativeNames() != null)
{
- for (List<?> entry : cert.getSubjectAlternativeNames())
+ for (final List<?> entry : cert.getSubjectAlternativeNames())
{
if (DNS_NAME_TYPE.equals(entry.get(0)))
{
@@ -331,11 +263,11 @@ public class SSLUtil
return names;
}
- public static String getIdFromSubjectDN(String dn)
+ public static String getIdFromSubjectDN(final String dn)
{
String cnStr = null;
- String dcStr = null;
- if(dn == null)
+ StringBuilder dcStr = null;
+ if (dn == null)
{
return "";
}
@@ -343,22 +275,22 @@ public class SSLUtil
{
try
{
- LdapName ln = new LdapName(dn);
- for(Rdn rdn : ln.getRdns())
+ final LdapName ln = new LdapName(dn);
+ for (final Rdn rdn : ln.getRdns())
{
- if("CN".equalsIgnoreCase(rdn.getType()))
+ if ("CN".equalsIgnoreCase(rdn.getType()))
{
cnStr = rdn.getValue().toString();
}
- else if("DC".equalsIgnoreCase(rdn.getType()))
+ else if ("DC".equalsIgnoreCase(rdn.getType()))
{
- if(dcStr == null)
+ if (dcStr == null)
{
- dcStr = rdn.getValue().toString();
+ dcStr = new StringBuilder(rdn.getValue().toString());
}
else
{
- dcStr = rdn.getValue().toString() + '.' + dcStr;
+ dcStr.insert(0, rdn.getValue().toString() + '.');
}
}
}
@@ -372,32 +304,16 @@ public class SSLUtil
}
}
-
- public static String retrieveIdentity(SSLEngine engine)
- {
- String id = "";
- Certificate cert = engine.getSession().getLocalCertificates()[0];
- Principal p = ((X509Certificate)cert).getSubjectDN();
- String dn = p.getName();
- try
- {
- id = SSLUtil.getIdFromSubjectDN(dn);
- }
- catch (Exception e)
- {
- LOGGER.info("Exception received while trying to retrieve client identity from SSL cert", e);
- }
- LOGGER.debug("Extracted Identity from client certificate : {}", id);
- return id;
- }
-
- public static KeyStore getInitializedKeyStore(String storePath, String storePassword, String keyStoreType) throws GeneralSecurityException, IOException
+ public static KeyStore getInitializedKeyStore(final String storePath,
+ final String storePassword,
+ final String keyStoreType)
+ throws GeneralSecurityException, IOException
{
- KeyStore ks = KeyStore.getInstance(keyStoreType);
+ final KeyStore ks = KeyStore.getInstance(keyStoreType);
InputStream in = null;
try
{
- File f = new File(storePath);
+ final File f = new File(storePath);
if (f.exists())
{
in = new FileInputStream(f);
@@ -411,7 +327,7 @@ public class SSLUtil
throw new IOException("Unable to load keystore resource: " + storePath);
}
- char[] storeCharPassword = storePassword == null ? null : storePassword.toCharArray();
+ final char[] storeCharPassword = storePassword == null ? null : storePassword.toCharArray();
ks.load(in, storeCharPassword);
}
@@ -432,17 +348,20 @@ public class SSLUtil
return ks;
}
- public static KeyStore getInitializedKeyStore(URL storePath, String storePassword, String keyStoreType) throws GeneralSecurityException, IOException
+ public static KeyStore getInitializedKeyStore(final URL storePath,
+ final String storePassword,
+ final String keyStoreType)
+ throws GeneralSecurityException, IOException
{
- KeyStore ks = KeyStore.getInstance(keyStoreType);
- try(InputStream in = storePath.openStream())
+ final KeyStore ks = KeyStore.getInstance(keyStoreType);
+ try (final InputStream in = storePath.openStream())
{
if (in == null && !"PKCS11".equalsIgnoreCase(keyStoreType)) // PKCS11 will not require an explicit path
{
throw new IOException("Unable to load keystore resource: " + storePath);
}
- char[] storeCharPassword = storePassword == null ? null : storePassword.toCharArray();
+ final char[] storeCharPassword = storePassword == null ? null : storePassword.toCharArray();
ks.load(in, storeCharPassword);
}
@@ -460,67 +379,63 @@ public class SSLUtil
return ks;
}
- public static X509Certificate[] readCertificates(URL certFile)
- throws IOException, GeneralSecurityException
+ public static X509Certificate[] readCertificates(final URL certFile) throws IOException, GeneralSecurityException
{
- try (InputStream is = certFile.openStream())
+ try (final InputStream is = certFile.openStream())
{
return readCertificates(is);
}
}
- public static X509Certificate[] readCertificates(InputStream input)
- throws IOException, GeneralSecurityException
+ public static X509Certificate[] readCertificates(final InputStream input) throws IOException, GeneralSecurityException
{
- List<X509Certificate> crt = new ArrayList<>();
+ final List<X509Certificate> crt = new ArrayList<>();
try
{
do
{
crt.add( (X509Certificate) getCertificateFactory().generateCertificate(input));
- } while(input.available() != 0);
+ } while (input.available() != 0);
}
- catch(CertificateException e)
+ catch (CertificateException e)
{
- if(crt.isEmpty())
+ if (crt.isEmpty())
{
throw e;
}
}
- return crt.toArray(new X509Certificate[crt.size()]);
+ return crt.toArray(new X509Certificate[0]);
}
- public static PrivateKey readPrivateKey(final URL url)
- throws IOException, GeneralSecurityException
+ public static PrivateKey readPrivateKey(final URL url) throws IOException, GeneralSecurityException
{
- try (InputStream urlStream = url.openStream())
+ try (final InputStream urlStream = url.openStream())
{
return readPrivateKey(urlStream);
}
}
- public static PrivateKey readPrivateKey(InputStream input)
- throws IOException, GeneralSecurityException
+ public static PrivateKey readPrivateKey(final InputStream input) throws IOException, GeneralSecurityException
{
byte[] content = toByteArray(input);
- String contentAsString = new String(content, StandardCharsets.US_ASCII);
- if(contentAsString.contains("-----BEGIN ") && contentAsString.contains(" PRIVATE KEY-----"))
+ final String contentAsString = new String(content, StandardCharsets.US_ASCII);
+ if (contentAsString.contains("-----BEGIN ") && contentAsString.contains(" PRIVATE KEY-----"))
{
- BufferedReader lineReader = new BufferedReader(new StringReader(contentAsString));
+ final BufferedReader lineReader = new BufferedReader(new StringReader(contentAsString));
String line;
do
{
line = lineReader.readLine();
- } while(line != null && !(line.startsWith("-----BEGIN ") && line.endsWith(" PRIVATE KEY-----")));
+ } while (line != null && !(line.startsWith("-----BEGIN ") && line.endsWith(" PRIVATE KEY-----")));
- if(line != null)
+ if (line != null)
{
- StringBuilder keyBuilder = new StringBuilder();
+ final StringBuilder keyBuilder = new StringBuilder();
- while((line = lineReader.readLine()) != null)
+ while ((line = lineReader.readLine()) != null)
{
- if(line.startsWith("-----END ") && line.endsWith(" PRIVATE KEY-----"))
+ if (line.startsWith("-----END ") && line.endsWith(" PRIVATE KEY-----"))
{
break;
}
@@ -535,17 +450,14 @@ public class SSLUtil
private static byte[] toByteArray(final InputStream input) throws IOException
{
- try(ByteArrayOutputStream buffer = new ByteArrayOutputStream())
+ try (final ByteArrayOutputStream buffer = new ByteArrayOutputStream())
{
-
- byte[] tmp = new byte[1024];
+ final byte[] tmp = new byte[1024];
int read;
- while((read=input.read(tmp))!=-1)
-
+ while ((read = input.read(tmp)) != -1)
{
buffer.write(tmp, 0, read);
}
-
return buffer.toByteArray();
}
}
@@ -556,31 +468,30 @@ public class SSLUtil
PrivateKey key;
try
{
- PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(content);
- KeyFactory kf = KeyFactory.getInstance(algorithm);
+ final PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(content);
+ final KeyFactory kf = KeyFactory.getInstance(algorithm);
key = kf.generatePrivate(keySpec);
}
- catch(InvalidKeySpecException e)
+ catch (InvalidKeySpecException e)
{
// not in PCKS#8 format - try parsing as PKCS#1
- RSAPrivateCrtKeySpec keySpec = getRSAKeySpec(content);
- KeyFactory kf = KeyFactory.getInstance(algorithm);
+ final RSAPrivateCrtKeySpec keySpec = getRSAKeySpec(content);
+ final KeyFactory kf = KeyFactory.getInstance(algorithm);
try
{
key = kf.generatePrivate(keySpec);
}
- catch(InvalidKeySpecException e2)
+ catch (InvalidKeySpecException e2)
{
throw new InvalidKeySpecException("Cannot parse the provided key as either PKCS#1 or PCKS#8 format");
}
-
}
return key;
}
- private static RSAPrivateCrtKeySpec getRSAKeySpec(byte[] keyBytes) throws InvalidKeySpecException
+ @SuppressWarnings("unused")
+ private static RSAPrivateCrtKeySpec getRSAKeySpec(final byte[] keyBytes) throws InvalidKeySpecException
{
-
ByteBuffer buffer = ByteBuffer.wrap(keyBytes);
try
{
@@ -588,41 +499,37 @@ public class SSLUtil
// (version, modulus, publicExponent, privateExponent, primeP, primeQ,
// primeExponentP, primeExponentQ, crtCoefficient)
- int tag = ((int)buffer.get()) & 0xff;
+ final int tag = ((int)buffer.get()) & 0xff;
// check tag is that of a sequence
- if(((tag & 0x20) != 0x20) || ((tag & 0x1F) != 0x10))
+ if (((tag & 0x20) != 0x20) || ((tag & 0x1F) != 0x10))
{
throw new InvalidKeySpecException("Unable to parse key as PKCS#1 format");
}
- int length = getLength(buffer);
+ final int length = getLength(buffer);
buffer = buffer.slice();
buffer.limit(length);
// first tlv is version - which we'll ignore
- byte versionTag = buffer.get();
- int versionLength = getLength(buffer);
+ final byte versionTag = buffer.get();
+ final int versionLength = getLength(buffer);
buffer.position(buffer.position()+versionLength);
-
- RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(
+ return new RSAPrivateCrtKeySpec(
getInteger(buffer), getInteger(buffer), getInteger(buffer), getInteger(buffer), getInteger(buffer),
getInteger(buffer), getInteger(buffer), getInteger(buffer));
-
- return keySpec;
}
- catch(BufferUnderflowException e)
+ catch (BufferUnderflowException e)
{
throw new InvalidKeySpecException("Unable to parse key as PKCS#1 format");
}
}
- private static int getLength(ByteBuffer buffer)
+ private static int getLength(final ByteBuffer buffer)
{
-
- int i = ((int) buffer.get()) & 0xff;
+ final int i = ((int) buffer.get()) & 0xff;
// length 0 <= i <= 127 encoded as a single byte
if ((i & ~0x7F) == 0)
@@ -631,21 +538,21 @@ public class SSLUtil
}
// otherwise the first octet gives us the number of octets needed to read the length
- byte[] bytes = new byte[i & 0x7f];
+ final byte[] bytes = new byte[i & 0x7f];
buffer.get(bytes);
return new BigInteger(1, bytes).intValue();
}
- private static BigInteger getInteger(ByteBuffer buffer) throws InvalidKeySpecException
+ private static BigInteger getInteger(final ByteBuffer buffer) throws InvalidKeySpecException
{
- int tag = ((int) buffer.get()) & 0xff;
+ final int tag = ((int) buffer.get()) & 0xff;
// 0x02 indicates an integer type
if((tag & 0x1f) != 0x02)
{
throw new InvalidKeySpecException("Unable to parse key as PKCS#1 format");
}
- byte[] num = new byte[getLength(buffer)];
+ final byte[] num = new byte[getLength(buffer)];
buffer.get(num);
return new BigInteger(num);
}
@@ -654,21 +561,17 @@ public class SSLUtil
final List<String> protocolAllowList,
final List<String> protocolDenyList)
{
- String[] filteredProtocols = filterEnabledProtocols(engine.getEnabledProtocols(),
- engine.getSupportedProtocols(),
- protocolAllowList,
- protocolDenyList);
+ final String[] filteredProtocols = filterEnabledProtocols(engine.getEnabledProtocols(),
+ engine.getSupportedProtocols(), protocolAllowList, protocolDenyList);
engine.setEnabledProtocols(filteredProtocols);
}
public static void updateEnabledTlsProtocols(final SSLSocket socket,
- final List<String> protocolAllowList,
- final List<String> protocolDenyList)
+ final List<String> protocolAllowList,
+ final List<String> protocolDenyList)
{
- String[] filteredProtocols = filterEnabledProtocols(socket.getEnabledProtocols(),
- socket.getSupportedProtocols(),
- protocolAllowList,
- protocolDenyList);
+ final String[] filteredProtocols = filterEnabledProtocols(socket.getEnabledProtocols(),
+ socket.getSupportedProtocols(), protocolAllowList, protocolDenyList);
socket.setEnabledProtocols(filteredProtocols);
}
@@ -688,15 +591,12 @@ public class SSLUtil
return filterEntries(enabledCipherSuites, supportedCipherSuites, cipherSuiteAllowList, cipherSuiteDenyList);
}
-
public static void updateEnabledCipherSuites(final SSLEngine engine,
final List<String> cipherSuitesAllowList,
final List<String> cipherSuitesDenyList)
{
- String[] filteredCipherSuites = filterEntries(engine.getEnabledCipherSuites(),
- engine.getSupportedCipherSuites(),
- cipherSuitesAllowList,
- cipherSuitesDenyList);
+ final String[] filteredCipherSuites = filterEntries(engine.getEnabledCipherSuites(),
+ engine.getSupportedCipherSuites(), cipherSuitesAllowList, cipherSuitesDenyList);
engine.setEnabledCipherSuites(filteredCipherSuites);
}
@@ -704,10 +604,8 @@ public class SSLUtil
final List<String> cipherSuitesAllowList,
final List<String> cipherSuitesDenyList)
{
- String[] filteredCipherSuites = filterEntries(socket.getEnabledCipherSuites(),
- socket.getSupportedCipherSuites(),
- cipherSuitesAllowList,
- cipherSuitesDenyList);
+ final String[] filteredCipherSuites = filterEntries(socket.getEnabledCipherSuites(),
+ socket.getSupportedCipherSuites(), cipherSuitesAllowList, cipherSuitesDenyList);
socket.setEnabledCipherSuites(filteredCipherSuites);
}
@@ -720,14 +618,14 @@ public class SSLUtil
if (allowList != null && !allowList.isEmpty())
{
filteredList = new ArrayList<>();
- List<String> supportedList = new ArrayList<>(Arrays.asList(supportedEntries));
+ final List<String> supportedList = new ArrayList<>(Arrays.asList(supportedEntries));
// the outer loop must be over the allow list to preserve its order
- for (String allowListedRegEx : allowList)
+ for (final String allowListedRegEx : allowList)
{
- Iterator<String> supportedIter = supportedList.iterator();
+ final Iterator<String> supportedIter = supportedList.iterator();
while (supportedIter.hasNext())
{
- String supportedEntry = supportedIter.next();
+ final String supportedEntry = supportedIter.next();
if (supportedEntry.matches(allowListedRegEx))
{
filteredList.add(supportedEntry);
@@ -743,20 +641,13 @@ public class SSLUtil
if (denyList != null && !denyList.isEmpty())
{
- for (String denyListedRegEx : denyList)
+ for (final String denyListedRegEx : denyList)
{
- Iterator<String> entriesIter = filteredList.iterator();
- while (entriesIter.hasNext())
- {
- if (entriesIter.next().matches(denyListedRegEx))
- {
- entriesIter.remove();
- }
- }
+ filteredList.removeIf(s -> s.matches(denyListedRegEx));
}
}
- return filteredList.toArray(new String[filteredList.size()]);
+ return filteredList.toArray(new String[0]);
}
public static SSLContext tryGetSSLContext() throws NoSuchAlgorithmException
@@ -766,7 +657,7 @@ public class SSLUtil
public static SSLContext tryGetSSLContext(final String[] protocols) throws NoSuchAlgorithmException
{
- for (String protocol : protocols)
+ for (final String protocol : protocols)
{
try
{
@@ -778,16 +669,16 @@ public class SSLUtil
}
}
throw new NoSuchAlgorithmException(String.format("Could not create SSLContext with one of the requested protocols: %s",
- Arrays.toString(protocols)));
+ Arrays.toString(protocols)));
}
- public static boolean isSufficientToDetermineClientSNIHost(QpidByteBuffer buffer)
+ public static boolean isSufficientToDetermineClientSNIHost(final QpidByteBuffer buffer)
{
- if(buffer.remaining() < 6)
+ if (buffer.remaining() < 6)
{
return false;
}
- else if(looksLikeSSLv3ClientHello(buffer))
+ else if (looksLikeSSLv3ClientHello(buffer))
{
final int position = buffer.position();
final int recordSize = 5 + (((buffer.get(position + 3) & 0xFF) << 8) | (buffer.get(position + 4) & 0xFF));
@@ -799,27 +690,27 @@ public class SSLUtil
}
}
- private static boolean looksLikeSSLv3ClientHello(QpidByteBuffer buffer)
+ private static boolean looksLikeSSLv3ClientHello(final QpidByteBuffer buffer)
{
- int contentType = buffer.get(buffer.position()+0);
- int majorVersion = buffer.get(buffer.position()+1);
- int minorVersion = buffer.get(buffer.position()+2);
- int messageType = buffer.get(buffer.position()+5);
+ final int contentType = buffer.get(buffer.position());
+ final int majorVersion = buffer.get(buffer.position() + 1);
+ final int minorVersion = buffer.get(buffer.position() + 2);
+ final int messageType = buffer.get(buffer.position() + 5);
return contentType == 22 && // SSL Handshake
- (majorVersion == 3 && // SSL 3.0 / TLS 1.x
- (minorVersion == 0 || // SSL 3.0
- minorVersion == 1 || // TLS 1.0
- minorVersion == 2 || // TLS 1.1
- minorVersion == 3)) && // TLS1.2
- (messageType == 1); // client_hello
+ (majorVersion == 3 && // SSL 3.0 / TLS 1.x
+ (minorVersion == 0 || // SSL 3.0
+ minorVersion == 1 || // TLS 1.0
+ minorVersion == 2 || // TLS 1.1
+ minorVersion == 3)) && // TLS1.2
+ (messageType == 1); // client_hello
}
- public final static String getServerNameFromTLSClientHello(QpidByteBuffer source)
+ @SuppressWarnings("unused")
+ public static String getServerNameFromTLSClientHello(final QpidByteBuffer source)
{
- try (QpidByteBuffer input = source.duplicate())
+ try (final QpidByteBuffer input = source.duplicate())
{
-
// Do we have a complete header?
if (!isSufficientToDetermineClientSNIHost(source))
{
@@ -830,36 +721,34 @@ public class SSLUtil
return null;
}
- byte contentType = input.get();
- byte majorVersion = input.get();
- byte minorVersion = input.get();
+ final byte contentType = input.get();
+ final byte majorVersion = input.get();
+ final byte minorVersion = input.get();
if (minorVersion != 0x00) // not supported for SSL 3.0
{
-
- int recordLength = input.getUnsignedShort();
- int messageType = input.get();
+ final int recordLength = input.getUnsignedShort();
+ final int messageType = input.get();
// 24-bit length field
- int length = (input.getUnsignedByte() << 16) | (input.getUnsignedByte() << 8) | input.getUnsignedByte();
- if(input.remaining() < length)
+ final int length = (input.getUnsignedByte() << 16) | (input.getUnsignedByte() << 8) | input.getUnsignedByte();
+ if (input.remaining() < length)
{
return null;
}
input.limit(length + input.position());
input.position(input.position() + 34); // hello minor/major version + random
- int skip = (int) input.get(); // session-id
+ int skip = input.get(); // session-id
input.position(input.position() + skip);
skip = input.getUnsignedShort(); // cipher suites
input.position(input.position() + skip);
- skip = (int) input.get(); // compression methods
+ skip = input.get(); // compression methods
input.position(input.position() + skip);
if (input.hasRemaining())
{
+ final int remaining = input.getUnsignedShort();
- int remaining = input.getUnsignedShort();
-
- if(input.remaining() < remaining)
+ if (input.remaining() < remaining)
{
// invalid remaining length
return null;
@@ -868,17 +757,15 @@ public class SSLUtil
input.limit(input.position()+remaining);
while (input.hasRemaining())
{
- int extensionType = input.getUnsignedShort();
-
- int extensionLength = input.getUnsignedShort();
+ final int extensionType = input.getUnsignedShort();
+ final int extensionLength = input.getUnsignedShort();
if (extensionType == 0x00)
{
-
int extensionDataRemaining = extensionLength;
if (extensionDataRemaining >= 2)
{
- int listLength = input.getUnsignedShort(); // length of server_name_list
+ final int listLength = input.getUnsignedShort(); // length of server_name_list
if (listLength + 2 != extensionDataRemaining)
{
// invalid format
@@ -888,14 +775,14 @@ public class SSLUtil
extensionDataRemaining -= 2;
while (extensionDataRemaining > 0)
{
- int code = input.get();
- int serverNameLength = input.getUnsignedShort();
+ final int code = input.get();
+ final int serverNameLength = input.getUnsignedShort();
if (serverNameLength > extensionDataRemaining)
{
// invalid format;
return null;
}
- byte[] encoded = new byte[serverNameLength];
+ final byte[] encoded = new byte[serverNameLength];
input.get(encoded);
if (code == StandardConstants.SNI_HOST_NAME)
@@ -909,7 +796,7 @@ public class SSLUtil
}
else
{
- if(input.remaining() < extensionLength)
+ if (input.remaining() < extensionLength)
{
return null;
}
@@ -917,12 +804,12 @@ public class SSLUtil
}
}
}
-
}
return null;
}
}
+ @SuppressWarnings("rawtypes")
public static SSLContext createSslContext(final org.apache.qpid.server.model.KeyStore keyStore,
final Collection<TrustStore> trustStores,
final String portName)
@@ -931,30 +818,30 @@ public class SSLUtil
try
{
sslContext = tryGetSSLContext();
- KeyManager[] keyManagers = keyStore.getKeyManagers();
+ final KeyManager[] keyManagers = keyStore.getKeyManagers();
TrustManager[] trustManagers;
- if(trustStores == null || trustStores.isEmpty())
+ if (trustStores == null || trustStores.isEmpty())
{
trustManagers = null;
}
- else if(trustStores.size() == 1)
+ else if (trustStores.size() == 1)
{
trustManagers = trustStores.iterator().next().getTrustManagers();
}
else
{
- Collection<TrustManager> trustManagerList = new ArrayList<>();
+ final Collection<TrustManager> trustManagerList = new ArrayList<>();
final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager();
- for(TrustStore ts : trustStores)
+ for (final TrustStore<?> ts : trustStores)
{
- TrustManager[] managers = ts.getTrustManagers();
- if(managers != null)
+ final TrustManager[] managers = ts.getTrustManagers();
+ if (managers != null)
{
- for(TrustManager manager : managers)
+ for (final TrustManager manager : managers)
{
- if(manager instanceof X509TrustManager)
+ if (manager instanceof X509TrustManager)
{
mulTrustManager.addTrustManager((X509TrustManager)manager);
}
@@ -965,11 +852,11 @@ public class SSLUtil
}
}
}
- if(!mulTrustManager.isEmpty())
+ if (!mulTrustManager.isEmpty())
{
trustManagerList.add(mulTrustManager);
}
- trustManagers = trustManagerList.toArray(new TrustManager[trustManagerList.size()]);
+ trustManagers = trustManagerList.toArray(new TrustManager[0]);
}
sslContext.init(keyManagers, trustManagers, null);
}
@@ -982,75 +869,67 @@ public class SSLUtil
public static boolean canGenerateCerts()
{
- return CAN_GENERATE_CERTS;
+ return true;
}
public static KeyCertPair generateSelfSignedCertificate(final String keyAlgorithm,
final String signatureAlgorithm,
final int keyLength,
- long startTime,
- long duration,
- String x500Name,
- Set<String> dnsNames,
- Set<InetAddress> addresses)
- throws IllegalAccessException, InvocationTargetException, InstantiationException
- {
- Object certAndKeyGen = CONSTRUCTOR.newInstance(keyAlgorithm, signatureAlgorithm);
- GENERATE_METHOD.invoke(certAndKeyGen, keyLength);
- final PrivateKey _privateKey = (PrivateKey) GET_PRIVATE_KEY_METHOD.invoke(certAndKeyGen);
-
- Object generalNames = GENERAL_NAMES_CONSTRUCTOR.newInstance();
-
- for(String dnsName : dnsNames)
- {
- if(dnsName.matches("[\\w&&[^\\d]][\\w\\d.-]*"))
- {
- ADD_NAME_TO_NAMES_METHOD.invoke(generalNames,
- GENERAL_NAME_CONSTRUCTOR.newInstance(DNS_NAME_CONSTRUCTOR.newInstance(
- dnsName)));
- }
- }
-
- for(InetAddress inetAddress : addresses)
- {
- ADD_NAME_TO_NAMES_METHOD.invoke(generalNames, GENERAL_NAME_CONSTRUCTOR.newInstance(IP_ADDR_NAME_CONSTRUCTOR.newInstance(inetAddress.getHostAddress())));
- }
- Object certificateExtensions;
- if(dnsNames.isEmpty() && addresses.isEmpty())
- {
- certificateExtensions = null;
- }
- else
- {
- Object altNamesExtension = ALT_NAMES_CONSTRUCTOR.newInstance(generalNames);
- certificateExtensions = CERTIFICATE_EXTENSIONS_CONSTRUCTOR.newInstance();
- SET_EXTENSION_METHOD.invoke(certificateExtensions,
- EXTENSION_GET_NAME_METHOD.invoke(altNamesExtension),
- altNamesExtension);
- }
-
- final X509Certificate _certificate = (X509Certificate) GET_SELF_CERTIFICATE_METHOD.invoke(certAndKeyGen,
- X500_NAME_CONSTRUCTOR
- .newInstance(x500Name),
- new Date(startTime),
- duration,
- certificateExtensions);
+ final long startTime,
+ final long endTime,
+ final String x500Name,
+ final Set<String> dnsNames,
+ final Set<InetAddress> addresses)
+ throws NoSuchAlgorithmException, OperatorCreationException, CertificateException, CertIOException
+ {
+ final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
+ keyPairGenerator.initialize(keyLength);
+
+ final KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ final PrivateKey privateKey = keyPair.getPrivate();
+
+ final ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
+
+ final GeneralName[] sanLocalHost = Stream.concat(dnsNames.stream()
+ .filter(dnsName -> DNS_NAME_PATTERN.matcher(dnsName).matches())
+ .map(dnaName -> new GeneralName(GeneralName.dNSName, dnaName)),
+ addresses.stream()
+ .map(InetAddress::getHostAddress)
+ .filter(address -> IPAddress.isValidIPv4(address) || IPAddress.isValidIPv4WithNetmask(address) ||
+ IPAddress.isValidIPv6(address) || IPAddress.isValidIPv6WithNetmask(address))
+ .map(address -> new GeneralName(GeneralName.iPAddress, address)))
+ .toArray(GeneralName[]::new);
+
+ final X500Principal issuerDn = new X500Principal(x500Name);
+ final X500Principal subjectDn = new X500Principal(x500Name);
+ final BigInteger serialNumber = new BigInteger(64, new SecureRandom());
+ final Date startDate = new Date(startTime);
+ final Date endDate = new Date(endTime);
+ final PublicKey publicKey = keyPair.getPublic();
+
+ final X509v3CertificateBuilder certificateBuilder =
+ new JcaX509v3CertificateBuilder(issuerDn, serialNumber, startDate, endDate, subjectDn, publicKey)
+ .addExtension(Extension.basicConstraints, CRITICAL, new BasicConstraints(CA_SIGNED))
+ .addExtension(Extension.subjectAlternativeName, false, new GeneralNames(sanLocalHost));
+
+ final X509Certificate certificate = new JcaX509CertificateConverter()
+ .setProvider(PROVIDER)
+ .getCertificate(certificateBuilder.build(contentSigner));
return new KeyCertPair()
{
@Override
public PrivateKey getPrivateKey()
{
- return _privateKey;
+ return privateKey;
}
@Override
public X509Certificate getCertificate()
{
- return _certificate;
+ return certificate;
}
};
-
}
public static Map<String, Certificate> getCertificates(final KeyStore ks) throws KeyStoreException
@@ -1068,7 +947,7 @@ public class SSLUtil
return certificates;
}
- public static SNIHostName createSNIHostName(String hostName)
+ public static SNIHostName createSNIHostName(final String hostName)
{
try
{
@@ -1080,7 +959,7 @@ public class SSLUtil
}
}
- public static SNIHostName createSNIHostName(byte[] hostName)
+ public static SNIHostName createSNIHostName(final byte[] hostName)
{
try
{
diff --git a/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java b/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java
index b624635ac4..ebd319fede 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java
@@ -24,10 +24,14 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
import java.net.URL;
import java.nio.ByteBuffer;
import java.security.KeyStore;
@@ -36,10 +40,16 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Base64;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@@ -226,6 +236,37 @@ public class SSLUtilTest extends UnitTestBase
assertEquals(certificate, certificates[0], "Unexpected certificate");
}
+ @Test
+ public void generateSelfSignedCertificate() throws Exception
+ {
+ final String keyAlgorithm = "RSA";
+ final String signatureAlgorithm = "SHA256withRSA";
+ final int keyLength = 2048;
+
+ final Set<InetAddress> addresses = Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
+ .flatMap(networkInterface -> networkInterface.getInterfaceAddresses().stream())
+ .map(InterfaceAddress::getAddress)
+ .collect(Collectors.toSet());
+
+ final Set<String> dnsNames = addresses.stream()
+ .map(address -> address.getHostName() != null ? address.getHostName() : address.getCanonicalHostName())
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+
+ final long startTime = System.currentTimeMillis();
+ final long endTime = Instant.ofEpochMilli(startTime).plus(365, ChronoUnit.DAYS).toEpochMilli();
+
+ final SSLUtil.KeyCertPair keyCertPair = SSLUtil.generateSelfSignedCertificate(keyAlgorithm,
+ signatureAlgorithm, keyLength, startTime, endTime, "CN=Qpid", dnsNames, addresses);
+
+ assertNotNull(keyCertPair);
+ assertNotNull(keyCertPair.getCertificate());
+ assertNotNull(keyCertPair.getPrivateKey());
+
+ assertEquals(keyAlgorithm, keyCertPair.getPrivateKey().getAlgorithm());
+ assertTrue(signatureAlgorithm.equalsIgnoreCase(keyCertPair.getCertificate().getSigAlgName()));
+ }
+
private Certificate getTestCertificate()
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
{
diff --git a/broker-plugins/query-engine/src/main/java/org/apache/qpid/server/query/engine/retriever/CertificateRetriever.java b/broker-plugins/query-engine/src/main/java/org/apache/qpid/server/query/engine/retriever/CertificateRetriever.java
index a36ea442a4..168bb364ba 100644
--- a/broker-plugins/query-engine/src/main/java/org/apache/qpid/server/query/engine/retriever/CertificateRetriever.java
+++ b/broker-plugins/query-engine/src/main/java/org/apache/qpid/server/query/engine/retriever/CertificateRetriever.java
@@ -78,7 +78,7 @@ public class CertificateRetriever<C extends ConfiguredObject<?>> extends Configu
private final BiFunction<ConfiguredObject<?>, CertificateDetails, Map<String, Object>> certificateMapping =
(ConfiguredObject<?> parent, CertificateDetails certificate) -> ImmutableMap.<String, Object>builder()
.put(_fieldNames.get(0), parent.getName())
- .put(_fieldNames.get(1), certificate.getAlias())
+ .put(_fieldNames.get(1), certificate.getAlias() == null ? "null" : certificate.getAlias())
.put(_fieldNames.get(2), certificate.getIssuerName())
.put(_fieldNames.get(3), certificate.getSerialNumber())
.put(_fieldNames.get(4), toHex(certificate.getSerialNumber()))
diff --git a/qpid-test-utils/pom.xml b/qpid-test-utils/pom.xml
index 87c26394e9..ff824cd39f 100644
--- a/qpid-test-utils/pom.xml
+++ b/qpid-test-utils/pom.xml
@@ -80,6 +80,12 @@
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-protocol-ldap</artifactId>
<scope>compile</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org