I'm accessing an internal database using MATLAB's urlread command, everything was working fine until the service was moved to a secure server (i.e. with an HTTPS address rather than an HTTP address). Now urlread no longer successfully retrieves results. It gives an error:
Error downloading URL. Your network connection may be down or your proxy settings improperly configured.
I believe the problem is that the service is using an invalid digital certificate since if I try to access the resource directly in a web browser I get "untrusted connection" warning which I am able to pass through by adding the site to an Exception list. urlread doesn't have an obvious way of handling this problem.
Under the hood urlread is using Java to access web resources, and the error is thrown at this line:
inputStream = urlConnection.getInputStream;
where urlConnection is a Java object: sun.net.www.protocol.https.HttpsURLConnectionImpl.
Anyone suggest a workaround for this problem?
Consider the following Java class. Borrowing from this code: Disabling Certificate Validation in an HTTPS Connection
C:\MATLAB\MyJavaClasses\com\stackoverflow\Downloader.java
package com.stackoverflow;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.HostnameVerifier;
public class Downloader {
public static String getData(String address) throws Exception {
// 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(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Create a host name verifier that always passes
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
// open connection
URL page = new URL(address);
HttpURLConnection conn = (HttpURLConnection) page.openConnection();
BufferedReader buff = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// read text
String line;
StringBuffer text = new StringBuffer();
while ( (line = buff.readLine()) != null ) {
//System.out.println(line);
text.append(line + "\n");
}
buff.close();
return text.toString();
}
public static void main(String[] argv) throws Exception {
String str = getData("https://expired.badssl.com/");
System.out.println(str);
}
}
MATLAB
First we compile the Java class (we must use a JDK version compatible with MATLAB):
>> version -java
>> system('javac C:\MATLAB\MyJavaClasses\com\stackoverflow\Downloader.java');
Next we instantiate and use it MATLAB as:
javaaddpath('C:\MATLAB\MyJavaClasses')
dl = com.stackoverflow.Downloader;
str = char(dl.getData('https://expired.badssl.com/'));
web(['text://' str], '-new')
Here are a few URLs with bad SSL certificates to test:
urls = {
'https://expired.badssl.com/' % expired
'https://wrong.host.badssl.com/' % wrong host
'https://self-signed.badssl.com/' % self-signed
'https://revoked.grc.com/' % revoked
};
UPDATE: I should mention that starting with R2014b, MATLAB has a new function webread that supersedes urlread.
thanks for the solution. It worked, however, sometimes, I had received the following exception "java.io.IOException: The issuer can not be found in the trusted CA list." and I was not able to get rid of this error.
Therefore, I tried an alternative solution that works well. You can use the following Java code in Matlab function:
function str = ReadUrl(url)
is = java.net.URL([], url, sun.net.www.protocol.https.Handler).openConnection().getInputStream();
br = java.io.BufferedReader(java.io.InputStreamReader(is));
str = char(br.readLine());
end
Best,
Jan
Note also that the "canonical" way to solve this issue is to import the certificate into MATLAB's keystore (i.e., not your JVM's keystore).
This is documented here: Mathworks on using untrusted SSL certificates.
Related
I am distributing a library jar for internal clients, and the library includes a certificate which it uses to call a service that is also internal to our network.
The trust manager is set up as follows
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream keystoreStream =
clazz.getClassLoader().getResourceAsStream("certs.keystore"); // (on classpath)
keystore.load(keystoreStream, "pa55w0rd".toCharArray());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustManagers, null);
SSLSocketFactory socketFact = context.getSocketFactory();
connection.setSSLSocketFactory(socketFact);
All of this works fine except in cases where users need other certificates or the default certificate.
I tried this
Registering multiple keystores in JVM with no luck (I am having trouble generalizing it for my case)
How can I use my cert and still allow user libraries to use their own certs as well?
You are configuring a connection with a custom keystore acting as a truststore ( a certificate of your server that you trust). You are not overriding the default JVM behaviour, so the rest of the connection that other applications that include your library can make will not be affected.
Therefore you do not need a multiple keystore manager, in fact, your code works perfectly.
I've attached a full example below using a keystore google.jks which includes Google's root CA, and a connection using the default JVM truststore. This is the output
request("https://www.google.com/", "test/google.jks", "pa55w0rd"); //OK
request("https://www.aragon.es/", "test/google.jks", "pa55w0rd"); // FAIL sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
request("https://www.aragon.es/", null, null); //OK
The problem is not in the code you have attached, so check the following in your code:
The truststore certs.keystore is really found in your classpath
Truststore settings are not set at JVM level using -Djavax.net.ssl.trustStore
The errors found (please include it in your question) are really related to the SSL connection
package test;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
public class HTTPSCustomTruststore {
public final static void main (String argv[]) throws Exception{
request("https://www.google.com/", "test/google.jks", "pa55w0rd"); //Expected OK
request("https://www.aragon.es/","test/google.jks","pa55w0rd"); // Expected FAIL
request("https://www.aragon.es/",null,null); //using default truststore. OK
}
public static void configureCustom(HttpsURLConnection connection, String truststore, String pwd)throws Exception{
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream keystoreStream = HTTPSCustomTruststore.class.getClassLoader().getResourceAsStream(truststore);
keystore.load(keystoreStream, pwd.toCharArray());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustManagers, new java.security.SecureRandom());
SSLSocketFactory socketFact = context.getSocketFactory();
connection.setSSLSocketFactory(socketFact);
}
public static void request(String urlS, String truststore, String pwd) {
try {
URL url = new URL(urlS);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
if (truststore != null) {
configureCustom((HttpsURLConnection) conn, truststore, pwd);
}
conn.connect();
int statusCode = conn.getResponseCode();
if (statusCode != 200) {
System.out.println(urlS + " FAIL");
} else {
System.out.println(urlS + " OK");
}
} catch (Exception e) {
System.out.println(urlS + " FAIL " + e.getMessage());
}
}
}
You could import the default certificates into your custom store to have a combined custom store and use that.
I know that to load a certificate to use, I need to call KeyStore.load(InputStream, char[]);. How could I load the certificate on the client side if I need the password? I don't need this when connecting to Google, but I want to use Trust Managers to validate Google certificates. I also cannot make a SSLServerSocket and connect to it without loading a certificate.
EDIT: Added code:
package testing;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLClientTest {
public static void main(String[] args) {
int port = 443;
String host = "google.com";
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
KeyStore ks = KeyStore.getInstance("JKS");
InputStream ksIs = new FileInputStream("securecert.certificate");
try {
ks.load(ksIs, "pwdpwdpwd".toCharArray());
} finally {
if (ksIs != null) {
ksIs.close();
}
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "pwdpwdpwd".toCharArray());
sc.init(kmf.getKeyManagers(),
new TrustManager[] { new MyTrustManager() }, null);
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.startHandshake();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
System.out.println(in.readLine());
in.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static final class MyTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
}
Note that I have to load the certificate, securecert.certificate, at the like of code ks.load(InputStream, char[]); I of course know the password, but what if I don't? Then how could I validate the certificate with a trust manager? This code simply locks. Please answer. Thanks!
Seems that you need a client authentication through SSL and you want let the user enter the password for his keystore. Based on your explanation I suppose that each installed client has its own keystore from a local path (If not the question has nonsense because if the keystore is always the same you don't need to pass a different password each time... however if this is the case you've to check if this client it's secure).
So to let the user enter a password you can instantiate the keystore in a different way instead of using KeyStore.getInstance(InputStream, Char[]), you can use KeyStore.Builder.newInstance and KeyStore.CallbackHandlerProtection methods, and you have to create a class which implements javax.security.auth.callback.CallbackHandler, this class have to override handle() method for example using swing or awt panel to let the user introduce the password. Below I show you some sample code to guide you through this steps:
Load the keystore
import java.io.File;
import java.security.KeyStore;
import java.security.Provider;
import java.util.Enumeration;
public class KeyStoreCallbackSample {
public static void main(String args[]) throws Exception {
// instantiate a keystore to get the provider for specific type
KeyStore ks = KeyStore.getInstance("JKS");
// create the callback handler to get the password
KeyStore.CallbackHandlerProtection cbhp = new KeyStore.CallbackHandlerProtection(new YourImplementationCallbackHander());
// create the builder passing keystoreType, provider, keystore file, and callbackhandler
KeyStore.Builder builder = KeyStore.Builder.newInstance("JKS", ks.getProvider(), new File("/path/YourKeyStore.jks"), cbhp);
// create the keystore
ks = builder.getKeyStore();
// print the keystores alias to check if all it's load correctly
Enumeration<String> aliases = ks.aliases();
while(aliases.hasMoreElements()){
System.out.println(aliases.nextElement());
}
}
}
CallbackHandler implementation
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
/**
* PIN handler for keystores
*/
public class PinInputHandler implements CallbackHandler {
private char[] lastPassword;
public PinInputHandler(){}
// implement this method to handle the callback
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback cb : callbacks) {
if (cb instanceof javax.security.auth.callback.PasswordCallback) {
javax.security.auth.callback.PasswordCallback pcb = (javax.security.auth.callback.PasswordCallback) cb;
try {
this.lastPassword = // HERE YOUR SWING OR AWT OR ANOTHER WAY TO GET THE PASSWORD FROM THE CLIENT
} catch (Exception e) {}
pcb.setPassword(this.lastPassword);
}
}
}
}
If you need more info you can check at KeyStore, KeyStore.Builder, KeyStore.CallbackHandlerProtection and CallbackHandlerdocumentation.
Hope this helps,
I need to extract expiration date from SSL certificate on web site in Java,should support both
trusted and self-signed certificate,such as:
1.trusted
https://github.com
2.self-signed
https://mms.nw.ru/
I already copy some code as:
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLTest {
public static void main(String [] args) throws Exception {
// configure the SSLContext with a TrustManager
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
URL url = new URL("https://github.com");//https://mms.nw.ru
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
System.out.println(conn.getResponseCode());
Certificate[] certs = conn.getServerCertificates();
for (Certificate cert :certs){
System.out.println(cert.getType());
System.out.println(cert);
}
conn.disconnect();
}
private static class DefaultTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}
The questions are:
How to parse the expiration date from the certificate, in my code the toString() did output the date,but it is hard to parse.
How to determine the certificate chain, eg, the github certificate with chains 3, how did i know which certificate to get the expiration date from?
How to parse the expiration date from the certificate
Cast it to an X509Certificate and call getNotAfter().
How to determine the certificate chain, eg, the github certificate with chains
You've got it. That's what the Certificate[] array is, as it says in the Javadoc.
How did i know which certificate to get the expiration date from?
Read the Javadoc. "The peer's own certificate first followed by any certificate authorities".
However I don't know why you're doing any of this. Java should already do it all for you.
And please throw away that insecure and incorrect TrustManager implementation. The correct way to handle self-signed certificates is to import them into the client truststore. Please also throw away your insecure HostnameVerifier, and use the default one, or a secure one. Why use HTTPS at all if you don't want it to be secure?
Make sure you append Begin/End lines to PEM format otherwise java does not understand it.
public class CertTest {
public static final String cert = "-----BEGIN CERTIFICATE-----\n<CERT_DATA>\n-----END CERTIFICATE-----";
public static void main(String[] args){
try {
X509Certificate myCert = (X509Certificate)CertificateFactory
.getInstance("X509")
.generateCertificate(
// string encoded with default charset
new ByteArrayInputStream(cert.getBytes())
);
System.out.println(myCert.getNotAfter());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In Kotlin way, it should look something like this:
fun certInformation(aURL: String) {
val destinationURL = URL(aURL)
val conn = destinationURL.openConnection() as HttpsURLConnection
conn.connect()
val certs = conn.serverCertificates
for (cert in certs) {
println("Certificate is: $cert")
if (cert is X509Certificate) {
println(cert.issuerDN.name)
println(cert.notAfter)
println(cert.notBefore)
}
}
}
am trying to change the truststore path dynamically using java web application.
am developing struts application and login is based on ldap through secure socket layer (ssl) connection.
To connect with ssl i have created .cer file using java keytool option.
Now i able to connect with ldap and i can retieve user information from ldap.
when i change the ssl certificate(invalid certificate for testing) dynamically it could not give any exceptions. but it works when i restart the tomcat
server.
following is the code that i am trying
try{
java.io.InputStream in = new java.io.FileInputStream("C:\\test.cer");
java.security.cert.Certificate c = java.security.cert.CertificateFactory.getInstance("X.509").generateCertificate(in);
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
ks.load(null);
if (!ks.containsAlias("alias ldap")) {
ks.setCertificateEntry("alias ldap", c);
}
java.io.OutputStream out = new java.io.FileOutputStream("C:\\ldap.jks");
char[] kspass = "changeit".toCharArray();
ks.store(out, kspass);
out.close();
System.setProperty("javax.net.ssl.trustStore", "C:\\ldap.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
}catch(Exception e){
e.printStackTrace();
}
is there any mistake that i made with the code?
does any new code that i need to put to connect dynamically?
Note :
instead of c:\ldap.jks file i gave invalid file dynamically. it does not give any exception.
Edited (checked with custom TrustManager) :
i also implemented TrustManager and ssl context is initialized with custom trust manager.
but i am not able to get the expected behaviour
could u please help me. the code that i tried is
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.UUID;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class TestDynamicSSLCert {
public static void main(String[] args)throws NamingException,IOException {
DataInputStream din = new DataInputStream (System.in);
String yes = "yes";
String certpath = "C:\\cert.cer";
String ldappath1 = "C:\\ldap.jks";
String ldappath2 = "C:\\ldap.jks"; // setting valid key store path
while("yes".equalsIgnoreCase(yes.trim())){
System.out.println(" ldappath2 : "+ldappath2);
Hashtable env = new Hashtable();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL,"uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://172.16.12.4:636/ou=system");
try {
java.io.InputStream in = new java.io.FileInputStream(certpath);
java.security.cert.Certificate c = java.security.cert.CertificateFactory.getInstance("X.509").generateCertificate(in);
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
ks.load(null);
if (!ks.containsAlias("alias ldap")) {
ks.setCertificateEntry("alias ldap", c);
}
java.io.OutputStream out = new java.io.FileOutputStream(ldappath1);
char[] kspass = "changeit".toCharArray();
ks.store(out, kspass);
out.close();
System.setProperty("javax.net.ssl.trustStore", ldappath2);
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
// Custorm trust manager
MyX509TrustManager reload = new MyX509TrustManager(ldappath2,c);
TrustManager[] tms = new TrustManager[] { reload };
javax.net.ssl.SSLContext sslCtx = javax.net.ssl.SSLContext.getInstance("SSL");
sslCtx.init(null, tms, null);
// Custom trust manager
} catch (Exception e) {
e.printStackTrace();
}
DirContext ctx = new InitialDirContext(env);
NamingEnumeration enm = ctx.list("");
while (enm.hasMore()) {
System.out.println(enm.next());
}
ctx.close();
System.out.println(" Go again by yes/no :");
yes = din.readLine();
ldappath2 = "C:\\invalidldap.jks"; // setting invalid keystore path
}
}
}
class MyX509TrustManager implements X509TrustManager {
private final String trustStorePath;
private X509TrustManager trustManager;
private List<Certificate> tempCertList = new ArrayList<Certificate>();
public MyX509TrustManager(String tspath,Certificate cert)throws Exception{
this.trustStorePath = tspath;
tempCertList.add(cert);
reloadTrustManager();
}
public MyX509TrustManager(String tspath)
throws Exception {
this.trustStorePath = tspath;
reloadTrustManager();
}
#Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
trustManager.checkClientTrusted(chain, authType);
}
#Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
try {
trustManager.checkServerTrusted(chain, authType);
} catch (CertificateException cx) {
addServerCertAndReload(chain[0], true);
trustManager.checkServerTrusted(chain, authType);
}
}
#Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] issuers = trustManager.getAcceptedIssuers();
return issuers;
}
private void reloadTrustManager() throws Exception {
// load keystore from specified cert store (or default)
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = new FileInputStream(trustStorePath);
try {
ts.load(in, null);
} finally {
in.close();
}
// add all temporary certs to KeyStore (ts)
for (Certificate cert : tempCertList) {
ts.setCertificateEntry(UUID.randomUUID().toString(), cert);
}
// initialize a new TMF with the ts we just loaded
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
// acquire X509 trust manager from factory
TrustManager tms[] = tmf.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
trustManager = (X509TrustManager) tms[i];
return;
}
}
throw new NoSuchAlgorithmException("No X509TrustManager in TrustManagerFactory");
}
private void addServerCertAndReload(Certificate cert,
boolean permanent) {
try {
if (permanent) {
// import the cert into file trust store
// Google "java keytool source" or just ...
Runtime.getRuntime().exec("keytool -importcert ...");
} else {
tempCertList.add(cert);
}
reloadTrustManager();
} catch (Exception ex) { /* ... */ }
}
}
Expected Behaviour :
ldap connection should be successfull with valid keystore file (during first loop ).
if user give yes then invalid keystore is assigned and need to produce exception and should not connect to ldap
Actual Behaviour:
for both valid keystore file i able to retrieve information from ldap.
Note :
if i set String ldappath2 = "C:\invalidldap.jks"; at begining, it gives exception.
Why am doing this ?
#EJP, because, i need to develope module which is based on ldap authentication securely. module should support multiple ldap servers. ldap settings can be inserted from the UI (webpage that has the ui to get the details like ldaphost, port, basedn, and ssl certificate) and this details should go to database. at the same time certificate also present in database. work for module is just retrieve the users from ldap and store it to another table. so if we change the new ldap server setting with new certificate means, System.setProperty("javax.net.ssl.trustStore","truststorepath") will fail. are you okay with my explanation?
You are correct. You have to restart Tomcat when you change the keystore or truststore. You don't need to write code to load client certificates, you just need to make sure you are dealing with servers whose certificates are signed by a CA that you trust. Adding new certificates at runtime is radically insecure.
Is there any other way to connect ldap securely with out using above
steps?
Yes, but why do you think you need to know?
Does the application (tomcat or single java file) should be restarted
whenever trustStore property is updated ?
Yes.
I am trying to write an SSL client that sends mail using the javax.mail API. The problem I am having is that the server request that I use SSL, but the server is also configured with a non-standard SSL certificate. The web pages I have found say that I need to install the certificate into the trust store. I don't want to do that (I don't have the necessary permissions.)
Is there a way to get Java to just ignore the certificate error and accept it?
Failing that, is there a way to have the trust store be local for my program, and not installed for the whole JVM?
Working code ( in jdk1.6.0_23) for #1.
Imports
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
The actual trust all TrustManager code.
TrustManager trm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { trm }, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
You need to create a fake TrustManager that accepts all certificates, and register it as a manager. Something like this:
public class MyManager implements com.sun.net.ssl.X509TrustManager {
public boolean isClientTrusted(X509Certificate[] chain) { return true; }
public boolean isHostTrusted(X509Certificate[] chain) { return true; }
...
}
com.sun.net.ssl.TrustManager[] managers =
new com.sun.net.ssl.TrustManager[] {new MyManager()};
com.sun.net.ssl.SSLContext.getInstance("SSL").
.init(null, managers, new SecureRandom());
Try this (answer to question 2):
System.setProperty("javax.net.ssl.trustStore", "/path/to/truststore");
You can also specify this as an additional command line parameter:
java -Djavax.net.ssl.trustStore=/path/to/truststore <remaining arguments>
On Fedora this could be the system wide java trust store in /etc/pki/java/cacerts
Just add -Dtrust_all_cert=true to VM arguments. This argument tells java to ignore all certificate checks.
In Command Line you can add argument -noCertificationCheck to java to ignore the certificate checks.