Java : javax.net.ssl.SSLHandshakeException - java

Given the following code:
public void start(String a_sAddress, int a_nPort) throws IOException {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
// TODO Auto-generated method stub
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
// TODO Auto-generated method stub
}
} };
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init( null, trustAllCerts, new java.security.SecureRandom() );
// Init a configuration with our SSL context
HttpsConfigurator configurator = new HttpsConfigurator(sslContext);
HttpsServer server = HttpsServer.create(new InetSocketAddress(a_sAddress, a_nPort), 0);
server.setHttpsConfigurator(configurator);
//here - attaching HttpHanlder code.
server.setExecutor(null); // creates a default executor
server.start();
}
catch (KeyManagementException e) {
System.out.println("HttpsRequest - setTLSMode - KeyManagementException");
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
System.out.println("HttpsRequest - setTLSMode - NoSuchAlgorithmException");
e.printStackTrace();
}
}
I was trying to ignore certificate verification, since I am only a test simulator.
The problem is that my client gets "javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake"
Must I handle certificates here? Or am I failing in trying to ignore the certificates validation?
Thank you.
Update: Well, talking to some friends, they suggested I should create a self-signed certificate, register my server with it and send it to my client to use when sending me requests.
My server is running on Solaris 10. I tried to look in
The Most Common Java Keytool Keystore Commands
but couldn't figure out the specific commands which fits my needs.
Can you please assist?
Thanks

You need
keytool -genkey ...
to generate a keypair, and then
keytool -selfcert ...
to generate a self-signed certificate, using the same alias.

Related

Access denied ("javax.net.ssl.SSLPermission" "setDefaultSSLContext")

I am using below code to trust all certificates and the code is running in a containerized environment, I am getting exception as Access denied ("javax.net.ssl.SSLPermission" "setDefaultSSLContext") and same code which is running on normal tomcat server is working fine
URL destinationURL = null;
SSLContext context = null;
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
//return new X509Certificate[1];
return null;
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//DO
}
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//DO
}
}
};
try {
context = SSLContext.getInstance("SSL");
context.init(null, trustAllCerts, null);
SSLContext.setDefault(context);
//proxy details here
destinationURL = new URL('url');
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception e) {
e.printStackTrace();
}
You can use specified SSLContext to build socketfactory which can be used for URL Connections, changing the default one is not recommended.
From SSLContext:
setDefault
Throws: SecurityException - if a security manager exists and its checkPermission method does not allow SSLPermission("setDefaultSSLContext")
This permission is not granted by default, as it is considered unsafe. From SSLPermission:
Malicious code can set a context that monitors the opening of connections or the plaintext data that is transmitted.
The recommended way to change the default SSLContext is via JVM start-up options. However, you're attempting to effectively disable all trust, which is also unsafe and not supported via system properties.
If you're really really sure you want to do this, you'll need to grant your application the necessary permissions. This would e.g. be via a policy file:
grant codeBase "file:/home/ajay/myunsafecode" {
permission javax.net.ssl.SSLPermission "setDefaultSSLContext";
};
Or, just don't change the default SSLContext and use your unsafe one directly.
(all links for JDK 11)

SSLContextBuilder fails to loadKeyMaterial

I'm trying to use Apache httpclient-4.5.5 (with httpcore-4.4.9) to obtain the server certificate from a server that applies 'mutual SSL'. I'm creating an SSLContext as follows:
final String keystorePass = Configuration.getInstance().getItem(EmittentProperties.keystorePass);
final String kmopEncKeyPass = Configuration.getInstance().getItem(EmittentProperties.kmopEncKeyPass);
final String kmopEncKeyAlias = Configuration.getInstance().getItem(EmittentProperties.kmopEncKeyAlias);
//1.Create the SSLContext and SSLConnectionSocketFactory
SSLContext sslContext;
try {
sslContext = SSLContexts.custom()
.loadKeyMaterial(keystoreFile.getFile(), keystorePass.toCharArray(), kmopEncKeyPass.toCharArray(), new PrivateKeyStrategy() {
#Override
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
return kmopEncKeyAlias;
}})
.loadTrustMaterial(new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}})
.build();
} catch (Exception e) {
logger.error("Error initializing SSLContext: " + e.getMessage(), e);
throw new FatalException(e.getMessage(), e);
}
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
However it always returns "java.security.UnrecoverableKeyException: Cannot recover key" on the loadKeyMaterial(...).
While debugging this method I can see that he succesfully loads the keystore and that it contains the keys I created in it. However when subsequently trying to load the key entry associated with the password kmopEncKeyPass it returns the UnrecoverableKeyException.
My (JKS) keystore has two (self-signed) entries 'kmop-enc' used for the SSL handshake and 'kmop-sign' for SSL signing of messages. The password for the alias kmop-enc (parameter kmopEncKeyPass) is the same as the password for the keystore (parameter keystorePass). With the custom PrivateKeyStrategy I want to make sure 'kmop-enc' is returned as alias and not 'kmop-sign' (which has a different password).
Verifying my keystore with keystore-explorer.org shows everything is OK with my keystore. Any ideas on why it throws an UnrecoverableKeyException?
Needed to add .setKeyStoreType("JKS") before calling .loadKeyMaterial(...).

javax.net.ssl.SSLException: Received fatal alert: bad_record_mac

I'm getting a javax.net.ssl.SSLException: Received fatal alert: bad_record_mac for an HTTPS connection. This doesn't happen for every request -- if I send the same request in 10 times I only get this error once or twice.
I have the following code to validate the certificate:
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
try {
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSLv3");
} catch (NoSuchAlgorithmException e3) {
logException(Arrays.toString(e3.getStackTrace()));
}
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory factory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(factory);
} catch (KeyManagementException e) {
logException(Arrays.toString(e.getStackTrace()));
}
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/*
* end of the fix
*/
I've set two system properties in my main method:
System.setProperty("jsse.enableSNIExtension", "false");
System.setProperty("https.protocols", "SSLv3");
But nothing helps.
According to this rubygems issue and the detailed description of the error (see below), it appears to be a bug in Oracle's JDK that is not present in OpenJDK. I recall (but cannot verify) that there was a bug in OpenSSL that also caused this error, so you may want to check the software on the other side of the connection.
You can read more details about what this error means here.
It is a hard to say what causing this. You need to find out by analyzing the logs. Enable debug by setting property:
System.setProperty("javax.net.debug", "all");
and check what is wrong.
A problem may be that the server is not supporting TLS, which may be picked by the implementation. To make sure that you always use the plain SSLv3 set the property:
System.setProperty("https.protocols", "SSLv3");
Try set com.sun.net.ssl.rsaPreMasterSecretFix to true.

Setting trust store programatically in ActiveMQSslConnectionFactory seems to fail

I have been working on a java activemq client software to connect to a ssl powered broker, but setting the trust store programatically through:
// Configure the secure connection factory.
ActiveMQSslConnectionFactory connectionFactory = new ActiveMQSslConnectionFactory(url);
connectionFactory.setTrustStore("/conf/client.ts"); // truststore which includes the certificate of the broaker
connectionFactory.setTrustStorePassword("password");
as indicated here. However, that throw a
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed
Error
Following the response of the QA Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error? I was able to successfully connect the client to the broker by adding the broker certificate to my java installation's trusted certificates.
However, in this case, I do not want each user using the application to import the certificate on their java distribution, but rather that the client application already carries the broker certificate. How can I do that preferably using the ActiveMQSslConnectionFactory class?
From what I understand, you need to trust all the incoming self-signed certificates.
You could try this way (create a trust-manager which does not validate and then register it:
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certificates, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certificates, String authType) {
}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
} catch (GeneralSecurityException e) {
}
//then do the ssl conversation.
I still havent managed to set the truststore programattically using the setTrustStore method from ActiveMQSslConnectionFactory
But based on #Chris response, it was possible to attach a new trust manager which accept all certificates to the ActiveMQSslConnectionFactory.
In order to do so, I created the same TrustManager as him, but used a different method to link it to the ActiveMQSslConnectionFactory
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certificates, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certificates, String authType) {
}
}
};
try {
String connectionString = "ssl://ipaddress:port"
ActiveMQSslConnectionFactory factory = new ActiveMQSslConnectionFactory(connectionString);
factory.setKeyAndTrustManagers(null, trustAllCerts, new SecureRandom());
Connection connection = factory.createConnection(user,password);
connection.start();
} catch (Exception e) {
}

Make a connection to a HTTPS server from Java and ignore the validity of the security certificate

I've been testing a system that accesses a group of https servers with different keys, some of which are invalid and all of them are not in the local key store for my JVM. I am really only testing things out, so I don't care about the security at this stage. Is there a good way to make POST calls to the server and tell Java not to worry about the security certificates?
My google searches for this have brought up some code examples that make a class to do the validation, that always works, but I cannot get it to connect to any of the servers.
As per the comments:
With Googled examples, you mean among others this one?
Update: the link broke, so here's an extract of relevance which I saved from the internet archive:
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}
// Now you can access an https URL without having the certificate in the truststore
try {
URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}
You need to create a X509TrustManager which bypass all the security check. You can find an example in my answer to this question,
How to ignore SSL certificate errors in Apache HttpClient 4.0

Categories