Internal File SSL Cert with Password fails - java

I'm in a Spring boot service, that will be within a microservice, attempting to connect to an external SOAP Web Service, that requires a cert that was created by that service and a password. This is being written in Windows, but will need to be run on Unix. Right now, I've hardcoded some things for Windows. This is what I have coded for my side, but I'm getting an error on httpConn.getInputStream():
"sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target".
Can someone help me understand what I'm missing?
public String getSoapData(String contentType) throws IOException, NoSuchAlgorithmException, KeyManagementException, CertificateException, KeyStoreException {
StringBuilder retVal = new StringBuilder();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// get user password and file input stream
char[] password = "MYPass".toCharArray();
java.io.FileInputStream fis = null;
//X509Certificate caCert = null;
//CertificateFactory cf = CertificateFactory.getInstance("X.509");
try {
fis = new java.io.FileInputStream("C:\\MyCerts\\dev_HubExplorer1.pfx");
ks.load(fis, password);
//caCert = (X509Certificate)cf.generateCertificate(fis);
//ks.setCertificateEntry("caCert", caCert);
} catch (Exception e) {
Common.screenPrint("Exception while importing certificate:%s%s", Common.CRLF, e.getMessage());
} finally {
if (fis != null) {
fis.close();
}
}
tmf.init(ks);
//TODO (GWL) Need to get this from a configuration file/db.
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, tmf.getTrustManagers(), new java.security.SecureRandom());
URL url = new URL(_publicRecordURL);
HttpsURLConnection httpConn = (HttpsURLConnection) url.openConnection();
httpConn.setSSLSocketFactory(sslContext.getSocketFactory());
byte[] bytes = _requestTemplate.getBytes();
// Set the appropriate HTTP parameters.
httpConn.setRequestProperty("Content-Length", String.valueOf( bytes.length ) );
httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction",_soapAction);
httpConn.setRequestProperty("Accept","text/xml");
httpConn.setRequestMethod( "POST" );
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
//Everything's set up; send the XML that was read in to b.
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write(_requestTemplate);
writer.flush();
//Read the response and write it to standard out.
InputStreamReader isr = new InputStreamReader(httpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);
String inputLine;
while ((inputLine = in.readLine()) != null) {
retVal.append(inputLine + Common.CRLF);
System.out.println(inputLine);
}
in.close();
return retVal.toString();
}

you can follow this stackoverflow answer to get the solution of this problem :
https://stackoverflow.com/a/12146838/7801800

Related

Exception while include .p12 file in java

I have .p12 certificate file which needs to be included in every sent to server from my java code.
When i run sample code from linux its gives me exception
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: timestamp check failed
My java code is below :
HttpsURLConnection con = null;
try
{
System.out.println("Calling webservice ..... ");
char[] passw = "mypassword".toCharArray();
KeyStore ks = KeyStore.getInstance("PKCS12");
InputStream keyInput = new FileInputStream( "/usr/local/KEYSTORE.p12");
ks.load(keyInput, passw );
keyInput.close();
System.out.println("Reading certificate file Completed");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, passw);
System.out.println("Set SSL certificate");
SSLContext sclx = SSLContext.getInstance("SSL");
sclx.init( kmf.getKeyManagers(), null, new SecureRandom());
SSLContext.setDefault(sclx);
HttpsURLConnection.setDefaultSSLSocketFactory(sclx.getSocketFactory());
URL url = new URL("https://myurl.server.com");
con = (HttpsURLConnection)url.openConnection();
System.out.println("Connection successfull");
//con.setSSLSocketFactory(sclx.getSocketFactory());
System.out.println("Token Id 026F800E-562D-4B0F-BC56-AC16895072F4");
if(con!=null)
{
System.out.println("Inside connection");
con.setRequestProperty("Content-Type","application/json;charset=utf-8");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setRequestProperty("Token-Id","026F800E-562D-4B0F-BC56-AC16895072F4");
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
con.setDefaultUseCaches(false);
con.setRequestMethod("POST");
con.connect();
OutputStreamWriter os = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
os.write("request String");
os.flush();
os.close();
InputStreamReader dis = new InputStreamReader(con.getInputStream(),"UTF-8");
if (null != dis)
{
System.out.println("Reading response from webservice 1");
BufferedReader reader = new BufferedReader(dis);
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
}
catch(IOException ioex)
{
System.err.println("Exception : "+ioex);
e.printStackTrace();
}
catch(Exception ex){
ex.printStackTrace();
}
finally{
if(con != null) {
con.disconnect();
}
}
Its work on windows server but gives exception on linux server.
Please any one help me to resolved this.

Android/Eclipse Open a file Outside the MainActivity in a Plugin

I have a problem with my Android Phonegap App.
I created a plugin to send Data from HTML/JAVASCRIPT to Java and Java will send this DATA to a
Server with HTTPS post.
To get this Worke I need to Open a ssl.crt (certification) from my Asset folder.
In the Cordova Class this function dose work because it extends the CordovaActivity.
My Plugin Class : public class ConnectPlugin extends CordovaPlugin
Here is the Login method:
protected String tryLogin_2(String d1) throws CertificateException, FileNotFoundException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException
{
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(this.getAssets().open("ssl.crt"));
java.security.cert.Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String httpsURL = "https://URL.com";
OutputStreamWriter request = null;
DataInputStream response_2 = null;
String parameters = "1="+d1;
String response = null;
try
{
URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
con.setSSLSocketFactory(context.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-length", String.valueOf(query.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setDoOutput(true);
con.setDoInput(true);
request = new OutputStreamWriter(con.getOutputStream());
request.write(parameters);
request.flush();
request.close();
String line = "";
InputStreamReader isr = new InputStreamReader(con.getInputStream());
BufferedReader reader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
//Response from server after login process will be stored in response variable.
response = sb.toString();
isr.close();
reader.close();
}
catch(IOException e)
{
response = "Error"; // Error
}
return response;
}
The problem now is "The method getAssets() is undefined for the type ConnectPlugin".
I can't use the getAssets() method outside the Main Class.
In my MainClass the obove code work 100% fine and sends a request to my server.
But not in my Plugin Class.
Use
cordova.getActivity().getAssets().open("ssl.crt"));

Android HttpsUrlConnection with POST data not work on Gingerbread

I've written code to download some data from external server. The server is using self-signed certificate, need to have session cookie set and some POST data. Currently I have the following code:
private byte[] getResponse(URL url, String postData)
throws IOException, KeyManagementException, CertificateException, KeyStoreException,
NoSuchAlgorithmException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setRequestProperty("User-Agent", userAgent);
urlConnection.setRequestProperty("Cookie", cookie);
urlConnection.setRequestMethod("POST");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setSSLSocketFactory(getSocketFactory());
OutputStream os = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(postData);
writer.flush();
writer.close();
os.close();
try {
urlConnection.connect();
InputStream is = urlConnection.getInputStream();
int len = 0;
while ((len = is.read(buffer)) != -1)
{
baos.write(buffer, 0, len);
}
}
catch(IOException e)
{
throw e;
}
finally {
urlConnection.disconnect();
}
return baos.toByteArray();
}
On Ice Cream Sandwich and higher (API >= 14) everything works fine. The problem started when I tried to make the app work on API >= 8. It is now properly sending the request with GET and no params (CAPTCHA) but when it comes to getting the actual data urlConnection's connect method fails with no exception. The code for getSocketFactory() is:
private SSLSocketFactory getSocketFactory()
throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException,
KeyManagementException
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = context.getResources().openRawResource(R.raw.historiapojazdu);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
EDIT: I've just realized that connect method apparently worked but it didn't follow redirect on the response so input stream was always empty.
I've just figured it myself. It looks like HttpsUrlConnection simply does not follow redirects on API 10 and lower for some reason even despite implicitly calling setInstanceFollowRedirects(true). It is just ignoring that setting. I've worked that around with this code just after calling urlConnection.connect():
String redirect = urlConnection.getHeaderField("Location");
if(redirect != null) //truth before ICS
{
urlConnection.disconnect();
urlConnection = (HttpsURLConnection) (new URL(redirect)).openConnection();
urlConnection.setRequestProperty("User-Agent", userAgent);
urlConnection.setRequestProperty("Cookie", cookie);
urlConnection.setRequestMethod("POST");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setSSLSocketFactory(getSocketFactory());
OutputStream os2 = urlConnection.getOutputStream();
BufferedWriter writer2 = new BufferedWriter(
new OutputStreamWriter(os2, "UTF-8"));
writer2.write(postData);
writer2.flush();
writer2.close();
os2.close();
urlConnection.connect();
}

Making Apache HttpClient 4.3 work with sslSocketFactory/HostnameVerifier

I'm working on a Java program that will send POST requests to a website for my company to use. We do not own this website, they are separate from us. I've been fighting with various ways to actually pass it the very picky parameters it wants in order for me to do work on it from a program (as opposed to doing it manually).
I've found that the Apache HttpClient 4.3 seems to be my best route for actually trying to access it, anything results in a angry response from the website telling me my username and password and not valid/authorized.
But then I got an error because the site certificate doesn't match, I contacted their support and they reportedly share an infrastructure with another site so the certificate mismatch is expected.
So I went commandline and generated a keystore, passed that to the program and then got the error "java.security.cert.CertificateException: No subject alternative DNS name matching".
Some hunting lead me to utilize a verifier, which removed errors.
Then I realized that I can't make URLConnection/HttpsURLConnection and HttpClient/HttpPost work together. That's where I'm stuck. I'm not sure how to make the code that handles my keystore, TrustManager, SSLSocketFactory, etc connect to the part where I actually have to connect and POST.
Code that handles the certificates and verification:
InputStream in = new FileInputStream(new File("C:\\Program Files (x86)\\Java\\jre7\\bin\\my.keystore"));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, "blahblah".toCharArray());
in.close(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] {defaultTrustManager}, null);
javax.net.ssl.SSLSocketFactory sslSocketFactory = context.getSocketFactory();
URL url = new URL("https://emailer.driveclick.com/dbadmin/xml_post.pl");
URLConnection con = url.openConnection();
((HttpsURLConnection) con).setSSLSocketFactory(sslSocketFactory);
((HttpsURLConnection) con).setHostnameVerifier(new Verifier());
con.connect();
in = con.getInputStream();
Code that should be connecting me to the website:
try {
//log into the website
String url2 = "https://emailer.driveclick.com/dbadmin/xml_post.pl";
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url2);
post.setHeader("User-Agent", USER_AGENT);
List<BasicNameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("username", "namefoo"));
urlParameters.add(new BasicNameValuePair("api_password", "passfoo"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
org.apache.http.HttpResponse response = client.execute(post);
System.out.println("\nSending 'POST' request to URL : " + url2);
System.out.println("Post parameters : " + post.getEntity());
System.out.println("Response Code : " + response.getStatusLine().getStatusCode());
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null)
{
result.append(line);
}
System.out.println(result.toString());
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(LastFileMove.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(LastFileMove.class.getName()).log(Level.SEVERE, null, ex);
}
EDIT: I forgot to include the little class I made for the Verifier that I referenced.
public class Verifier implements HostnameVerifier
{
public boolean verify(String arg0, SSLSession arg1) {
return true; // mark everything as verified
}
}
Update 5/8/2014
SSLConext and Verifier are now set up like this:
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.loadTrustMaterial(ks)
.build();
X509HostnameVerifier verifier = new AbstractVerifier()
{
#Override
public void verify(final String host, final String[]
cns, final String[] subjectAlts) throws SSLException
{
verify(host, cns, subjectAlts, true);
}
};
And I've gone ahead and changed my HttpClient to a closeable one here:
CloseableHttpClient client = HttpClients.custom()
sslSocketFactory)
.setHostnameVerifier(verifier)
.setSslcontext(sslContext)
.build();
And I'm back to having "javax.net.ssl.SSLException: hostname in certificate didn't match" errors. Suggestions?
I have no idea how Verifier is implemented but this code snippet demonstrates how one can create a custom hostname verifier none of those shipped with HttpClient fits their needs
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = new FileInputStream(new File("C:\\Program Files (x86)\\Java\\jre7\\bin\\my.keystore"));
try {
ks.load(in, "blahblah".toCharArray());
} finally {
in.close();
}
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.loadTrustMaterial(ks)
.build();
X509HostnameVerifier verifier = new AbstractVerifier() {
#Override
public void verify(final String host, final String[] cns, final String[] subjectAlts) throws SSLException {
verify(host, cns, subjectAlts, true);
}
};
CloseableHttpClient hc = HttpClients.custom()
.setSslcontext(sslContext)
.setHostnameVerifier(verifier)
.build();

Java - Download zip from a SSL HTTP url (with keystore/trustore)

I'm trying to download a zip file from an url but the url returns a 404 page with the app.
When I try with firefox, it just asked the keystore so I put it and it works : I can download the ZIP file.
I don't really understand what I'm doing wrong.
Here is my code
URL url = new URL(reportInfo.getURI().toString());
HttpsURLConnection con = (HttpsURLConnection) url
.openConnection();
/*
* Keystore manager
*/
KeyManagerFactory keyManagerFactory = KeyManagerFactory
.getInstance("SunX509");
String pKeyPassword = GSBConstants.KEYSTORE_PASSWORD;
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream(new File(
cc.getWorkingDir() + File.separator
+ GSBConstants.KEYSTOREJKS_NAME));
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();
keyManagerFactory
.init(keyStore, pKeyPassword.toCharArray());
/*
* Trustore manager
*/
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance("SunX509");
KeyStore trustStore = KeyStore.getInstance("JKS");
InputStream trustInput = new FileInputStream(new File(
cc.getWorkingDir() + File.separator
+ GSBConstants.TRUSTORE_NAME));
String pTrustPassword = GSBConstants.TRUSTORE_PASSWORD;
trustStore.load(trustInput, pTrustPassword.toCharArray());
trustInput.close();
trustManagerFactory.init(trustStore);
SSLContext context = SSLContext.getInstance("SSL");
context.init(keyManagerFactory.getKeyManagers(),
trustManagerFactory.getTrustManagers(),
new SecureRandom());
SSLContext.setDefault(context);
SSLSocketFactory sockFact = context.getSocketFactory();
con.setSSLSocketFactory(sockFact);
// Check for errors
int responseCode = con.getResponseCode();
InputStream inputStream;
if (responseCode == HttpURLConnection.HTTP_OK) {
inputStream = con.getInputStream();
} else {
inputStream = con.getErrorStream();
}
OutputStream output = new FileOutputStream("test.zip");
// Process the response
BufferedReader reader;
String line = null;
reader = new BufferedReader(new InputStreamReader(
inputStream));
while ((line = reader.readLine()) != null) {
output.write(line.getBytes());
}
output.close();
inputStream.close();
Any ideas ?
I don't have any exceptions.

Categories

Resources