I want to get a connection via HTTPS to a Server. The Server uses a unsigned certificate.
I found a solution to download those certificates from sun.
That is my Code:
{
final char[] CertPassphrase = "changeit".toCharArray();
private boolean installCert() throws
KeyStoreException, NoSuchAlgorithmException,
CertificateException, KeyManagementException,
IOException {
boolean isCertInstalled = true;
File file = new File("jcacerts");
if (!file.isFile())
{
char SEP = File.separatorChar;
File dir = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security");
file = new File(dir, "jssecacerts");
if (!file.isFile())
{
file = new File(dir, "cacerts");
}
}
InputStream in = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, CertPassphrase);
in.close();
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
context.init(null, new TrustManager[]
{
tm
}, null);
SSLSocketFactory factory = context.getSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(this.getStrUrl(), this.getPort() );
socket.setSoTimeout(10000);
try
{
socket.startHandshake();
socket.close();
} catch (SSLException e)
{
isCertInstalled = false;
}
if(!isCertInstalled){
X509Certificate[] chain = tm.chain;
if (chain == null)
{
return true;
}
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
System.out.println("Certificat from "+this.getStrUrl()+". [Enter] to download, [q] to quit!");
String line = reader.readLine().trim();
if(line.length()==0){
for(int i=0; i<chain.length; i++){
X509Certificate cert = chain[i];
String alias = this.getStrUrl() + "-" + (i + 1);
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts");
ks.store(out, this.CertPassphrase);
out.close();
System.out.println("Added certificate to keystore 'jcacerts'");
}
return true;
}else{
return false;
}
}else
return true;
}
private HttpsURLConnection openHttpsConnection(){
try{
if(this.installCert()){
return (HttpsURLConnection)this.getUrl().openConnection();
}
else{
System.out.println("Zertifikat heruntergeladen");
return null;
}
}catch (KeyStoreException e){
System.out.println(e.getMessage());
}catch (NoSuchAlgorithmException e){
System.out.println(e.getMessage());
}catch (CertificateException e){
System.out.println(e.getMessage());
}catch (KeyManagementException e){
System.out.println(e.getMessage());
}catch (IOException e){
System.out.println(e.getMessage());
}
return null;
}
private void closeHttpsConnection(HttpsURLConnection con){
con.disconnect();
}
public void print_content(){
HttpsURLConnection con = this.openHttpsConnection();
try{
BufferedReader br = new BufferedReader( new InputStreamReader(con.getInputStream()));
String input;
while ((input = br.readLine()) != null){
System.out.println(input);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public Https(String Url) { this.setUrl(Url); }
private static class SavingTrustManager implements X509TrustManager
{
private final X509TrustManager tm;
private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm)
{
this.tm = tm;
}
public X509Certificate[] getAcceptedIssuers()
{
throw new UnsupportedOperationException();
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
throw new UnsupportedOperationException();
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
this.chain = chain;
tm.checkServerTrusted(chain, authType);
}
}
In my opinion, the certificate is downloaded completely. But if I try to read from the Input-Stream, following Exceptions are thrown:
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertificateException: No name matching url found
Does someone know the correct solution for my problem or can otherwise help me?
Related
I'm encountering a problem while downloading a gzip file and saving it in the file system with Java 5. When the download is finished, the file (which has the correct name and extension) appears to have a different MIME type... I'm unable to unzip it from my Linux server (using gunzip) and if I try to open it with WinZip on my Windows pc I see a "recursive" archive (like a matryoshka doll). If I type the command file *filename*.gz from the server, it recognizes the file as an ascii text.
Instead, if I try to download the archive using the browser, everything goes well and I can correctly open and unzip the file (even with my Linux server) and now it's recognized as a gzip compressed archive.
Here's the code I'm using to download the file and save it.
Main.java:
public class Main {
public static void main(String[] args) {
String filePath = "";
HttpOutgoingCall httpOngoingCall = null;
httpOngoingCall = new HttpOutgoingCall();
String endpointUrl = "https://myurl/myfile.gz";
try {
InputStream inputStream = httpOngoingCall.callHttps(endpointUrl);
//I also tried with ZipInputStream and GZIPInputStream
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
filePath = parseAndWriteResponse(br, "myfile.gz", "C:\\");
System.out.println(filePath);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
private static String parseAndWriteResponse(BufferedReader br, String fileName,
String destPath) {
String outputFileName = null;
outputFileName = destPath + File.separator + fileName;
String line;
File outputFile = new File(outputFileName);
FileWriter fileWriter = null;
BufferedWriter bw = null;
try {
if (!outputFile.exists()) {
outputFile.createNewFile();
}
} catch (IOException e1) {
}
try {
fileWriter = new FileWriter(outputFile);
bw = new BufferedWriter(fileWriter);
while ((line = br.readLine()) != null) {
bw.write(line);
bw.write("\n");
}
} catch (IOException e) {
} finally {
try {
bw.close();
fileWriter.close();
} catch (IOException e) {
}
}
return outputFileName;
}
HttpOutgoingCall.java:
public class HttpOutgoingCall {
private InputStream inStream = null;
private HttpsURLConnection httpsConnection = null;
private final static int CONNECTION_TIMEOUT = 20000;
public InputStream callHttps(String endpointUrl) throws Exception {
String socksServer = "";
String socksPort = "";
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
Properties properties = System.getProperties();
System.setProperty("java.protocol.handler.pkgs", "javax.net.ssl");
java.security.Security
.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
if (!socksServer.equals("")) {
if (System.getProperty("socksProxyHost") == null) {
properties.put("socksProxyHost", socksServer);
}
if (!socksPort.equals("")) {
if (System.getProperty("socksProxyPort") == null) {
properties.put("socksProxyPort", socksPort);
}
}
}
System.setProperties(properties);
System.setProperty("java.protocol.handler.pkgs", "javax.net.ssl");
java.security.Security
.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
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) {
}
} };
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
httpsConnection = (HttpsURLConnection) (new URL(endpointUrl)).openConnection();
httpsConnection.setDoOutput(true);
httpsConnection.setUseCaches(false);
httpsConnection.setConnectTimeout(CONNECTION_TIMEOUT);
httpsConnection.setReadTimeout(CONNECTION_TIMEOUT);
inStream = httpsConnection.getInputStream();
} catch (Exception e) {}
return inStream;
}
Could someone help me? Thanks!
When writing your file, you should send it through a java.util.zip.GZIPOutputStream.
When trying to access web service from secured testing environment with SSL certificate getting the issue below.
com.android.volley.NoConnectionError: javax.net.ssl.SSLProtocolException: Read error: ssl=0xa35dad40: Failure in SSL library, usually a protocol error
error:100000d7:SSL routines:OPENSSL_internal:SSL_HANDSHAKE_FAILURE (external/boringssl/src/ssl/s3_pkt.c:402 0xa3630912:0x00000000)
I have tried with volley and basic java code, still getting the same issue. When I used the same code for secured development environment with different certificate its working fine. Whereas its not working in testing environment for specific bandwidths (Airtel 3G, 4G). It is working fine with all the environments(Testing & Dev) for 2G bandwidths.
Don't know where the problem occurs. Help me in sorting out this issue.
I have added the code snippet below,
Responsecallback responsecallback;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
testing(mBase_Url);
}
public void testing(String urls) {
String result = "";
try {
URL url = new URL(urls);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(getSSLCertificate()); // Tell the URLConnection to use a SocketFactory from our SSLContext
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setConnectTimeout(30000);
connection.setReadTimeout(30000);
connection.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
Uri.Builder builder = new Uri.Builder()
.appendQueryParameter("country", "IN");
String query = builder.build().getEncodedQuery();
PrintWriter out = new PrintWriter(connection.getOutputStream());
out.println(query);
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); //,8192
String inputLine;
while ((inputLine = in.readLine()) != null) {
result = result.concat(inputLine);
}
responsecallback.displayResponse(result);
in.close();
} catch (IOException e) {
result = e.toString();
Log.e(TAG, "HTTP Error Result=" + result);
responsecallback.displayResponse(result);
}
}
private SSLSocketFactory getSSLCertificate() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("PKCS12");
// your trusted certificates (root and any intermediate certs)
InputStream in = getResources().openRawResource(R.raw.xxxxxx); //SSL Certificate - P12 formate
String password = "XXXXXXX"; // Certificate password
char[] pwd = password.toCharArray();
try {
trusted.load(in, pwd);
} finally {
in.close();
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(trusted, pwd);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(trusted);
SSLContext context = SSLContext.getInstance("SSL");
context.init(kmf.getKeyManagers(), getWrappedTrustManagers(), new SecureRandom());
return context.getSocketFactory();
} catch (Exception e) {
Log.e(TAG, "Exception e=" + e.toString());
throw new AssertionError(e);
}
}
private TrustManager[] getWrappedTrustManagers() {
return new TrustManager[]{
new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return null;
}
}
};
}
I have written below code to connect to server using client side certificate authentication.
public void login()
{
try {
KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
ks.load(null, null);
String kalg = KeyManagerFactory.getDefaultAlgorithm();
System.out.println(kalg);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(kalg);
kmf.init(ks, null);
String talg = TrustManagerFactory.getDefaultAlgorithm();
System.out.println(talg);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(talg);
KeyStore ts;
ts = KeyStore.getInstance("Windows-ROOT", "SunMSCAPI");
ts.load(null, null);
tmf.init(ts);
TrustManager tm[] = tmf.getTrustManagers();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(kmf.getKeyManagers(), tm, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://xxxxxx/");
HttpsURLConnection httpsCon = (HttpsURLConnection) url
.openConnection();
InputStream is = httpsCon.getInputStream();
httpsCon.getHeaderFields();
String str =httpsCon.getHeaderField("Set-Cookie");
System.out.println(httpsCon.getResponseMessage());
int c;
StringBuffer sb = new StringBuffer();
while ((c = is.read()) >= 0) {
System.out.print((char)c);
sb.append((char) c);
}
is.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
for testing purposed I have created self signed server and client certificates.
This code works only in java 7, in java 8 it throws exception:
java.security.InvalidKeyException: No installed provider supports
this key: sun.security.mscapi.RSAPrivateKey
Is it something to do with some features introduced in java 8?
public static void login()
{
try {
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
String kalg = KeyManagerFactory.getDefaultAlgorithm();
System.out.println(kalg);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(kalg);
kmf.init(ks, null);
String talg = TrustManagerFactory.getDefaultAlgorithm();
System.out.println(talg);
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
#Override
public void checkClientTrusted(final X509Certificate[] chain,
final String authType) {
}
#Override
public void checkServerTrusted(final X509Certificate[] chain,
final String authType) {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
} };
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(kmf.getKeyManagers(), trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("xxxxx");
HttpsURLConnection httpsCon = (HttpsURLConnection) url
.openConnection();
InputStream is = httpsCon.getInputStream();
httpsCon.getHeaderFields();
String str =httpsCon.getHeaderField("Set-Cookie");
System.out.println(httpsCon.getResponseMessage());
int c;
StringBuffer sb = new StringBuffer();
while ((c = is.read()) >= 0) {
System.out.print((char)c);
sb.append((char) c);
}
is.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
This is basically how I am reading the content from an URL and get the content in the variable result. The result is a json parsed after.
I was wondering if it was a way to increase the performance of this request as it takes up to 4~5 seconds while I would like it to take, if possible, less than 2.
Thing is trustAllHosts() and BufferedReader br = new BufferedReader(new InputStreamReader(in)); seems to take some time, but I'm not sure about that. Any idea will be appreciated!
try {
URL url;
// get URL content
url = new URL(apiURL);
trustAllHosts();
conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(DO_NOT_VERIFY);
conn.setRequestMethod("GET");
conn.setRequestProperty("some values here");
conn.setConnectTimeout(10000);
in=conn.getInputStream();
// open the stream and put it into BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(in));
while ((line=br.readLine())!= null) {
builder.append(line);
}
result=builder.toString();
//System.out.print(result);
br.close();
} catch (MalformedURLException e) {
result=null;
} catch (java.net.SocketTimeoutException e) {
result=null;
} catch (IOException e) {
result=null;
}
catch (Exception e) {
result=null;
}
finally {
try {
in.close();
}catch(Exception e){}
try {
conn.disconnect();
}catch(Exception e){}
return result;
}
trustAllHosts() :
/**
* Trust every server - dont check for any certificate
*/
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("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
I am trying to read the content of the URL with the code down below, but get an 403 error:
https://api.kraken.com/0/public/Time
The URL is reachable in the Problem or via Rest-Connection-Test-Pages like https://apigee.com without a problem. The code works for other HTTPS-Urls just fine. I have no clue what could be wrong here:
public class HttpsClient{
public static void main(String[] args)
{
new HttpsClient().testIt();
}
private void testIt(){
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
;
}
String https_url = "https://api.kraken.com/0/public/Time";
URL url;
HttpsURLConnection con = null;
try {
url = new URL(https_url);
con = (HttpsURLConnection)url.openConnection();
//dumpl all cert info
print_https_cert(con);
try{
System.out.println("****** Content of the URL ********");
BufferedReader br =
new BufferedReader(
new InputStreamReader(con.getInputStream()));
String input;
while ((input = br.readLine()) != null){
System.out.println(input);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
#Override
public X509Certificate[] getAcceptedIssuers(){return null;}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType){}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};
}