I have a pretty brittle and complicated development setup. I have a ssh tunnel to a machine that exposes a machine on that network, when ssh tunnel is in place, I can access my api easily via Postman or curl like this.
curl -X GET -u admin:admin123 -k "https://172.23.1.175/api/storage/aggregates/?fields=space&return_records=true&return_timeout=15" -H "accept: application/hal+json"
My client code is created via swagger, for development purpose I want to be able to try within my java application in IntelliJ to make the actual API call. I know this is completely frowned up on. The error I get is this:
io.swagger.ontap.client.ApiException: javax.net.ssl.SSLPeerUnverifiedException: Hostname localhost not verified:
certificate: sha1/o6KF0+STnresD1HaPMVoHNMgwpY=
DN: C=US, CN=ontapcloud-net0ejmuaf-1
subjectAltNames: []
This is a newer error after I tried to import the cert to my java config, before it was like this.
cause javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Can the code below be modified to accommodate so the request will pass through?
private void applySslSettings() {
try {
TrustManager[] trustManagers = null;
HostnameVerifier hostnameVerifier = null;
System.out.println("verifyingSsl: " + verifyingSsl);
if (!verifyingSsl) {
TrustManager trustAll = new X509TrustManager() {
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
#Override
public X509Certificate[] getAcceptedIssuers() { return null; }
};
SSLContext sslContext = SSLContext.getInstance("TLS");
trustManagers = new TrustManager[]{ trustAll };
hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) { return true; }
};
} else if (sslCaCert != null) {
char[] password = null; // Any password will work.
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(sslCaCert);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
KeyStore caKeyStore = newEmptyKeyStore(password);
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = "ca" + Integer.toString(index++);
caKeyStore.setCertificateEntry(certificateAlias, certificate);
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(caKeyStore);
trustManagers = trustManagerFactory.getTrustManagers();
}
if (keyManagers != null || trustManagers != null) {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
httpClient.setSslSocketFactory(sslContext.getSocketFactory());
} else {
httpClient.setSslSocketFactory(null);
}
httpClient.setHostnameVerifier(hostnameVerifier);
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
The solution was rather simple, there is attribute that swagger offers that took care of my issue.
ApiClient apiClient = new ApiClient();
apiClient.setBasePath("https://localhost:8077/api");
apiClient.setVerifyingSsl(false);
Related
I am trying to implement ssl support in my volley request (also I saw answers in SO with similar issues, but it does not help me)
With help of this article I converted my certificate extension from .cer to .bks
That according to this SO answer I do next
mRequestQueue = Volley.newRequestQueue(this, hurlStack);
private HurlStack hurlStack = new HurlStack()
{
#Override
protected HttpURLConnection createConnection(URL url) throws IOException
{
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super.createConnection(url);
try
{
httpsURLConnection.setSSLSocketFactory(getSSLSocketFactory());
httpsURLConnection.setHostnameVerifier(getHostnameVerifier());
}
catch (Exception e)
{
AppUtils.printLog(Log.ERROR, TAG, e.getMessage());
}
return httpsURLConnection;
}
};
private SSLSocketFactory getSSLSocketFactory() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.keystore); // this cert file stored in \app\src\main\res\raw folder path
Certificate ca = cf.generateCertificate(caInput);
caInput.close();
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, wrappedTrustManagers, null);
return sslContext.getSocketFactory();
}
// Let's assume your server app is hosting inside a server machine
// which has a server certificate in which "Issued to" is "localhost",for example.
// Then, inside verify method you can verify "localhost".
// If not, you can temporarily return true
private HostnameVerifier getHostnameVerifier()
{
return new HostnameVerifier()
{
#Override
public boolean verify(String hostname, SSLSession session)
{
//return true; // verify always returns true, which could cause insecure network traffic due to trusting TLS/SSL server certificates for wrong hostnames
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify("localhost", session);
}
};
}
private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers)
{
final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
return new TrustManager[] {new X509TrustManager()
{
public X509Certificate[] getAcceptedIssuers()
{
return originalTrustManager.getAcceptedIssuers();
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
{
try
{
if (certs != null && certs.length > 0)
{
certs[0].checkValidity();
}
else
{
originalTrustManager.checkClientTrusted(certs, authType);
}
}
catch (CertificateException e)
{
Log.w("checkClientTrusted", e.toString());
}
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
{
try
{
if (certs != null && certs.length > 0)
{
certs[0].checkValidity();
}
else
{
originalTrustManager.checkServerTrusted(certs, authType);
}
}
catch (CertificateException e)
{
Log.w("checkServerTrusted", e.toString());
}
}
}};
}
And I get next error
com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG
And because of this I get such respond
Bad Request
Bad Request - Invalid Header
HTTP Error 400. The request has an invalid header name.
What am I doing wrong?
Feel free to ask
EDIT 1
so now my getSSLSocketFactory() method look like this
private SSLSocketFactory getSSLSocketFactory() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException
{
InputStream ksInStream = getResources().openRawResource(R.raw.keystore);
KeyStore ks = KeyStore.getInstance("BKS");
ks.load(ksInStream, SslUtils.KEYSTORE_PASSWORD_SSL.toCharArray());
// Certificate cert = ks.getCertificate("alias");
// ks.setCertificateEntry("ca", cert);
ksInStream.close();
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(ks);
TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, wrappedTrustManagers, null);
return sslContext.getSocketFactory();
}
Now I did not get message about wrong TAG , but I still get bad respond
ResponseJsonString =
Bad Request
Bad Request - Invalid Header
HTTP Error 400. The request has an invalid header name.
In this code you seem to load keystore in BKS format as it would be X.509 encoded certificate, which is bound to fail
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.elalkeystore);
Certificate ca = cf.generateCertificate(caInput);
caInput.close();
You can load keystore like this:
InputStream ksInStream = getResources().openRawResource(R.raw.elalkeystore);
KeyStore ks = KeyStore.getInstance("BKS");
ks.load(ksInStream, keystorePasswordCharArray);
Certificate cert = ks.getCertificate("entryAlias");
ksInStream.close();
Eventually I did not find solution for the issue, I found another approach for implementation
So follow this article
http://ogrelab.ikratko.com/using-android-volley-with-self-signed-certificate/
also if there is any issue about converting .cer to .bks here my SO question and answer
Extension of certificate .cer convert to .bks
I have to consume a rest service which is running on HTTPs. The producer has given me the certificate and method arguments. Could you please let me know how to consume the service and how to use the certificate in code. I am using Spring 4, Java 8. Please share the code snippet.
If it is just an one way SSL where consumer validates the identity of the service, you simply need to import the certificate provided by the service(producers certificate) to you trust store (CACerts file) or write your own trust manager.
For 2 Way SSL where service also authenticate the client's identity, you not only need to validate the identity of the service, you also need to send your certificate to the service so that service can take decision on it.
Following snippet is for 2 way SSL, but you can easily adopt it to 1 way SSL by commenting out the portion which sends client certicate to the server.
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){return null;}
public void checkClientTrusted(X509Certificate[] certs, String authType){}
public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};
// Install the all-trusting trust manager
RestTemplate restTemplate = new RestTemplate();
try {
String keyPassphrase = "changeit";
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(new FileInputStream("c:\\jks\\client.jks"), keyPassphrase.toCharArray());
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keyStore, keyPassphrase.toCharArray());
KeyManager[] keyManager = kmfactory.getKeyManagers();
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(keyManager, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
if (hostname.equals("localhost")) {
return true;
}
return false;
}
});
} catch (Exception e) {
;
}
System.out.println("Testing listAllUsers API-----------");
restTemplate.setErrorHandler(new ResponseErrorHandler(){
#Override
public void handleError(ClientHttpResponse rs) throws IOException {
InputStream in = rs.getBody();
String str = new String("");
int len =0;
while((len = in.available()) > 0){
byte[] bytes = new byte[len];
in.read(bytes);
str = str + new String (bytes, "UTF-8");
}
System.out.println(str);
}
#Override
public boolean hasError(ClientHttpResponse rs) throws IOException {
return false;
}
});
try{
String usersMap = restTemplate.getForObject(REST_SERVICE_URI+"/user/shailendra/", String.class);`
I'm developing an hybrid cordova app which might connect to different servers. Some of them do require a client certificate.
On an Android mobile the corresponding root cert + client certificate is installed.
On Chrome browser I get the following dialog to choose the corresponding client certificate for the Web connection.
With the cordova plugin cordova-client-cert-authentication the same dialog pops up for Http(s) requests within the WebView.
My question is how to achieve a automatic certificate selection on Http(s) requests on the native Android platform without explicitly declaring the corresponding client certificate. Or is there something similiar to the user selection of certificate like implemented on Chrome?
This is the current implementation, which throws a handshake exception:
try {
URL url = new URL( versionUrl );
HttpsURLConnection urlConnection = ( HttpsURLConnection ) url.openConnection();
urlConnection.setConnectTimeout( 10000 );
InputStream in = urlConnection.getInputStream();
}
catch(Exception e)
{
//javax.net.ssl.SSLHandshakeException: Handshake failed
}
You can use a certificate previously installed in Android KeyChain (the system key store) extending X509ExtendedKeyManager to configure the SSLContext used by URLConnection
The certificate is referenced by an alias that you need. To prompt user for selection with a dialog similar to chrome use:
KeyChain.choosePrivateKeyAlias(this, this, // Callback
new String[] {"RSA", "DSA"}, // Any key types.
null, // Any issuers.
null, // Any host
-1, // Any port
DEFAULT_ALIAS);
This is the code to configure the SSL connection using a custom KeyManager. It uses the default TrustManager and HostnameVerifier. You will need to configure them if the server is using a self signed certificate not present in Android default truststore (trusting all certificates is not recommended)
//Configure trustManager if needed
TrustManager[] trustManagers = null;
//Configure keyManager to select the private key and the certificate chain from KeyChain
KeyManager keyManager = KeyChainKeyManager.fromAlias(
context, mClientCertAlias);
//Configure SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] {keyManager}, trustManagers, null);
//Perform the connection
URL url = new URL( versionUrl );
HttpsURLConnection urlConnection = ( HttpsURLConnection ) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
//urlConnection.setHostnameVerifier(hostnameVerifier); //Configure hostnameVerifier if needed
urlConnection.setConnectTimeout( 10000 );
InputStream in = urlConnection.getInputStream();
Finally here you have and a full implementation of the custom X509ExtendedKeyManager extracted from here and here that is in charge of selecting the client certificate. I have extracted the required code.
public static class KeyChainKeyManager extends X509ExtendedKeyManager {
private final String mClientAlias;
private final X509Certificate[] mCertificateChain;
private final PrivateKey mPrivateKey;
/**
* Builds an instance of a KeyChainKeyManager using the given certificate alias.
* If for any reason retrieval of the credentials from the system {#link android.security.KeyChain} fails,
* a {#code null} value will be returned.
*/
public static KeyChainKeyManager fromAlias(Context context, String alias)
throws CertificateException {
X509Certificate[] certificateChain;
try {
certificateChain = KeyChain.getCertificateChain(context, alias);
} catch (KeyChainException e) {
throw new CertificateException(e);
} catch (InterruptedException e) {
throw new CertificateException(e);
}
PrivateKey privateKey;
try {
privateKey = KeyChain.getPrivateKey(context, alias);
} catch (KeyChainException e) {
throw new CertificateException(e);
} catch (InterruptedException e) {
throw new CertificateException(e);
}
if (certificateChain == null || privateKey == null) {
throw new CertificateException("Can't access certificate from keystore");
}
return new KeyChainKeyManager(alias, certificateChain, privateKey);
}
private KeyChainKeyManager(
String clientAlias, X509Certificate[] certificateChain, PrivateKey privateKey) {
mClientAlias = clientAlias;
mCertificateChain = certificateChain;
mPrivateKey = privateKey;
}
#Override
public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
return mClientAlias;
}
#Override
public X509Certificate[] getCertificateChain(String alias) {
return mCertificateChain;
}
#Override
public PrivateKey getPrivateKey(String alias) {
return mPrivateKey;
}
#Override
public final String chooseServerAlias( String keyType, Principal[] issuers, Socket socket) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
#Override
public final String[] getClientAliases(String keyType, Principal[] issuers) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
#Override
public final String[] getServerAliases(String keyType, Principal[] issuers) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
}
}
I did not test it. Report any error!
If your URLs are still in development stage (not production version), you can skip those SSL/NON-SSL certificates installing to access the URLs.
Here is how to skip SSL validation :
Call when activity onCreate() or where your need before accessing URL.
public static void skipSSLValidation() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
/* Create a new array with room for an additional trusted certificate. */
return new X509Certificate[0];
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
// pass
}
}
Note : If your HTTPS URLs are valid, you will no require to use server-generated certificates. You should using this method for testing/development only. For release/production you don't have to use this method.
I want access a SOAP webservice url having https hosted in a remote vm. I am getting an exception while accessing it using HttpURLConnection.
Here's my code:
import javax.net.ssl.*;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* Created by prasantabiswas on 07/03/17.
*/
public class Main
{
public static void main(String [] args)
{
try
{
URL url = new URL("https://myhost:8913/myservice/service?wsdl");
HttpURLConnection http = null;
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setHostnameVerifier(DO_NOT_VERIFY);
http = https;
} else {
http = (HttpURLConnection) url.openConnection();
}
String SOAPAction="";
// http.setRequestProperty("Content-Length", String.valueOf(b.length));
http.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
http.setRequestProperty("SOAPAction", SOAPAction);
http.setRequestMethod("GET");
http.setDoOutput(true);
http.setDoInput(true);
OutputStream out = http.getOutputStream();
}
catch (Exception e)
{
e.printStackTrace();
}
}
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
private static void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
// 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) {
e.printStackTrace();
}
}
}
I'm getting the following exception:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1283)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1258)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at Main.main(Main.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:1055)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:981)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:923)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
... 18 more
Tried different solution from the google search, Non of them worked. I want to avoid using keytool because I will be running my tests on different vm.
Does anyone have any solution for this?
Using X509ExtendedTrustManager instead of X509TrustManager() solved the problem. Here's the example:
public void trustAllHosts()
{
try
{
TrustManager[] trustAllCerts = new TrustManager[]{
new X509ExtendedTrustManager()
{
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return null;
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] xcs, String string, Socket socket) throws CertificateException
{
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] xcs, String string, Socket socket) throws CertificateException
{
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException
{
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException
{
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier()
{
#Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
catch (Exception e)
{
log.error("Error occurred",e);
}
}
Edit : Understand the vulnerability this would cause before using it. This is by no means recommended for production use.
The best way is to create a dummy trustmanager that trusts everything.
TrustManager[] dummyTrustManager = 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) {
}
} };
Then use the dummy trustmanager to initialize the SSL Context
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, dummyTrustManager, new java.security.SecureRandom());
Finally use the SSLContext to open connection
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://myhost:8913/myservice/service?wsdl");
This question has already been answered here in more detail
Java: Overriding function to disable SSL certificate check
Update:
Above issue is due to certificate signature algorithm not being supported by Java. As per this post, later releases of Java 8 have disabled md5 algorithm.
To enable md5 support, locate java.security file under <jre_home>/lib/security
and locate the line (535)
jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024,
and remove MD5
Try with Apache HTTP client, this works for me.
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
// GET or POST request with the client
...
Instead of using HttpsURLConnection.setDefaultSSLSocketFactory and your own implementation of TrustManager or X509ExtendedTrustManager, you can use TrustManagerFactory with a KeyStore with the certificate that issued the certificate you need to trust (for a self-signed certificate, this is the same as the host certificate) and call HttpsURLConnection.setSSLSocketFactory on the specific instance. This is both less code and avoids the security problems with trusting all HTTPS certicates.
In main:
if (url.getProtocol().toLowerCase().equals("https")) {
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setSSLSocketFactory(createSSLSocketFactory());
http = https;
}
The method createSSLSocketFactory looks like this:
private static SSLSocketFactory createSSLSocketFactory() {
File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
Hell everyone,
I have set up the java webservices on tomcat + ssl Connection by the link below
http://www.mkyong.com/webservices/jax-ws/deploy-jax-ws-web-services-on-tomcat-ssl-connection/ . It works fine.
My question now is here in this code the client part does not authencticate certificate or ssl connection, I have part only to check the hostname,by hostname verifier,but now I have a self-signed certificate, and not sure what should I do.
how to extend this class. I find few codes from forum but i do not get an entire idea, where the keystore or truststore come from. Reference to any blog or link that guide me is much appreciated.
My Client code is below
public IExample create() throws MalformedURLException{
try{
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Trust always
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Trust always
}
} };
// Install the all-trusting trust manager
sc = SSLContext.getInstance("SSL");
// Create empty HostnameVerifier
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession arg1) {
if(hostname.equals(arg1.getPeerHost()) && hostname.equals("example.com"))
{
return true;
}else{
return false;
}
}
};
sc.init(null,trustAllCerts , new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
catch(Exception e){
e.printStackTrace();
}
try{
URL url = new URL( urlString );
//1st argument service URI, refer to wsdl document above
//2nd argument is service name, refer to wsdl document above
QName qname = new QName("http://synchronization.ws/", "ExampleImplclass");
Service service = Service.create(url, qname);
IExample iExample = service.getPort(IExample.class);
return iExample;
}catch(Exception e)
{
e.printStackTrace();
return null;
}
}