After upgrade from WildFly-8.2, EJB remote invoke works fine on HTTP but when I set HTTPS remote connector and URL, it fails. I am invoking from a Java client using InitialContext.
Tried adding the server certificate to java truststore and client truststore but not worked. The client shown certificate unknown.
This issue fixed when loaded the keystore from client code before remote EJB call:
KeyManager[] keyManager = keyManagerFactory.getKeyManagers();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
logger.info("Load JSSE truststore ");
KeyStore trustStore = getTrustStore(userId, null);
if (trustStore == null) {
throw new RuntimeException("A truststore is required for SSL");
}
trustManagerFactory.init(trustStore);
TrustManager[] trustManager = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManager, trustManager, null);
SSLContext.setDefault(sslContext);
The following option passed on running java client not taken for EJB remote SSL call:
-Djavax.net.ssl.trustStore=/home/wf/clientw16.truststore
This way of passing truststore was working for WF-8.2.
Is this changed in WF-16 or any other settings needed?
Related
I am working on a code that connects to slack through a proxy which act as a MITM and replaces slack cert with its own self signed cert. I added proxy's cert into a trust store and configured my RestTemplate to use the trust store:
def sslContext = new SslContextBuilder().withTrustStore(trustStoreResource, trustStorePassword).build()
def proxy = proxyEnabled ? new HttpHost(proxyHost, proxyPort) : null
def httpClient = HttpClients.custom().setProxy(proxy).setSSLContext(sslContext).build()
def result = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient))
That works fine. However, on my local I don't go through the proxy and connect to slack directly. In other words, the httpClient in the above code would be configured with SSLContext but not proxy. I was expecting this to be fine since Slack's cert is signed with a valid root CA but my code fails to verify Slack's cert.
I am assuming this is because my trustore but I am confused as why this is happening. Is it happening because root CAs are not imported in my trustsore? If so, how would I do that without having to maintain the root CAs?
I understand that locally I can refrain from setting up a trust store but I would like to avoid adding branches in the code if possible.
What I finally ended up doing was to use the implementation in https://gist.github.com/JensRantil/9b7fecb3647ecf1e3076 to combine system's default trust store with mine and then used the following class to build my SSL context. It's a shame HttpClient doesn't offer this but there might be a good reason for it.
import org.springframework.core.io.Resource
import javax.net.ssl.KeyManager
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import java.security.KeyStore
class SslContextBuilder {
private KeyManager[] keyManagers = []
private TrustManager[] trustManagers = []
SslContextBuilder withKeyStore(Resource resource, String password) {
def keyStore = KeyStore.getInstance('JKS')
keyStore.load(resource.getInputStream(), password.chars)
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
kmfactory.init(keyStore, password.chars)
KeyManager[] kms = kmfactory.getKeyManagers()
keyManagers += kms ? kms : []
this
}
SslContextBuilder withTrustStore(Resource resource, String password) {
def trustStore = KeyStore.getInstance('JKS')
trustStore.load(resource.getInputStream(), password.chars)
def tss = CompositeX509TrustManager.getTrustManagers(trustStore)
trustManagers += tss ? tss : []
this
}
SSLContext build() {
def sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null)
sslContext
}
}
I am trying to get AWS Secrets Manager to work on an older Java 7 platform. Unfortunately we're locked on Java 7 for now.
The issue I have is that Java 7 had some security issues with SSL, and most modern Java platforms are using newer cipherSuites. Thus I get the error
javax.net.ssl.SSLHandshakeException: No negotiable cipher suite
In other interfaces I've been able to solve the issue by doing an .setEnabledCipherSuites on the SSL socket.
The problem here is that the Secrets Manager client does not expose the socket (AFAICT), nor does it expose the SocketFactory. I've been trying to create a new SSLContext wrapping the stock SSLContext that will provide a custom SocketFactory but creating and installing a custom SSLContext has proven to be quite complicated.
Before I end up pulling out the rest of my hair, is there an easier way to do this?
AWS Secrets Manager uses Apache HTTP Client (httpclient-4.5.7) under the covers. Is there a static way of hooking the Apache client with a custom Socket, SocketFactory, or SSLContext? One that does not require access to the HTTPClient object (which is not exposed either).
After much head banging I came up with the following code:
final String ciphers[] =
{ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256" };
final String[] protocols = new String[]
{ "TLSv1.2" };
// create and initialize an SSLContext for a custom socket factory
final SSLContext sslcontext = SSLContext.getInstance("SSL");
sslcontext.init(null, null, new SecureRandom());
// and here's our SocketFactory
final SSLConnectionSocketFactory secureSocketFactory = new SSLConnectionSocketFactory(sslcontext, protocols,
ciphers, new DefaultHostnameVerifier());
// Create a custom AWS Client Configuration with our socket factory
final ClientConfiguration cc = new ClientConfiguration();
final ApacheHttpClientConfig acc = cc.getApacheHttpClientConfig();
acc.setSslSocketFactory(secureSocketFactory);
// Create a Secrets Manager client with our custom AWS Client Configuration
final AWSSecretsManager client = AWSSecretsManagerClientBuilder //
.standard() //
.withRegion(region) //
.withClientConfiguration(cc) //
.build();
client is then used for the requests.
I'm working on a legacy application that always used UnboundId over a none SSL connection. Our infrastructure has changed and I need to rework it to SSL. So I changed the code to the following
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
FileInputStream fin1 = new FileInputStream("D:/mycert.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
int i = 0;
Certificate cert = cf.generateCertificate(fin1);
trustStore.setCertificateEntry("cert " + i++, cert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustStore.load(null);
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLUtil sslUtil = new SSLUtil(trustManagers);
sslUtil.setDefaultSSLProtocol("TLSv1");
SSLSocketFactory sslServerSocketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(sslServerSocketFactory, server, port, user, password);
This code works. However we are running on a Websphere and all the certificates are located in the Websphere keystore. In this case I downloaded the cert and I'm loading it in from filesystem or resources. This is not what we want. We want to use the keystore of Websphere.
I tried this without defining thrustmanagers and keystores manually, but then I get certificate chaining errors all over the place.
Is there any way to configure UnboundId to use the websphere keystore ?
We had to settle in the end on a semi clean solution. We use the keystore files stored by the websphere server as input to the code.
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
File file = new File(keystoreLocation);
if(file.exists()){
FileInputStream keystoreFile = new FileInputStream(keystoreLocation);
trustStore.load(keystoreFile, keystorePassword.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLUtil sslUtil = new SSLUtil(trustManagers);
sslUtil.setDefaultSSLProtocol(sslProtocol);
SSLSocketFactory sslServerSocketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(sslServerSocketFactory, server, port, user, password);
return connection;
} else {
throw new TechnicalException("Keystore not found");
}
notice keystoreLocation this basically is the keystore file from websphere and kesystorePassword.toCharArray() is the websphere password for that particular keystore. It's not the cleanest of solutions but it got us going again. Maybe this helps others in the future
EDIT: Self-signed certificate installed on browser made it work.
I have configured jetty 9 embedded for http on port 8080 and https on port 8443. When I visit localhost:8080 I get my website and everything works, but when I try to access localhost:8443, I get this mess: image of unreadable stuff.
I pretty much mimicked the ManyConnectorsExample in the jetty documentation in order to set up a http connector and a https connector. Here is my code:
File keystoreFile = new File("config/myownkeystore.p12");
if (!keystoreFile.exists()){
throw new FileNotFoundException(keystoreFile.getAbsolutePath());
}
Server server = new Server();
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(8443);
http_config.setOutputBufferSize(32768);
ServerConnector http = new ServerConnector(server,
new HttpConnectionFactory(http_config));
http.setPort(8080);
http.setIdleTimeout(30000);
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreType("PKCS12");
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
sslContextFactory.setKeyStorePassword("myownstorepass");
sslContextFactory.setKeyManagerPassword("myownkeypass");
HttpConfiguration https_config = new HttpConfiguration(http_config);
SecureRequestCustomizer src = new SecureRequestCustomizer();
src.setStsMaxAge(2000);
src.setStsIncludeSubDomains(true);
https_config.addCustomizer(src);
ServerConnector https = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
https.setPort(8443);
https.setIdleTimeout(500000);
// Set the connectors
server.setConnectors(new Connector[] { http, https });
// servlet handler
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContextHandler.setResourceBase(".");
servletContextHandler.setContextPath("/");
servletContextHandler.addServlet(new ServletHolder(new MainServlet()), "/*");
// set the handlers
HandlerCollection handlerList = new HandlerCollection();
handlerList.setHandlers(new Handler[]{servletContextHandler});
server.setHandler(handlerList);
At first I thought that maybe the keystore type was at fault, since jetty uses jks by default. So I switched the sslcontext to use pkcs12 since the keystore is a .p12 file. That didn't help.
I checked the passwords next but the password for both private key and for the keystore are the same, so that can't be the issue.
At this point, I want to believe its a fault in my code somewhere, but I don't know what is wrong exactly.
I am not able to get mbeans from Weblogic server using PKCS12 ssl certificate through Java client.
Server: Weblogic
Client: Java client/JConsole
Server side commands used to create self signed certificates:
Created a certificate using the Weblogic CertGen utility, Weblogic CertGenCA.der and the Certificate Authority.
java utils.CertGen -certfile ServerCert -keyfile ServerKey -keyfilepass keypass
java utils.der2pem CertGenCA.der
type serverCert.pem CertGenCA.pem >> myCert.pem
Server Keystore created>>
java utils.ImportPrivateKey -keystore SeverIdentity.jks -storepass storepass -storetype JKS \
-keypass keypass -alias mykey -certfile myCert.pem -keyfile ServerKey.pem \
-keyfilepass keypass
Server Truststore used>>
DemoTrust.jks (Default Weblogic truststore)
Client side commands used to create PKCS12 self signed certificate:
java utils.CertGen -certfile ClientCert -keyfile ClientKey -keyfilepass keypass
openssl pkcs12 -export -in ClientCert.pem -inkey ClientKey.pem -out client-pkcs-12-cert
Configurations done in Weblogic Admin Console:
Keystores: Custom Identity Custom Trust.
Custom Identity Keystore: D:\certificate\latest\pkcs\SeverIdentity.jks
Custom Identity Keystore Type: JKS
Custom Identity Keystore Passphrase: storepass (same as –storepass value of ImportPrivateKey)
Confirm Custom Identity Keystore Passphrase: storepass
Custom Trust Keystore: D:\certificate\latest\pkcs\DemoTrust.jks
Custom Trust Keystore Type: JKS
Custom Trust Keystore Passphrase: DemoTrustKeyStorePassPhrase
Custom Trust Keystore Passphrase: DemoTrustKeyStorePassPhrase
Configurations done in setDomainEnv.cmd:
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9191 \
-Dcom.sun.management.jmxremote.ssl=true -Dcom.sun.management.jmxremote.authenticate=false \
-Djavax.net.ssl.keyStore=D:\certificate\latest\pkcs\SeverIdentity.jks \
-Djavax.net.ssl.keyStorePassword=keypass -Djavax.net.ssl.trustStore=D:\certificate\latest\pkcs\DemoTrust.jks \
-Djavax.net.ssl.trustStorePassword=DemoTrustKeyStorePassPhrase -Djava.rmi.server.hostname=10.112.69.200
Reference : http://www.weblogic-tips.com/2010/05/20/two-way-ssl-on-weblogic-server/
Java client code:
public static void main22(String args[]) {
try {
System.setProperty("javax.net.ssl.keyStore",
"D://certificate//latest//client-pkcs-12-cert");
System.setProperty("javax.net.ssl.keyStorePassword", "keypass");
HashMap<String, Object> env = new HashMap<String, Object>();
String truststore = "D://certificate//latest//client-pkcs-12-cert";
char truststorepass[] = "keypass".toCharArray();
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(new FileInputStream(truststore), truststorepass);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance("SunX509");
tmf.init(ks);
SSLContext ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory ssf = ctx.getSocketFactory();
env.put("jmx.remote.tls.socket.factory", ssf);
JMXServiceURL address = new JMXServiceURL("rmi", "", 0,
"/jndi/rmi://localhost:9191/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(address, env);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
Set<ObjectInstance> beans = mbsc.queryMBeans(null, null);
for (ObjectInstance instance : beans) {
MBeanInfo info = mbsc.getMBeanInfo(instance.getObjectName());
System.out.println(info);
}
jmxc.close();
} catch (Exception e) {
e.printStackTrace();
System.out.println("error :" + e.getMessage());
}
}
I am able to get mbeans when JKS certificate is being used but when I use PKCS12 certificate it gives the following error while connecting through JMXConnectorFactory:
Exception at line : JMXConnector jmxc = JMXConnectorFactory.connect(address, env);
Exceptions:
java.rmi.ConnectIOException: Exception creating connection to: 10.112.69.200; nested exception is:
java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:614)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:110)
at javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
at javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2327)
at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:277)
at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:248)
at test.Test.main(Test.java:68)
Caused by: java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
at javax.net.ssl.DefaultSSLSocketFactory.throwException(SSLSocketFactory.java:179)
at javax.net.ssl.DefaultSSLSocketFactory.createSocket(SSLSocketFactory.java:192)
at javax.rmi.ssl.SslRMIClientSocketFactory.createSocket(SslRMIClientSocketFactory.java:105)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
... 8 more
Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
at java.security.Provider$Service.newInstance(Provider.java:1245)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:220)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:147)
at javax.net.ssl.SSLContext.getInstance(SSLContext.java:125)
at javax.net.ssl.SSLContext.getDefault(SSLContext.java:68)
at javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:102)
at javax.rmi.ssl.SslRMIClientSocketFactory.getDefaultClientSocketFactory(SslRMIClientSocketFactory.java:192)
at javax.rmi.ssl.SslRMIClientSocketFactory.createSocket(SslRMIClientSocketFactory.java:102)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.transport.DGCImpl_Stub.dirty(Unknown Source)
at sun.rmi.transport.DGCClient$EndpointEntry.makeDirtyCall(DGCClient.java:342)
at sun.rmi.transport.DGCClient$EndpointEntry.registerRefs(DGCClient.java:285)
at sun.rmi.transport.DGCClient.registerRefs(DGCClient.java:121)
at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputStream.java:80)
at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCall.java:138)
at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292)
at sun.rmi.server.UnicastRef.done(UnicastRef.java:431)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:97)
at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:185)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at javax.management.remote.rmi.RMIConnector.findRMIServerJNDI(RMIConnector.java:1886)
at javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1856)
at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:255)
... 2 more
Caused by: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:544)
at sun.security.util.DerValue.init(DerValue.java:347)
at sun.security.util.DerValue.<init>(DerValue.java:303)
at com.sun.net.ssl.internal.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1200)
at java.security.KeyStore.load(KeyStore.java:1185)
at com.sun.net.ssl.internal.ssl.TrustManagerFactoryImpl.getCacertsKeyStore(TrustManagerFactoryImpl.java:202)
at com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl.getDefaultTrustManager(DefaultSSLContextImpl.java:70)
at com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl.<init>(DefaultSSLContextImpl.java:40)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:310)
at java.security.Provider$Service.newInstance(Provider.java:1221)
... 28 more
error :Exception creating connection to: 10.112.69.200; nested exception is:
java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
Firstly, ... (EDIT: I've realised I had misread part of the error, my first point was most certainly at least partly incorrect.)
A quick search for your error message (java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big. )points to this IBM support page, which suggests to use a JKS keystore instead of PKCS#12 (on the server side, which you're not doing) or that there are incorrect characters in the certificate.
Secondly, you have no chance to get client-certificate authentication working with this code, even once your server certificate problems are fixed.
String truststore = "D://certificate//latest//client-pkcs-12-cert";
char truststorepass[] = "keypass".toCharArray();
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(new FileInputStream(truststore), truststorepass);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance("SunX509");
tmf.init(ks);
SSLContext ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
The PKCS#12 file should contain both your client cert and its private key. It is meant to be used as a keystore, not a truststore. That is, although the entity is called keystore in both cases, you are meant to use it with the key manager, not the trust manager.
Here, you're using your PKCS#12 file to initialise the trust manager of your SSLContext. It's the key manager you should initialise instead.
In addition, if you're using your code with a JRE that isn't related to Sun/Oracle/OpenJDK, you should probably avoid to hard-code "SunX509", use TrustManagerFactory.getDefaultAlgorthim() instead (same for the KeyManagerFactory when you implement this stage).