I have been looking for answer everywhere and nothing help.
Thats my code :
BufferedImage img1 = ImageIO.read(new File(dir1));
URL url = new URL(image_srcURL);
BufferedImage img2 =
ImageIO.read(url.openStream());
Now I get the exception below when I'm trying to read the url.
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 at
java.base/sun.security.ssl.Alerts.getSSLException(Alerts.java:198) at
java.base/sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1974)
at java.base/sun.security.ssl.Handshaker.fatalSE(Handshaker.java:345)
at java.base/sun.security.ssl.Handshaker.fatalSE(Handshaker.java:339)
at
java.base/sun.security.ssl.ClientHandshaker.checkServerCerts(ClientHandshaker.java:1968)
at
java.base/sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1777)
at
java.base/sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:264)
at
java.base/sun.security.ssl.Handshaker.processLoop(Handshaker.java:1098)
at
java.base/sun.security.ssl.Handshaker.processRecord(Handshaker.java:1026)
at
java.base/sun.security.ssl.SSLSocketImpl.processInputRecord(SSLSocketImpl.java:1137)
at
java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1074)
at
java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
at
java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1402)
at
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1429)
at
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at
java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
at
java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1581)
at
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1509)
at
java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:245)
at
com.folderName.Tools.DataForAutomationV1.compareImg(DFA.java:606)
at
com.folderName.VendorTests.SettingsPage.editCompDets(SettingsPage.java:562)
at
com.folderName.VendorTests.SettingsPage.runTest(SettingsPage.java:62)
at com.folderName.Vendor.vendorTests(Vendor.java:36) at
com.folderName.Main.main(Main.java:40) Caused by:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target at
java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
at
java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:290)
at
java.base/sun.security.validator.Validator.validate(Validator.java:264)
at
java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:343)
at
java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:226)
at
java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:133)
at
java.base/sun.security.ssl.ClientHandshaker.checkServerCerts(ClientHandshaker.java:1947)
... 20 more Caused by:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target at
java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at
java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at
java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
at
java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 26 more
Any help would be great.
I'm trying to read an image inside the url and compare it to an existing file.
There wasn't any questions here that gave the answer.
Edit:
I've try to enter in my command line " keytool -list -keystore keystore ", but it showed me only trustedCertEntries. No solution worked yet.
Below is an example of how I implemented it. The code reads the the response body into an awt BufferedImage, then writes to a .jpg file, then reads the file back into a byte array and then deletes the file. I'm sure I found help with this on SO but I don't have the answer handy. I will try to find that so I can cite. Hope it helps you!
**Edit as #Srikanthkumar mentions in his answer, you will also need to get the cert and add it to your truststore of your JVM. You can get that through a browser via whatever browser you have cert exploring tools.
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.util.Base64;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Override
public String getImage(String productNumber) throws EcomWebException {
try {
BufferedImage image = ImageIO.read(url);
File file = new File(guid.toString() + ".jpg");
ImageIO.write(image, "jpg", file);
String base64ImageString = Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath()));
file.delete();
return base64ImageString;
} catch (Exception e) {
throw new EcomWebException(IMAGE_NOT_FOUND_MESSAGE + productNumber, e);
}
}
First you need to obtain the certificate of the server, add it to a keystone file, either to the java truststore in jre or a separate file. If you are creating a new truststore then make sure that you supply truststore to your program
The following snippet from this post may help you:
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
#Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType
) {}
#Override
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());
} catch (GeneralSecurityException e) {
}
Related
This is my first time working with SSL, and I'm trying to create and use a self-signed certificate on my local machine (for now).
I've used the following batch file to create my certificate:
#ECHO off
rem keytool docs: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html
SET JAVA_HOME=C:\Program Files\Java\jre1.8.0_251
SET KEYTOOL="%JAVA_HOME%\bin\keytool.exe"
rem keystore name, which we'll set to the servername
SET KEYSTORE=127.0.0.1
SET EXPORT_ALIAS=localhost
SET SAN=127.0.0.1
rem CM=commonname, OU=organisation; O=province; C=country
SET DNAME="CN=localhost, OU=Kevin, O=Gelderland, C=NL"
SET CERT_PUB=localhost.crt
SET PASS=myPass
rem path the files will be output to:
cd c:\temp\localhost
c:
echo "create new keystore and self-signed certificate with corresponding public/private keys for the given alias: %EXPORT_ALIAS%"
%KEYTOOL% -genkeypair -alias %EXPORT_ALIAS% -keyalg RSA -keystore myKeystore.jks -validity 5000 -keysize 2048 -dname %DNAME% -keypass %PASS% -storepass %PASS% -ext san=dns:%SAN%
echo "reads from the newly created keystore for this alias %EXPORT_ALIAS%, and stores it as myKeystore.jks (in the certificate-file %CERT_PUB%)"
%KEYTOOL% -exportcert -rfc -alias %EXPORT_ALIAS% -keystore myKeystore.jks -file %CERT_PUB% -storepass %PASS%
echo "reads the newly created keystore myKeystore.jks (from certificate-file %CERT_PUB%), and stores it in the myTruststore.jks"
%KEYTOOL% -importcert -file %CERT_PUB% -alias %EXPORT_ALIAS% -keystore myTruststore.jks -storepass %PASS%
echo "creates a copy of the keystore myKeystore.jks to %KEYSTORE%"
%KEYTOOL% -importkeystore -srckeystore myKeystore.jks -destkeystore %KEYSTORE% -deststoretype PKCS12 -srcstorepass %PASS% -deststorepass %PASS%
After that I've used the tutorial Secure Socket Connection Between a Client and a Server from Oracle, and downloaded those sample files as zip from here. Below the three files I use from this zip, slightly modified to use my own keystore with passphrase:
SSLSocketClientWithClientAuth.java class:
package client;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
/*
* This example shows how to set up a key manager to do client
* authentication if required by server.
*
* This program assumes that the client is not inside a firewall.
* The application can be modified to connect to a server outside
* the firewall by following SSLSocketClientWithTunneling.java.
*/
public class SSLSocketClientWithClientAuth {
public static void main(final String[] args) throws Exception {
String host = null;
int port = -1;
String path = null;
for (final String arg : args) {
System.out.println(arg);
}
if (args.length < 3) {
System.out.println("USAGE: java SSLSocketClientWithClientAuth " +
"host port requestedfilepath");
System.exit(-1);
}
try {
host = args[0];
port = Integer.parseInt(args[1]);
path = args[2];
} catch (final IllegalArgumentException e) {
System.out.println("USAGE: java SSLSocketClientWithClientAuth " +
"host port requestedfilepath");
System.exit(-1);
}
try {
/*
* Set up a key manager for client authentication
* if asked by the server. Use the implementation's
* default TrustStore and secureRandom routines.
*/
SSLSocketFactory factory = null;
try {
SSLContext ctx;
KeyManagerFactory kmf;
KeyStore ks;
final char[] passphrase = "myPass".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("C:\\temp\\localhost\\myKeystore.jks"),
passphrase);
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, null);
factory = ctx.getSocketFactory();
} catch (final Exception e) {
throw new IOException(e.getMessage());
}
final SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
/*
* send http request
*
* See SSLSocketClient.java for more information about why
* there is a forced handshake here when using PrintWriters.
*/
socket.startHandshake();
final PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())));
out.println("GET " + path + " HTTP/1.0");
out.println();
out.flush();
/*
* Make sure there were no surprises
*/
if (out.checkError()) {
System.out.println("SSLSocketClient: java.io.PrintWriter error");
}
/* read response */
final BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
out.close();
socket.close();
} catch (final Exception e) {
e.printStackTrace();
}
}
}
ClassFileServer.java class:
package server;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.security.KeyStore;
import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
/* ClassFileServer.java -- a simple file server that can server
* Http get request in both clear and secure channel
*
* The ClassFileServer implements a ClassServer that
* reads files from the file system. See the
* doc for the "Main" method for how to run this
* server.
*/
public class ClassFileServer extends ClassServer {
private static int DefaultServerPort = 2001;
private static ServerSocketFactory getServerSocketFactory(final String type) {
if (type.equals("TLS")) {
SSLServerSocketFactory ssf = null;
try {
// set up key manager to do server authentication
SSLContext ctx;
KeyManagerFactory kmf;
KeyStore ks;
final char[] passphrase = "myPass".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("C:\\temp\\localhost\\myKeystore.jks"), passphrase);
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, null);
ssf = ctx.getServerSocketFactory();
return ssf;
} catch (final Exception e) {
e.printStackTrace();
}
} else {
return ServerSocketFactory.getDefault();
}
return null;
}
/**
* Main method to create the class server that reads
* files. This takes two command line arguments, the
* port on which the server accepts requests and the
* root of the path. To start up the server: <br><br>
*
* <code> java ClassFileServer <port> <path>
* </code><br><br>
*
* <code> new ClassFileServer(port, docroot);
* </code>
*/
public static void main(final String args[]) {
System.out.println("USAGE: java ClassFileServer port docroot [TLS [true]]");
System.out.println("");
System.out.println("If the third argument is TLS, it will start as\n" +
"a TLS/SSL file server, otherwise, it will be\n" +
"an ordinary file server. \n" +
"If the fourth argument is true,it will require\n" +
"client authentication as well.");
int port = DefaultServerPort;
String docroot = "";
if (args.length >= 1) {
port = Integer.parseInt(args[0]);
}
if (args.length >= 2) {
docroot = args[1];
}
String type = "PlainSocket";
if (args.length >= 3) {
type = args[2];
}
try {
final ServerSocketFactory ssf = ClassFileServer.getServerSocketFactory(type);
final ServerSocket ss = ssf.createServerSocket(port);
if ((args.length >= 4) && args[3].equals("true")) {
((SSLServerSocket) ss).setNeedClientAuth(true);
}
new ClassFileServer(ss, docroot);
} catch (final IOException e) {
System.out.println("Unable to start ClassServer: " + e.getMessage());
e.printStackTrace();
}
}
private final String docroot;
/**
* Constructs a ClassFileServer.
*
* #param path the path where the server locates files
*/
public ClassFileServer(final ServerSocket ss, final String docroot) throws IOException {
super(ss);
this.docroot = docroot;
}
/**
* Returns an array of bytes containing the bytes for
* the file represented by the argument <b>path</b>.
*
* #return the bytes for the file
* #exception FileNotFoundException if the file corresponding
* to <b>path</b> could not be loaded.
*/
#Override
public byte[] getBytes(final String path) throws IOException {
System.out.println("reading: " + path);
final File f = new File(this.docroot + File.separator + path);
final int length = (int) (f.length());
if (length == 0) {
throw new IOException("File length is zero: " + path);
} else {
final FileInputStream fin = new FileInputStream(f);
final DataInputStream in = new DataInputStream(fin);
final byte[] bytecodes = new byte[length];
in.readFully(bytecodes);
return bytecodes;
}
}
}
ClassServer.java class:
package server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/*
* ClassServer.java -- a simple file server that can serve
* Http get request in both clear and secure channel
*/
/**
* Based on ClassServer.java in tutorial/rmi
*/
public abstract class ClassServer implements Runnable {
/**
* Returns the path to the file obtained from
* parsing the HTML header.
*/
private static String getPath(final BufferedReader in) throws IOException {
String line = in.readLine();
String path = "";
// extract class from GET line
if (line.startsWith("GET /")) {
line = line.substring(5, line.length() - 1).trim();
final int index = line.indexOf(' ');
if (index != -1) {
path = line.substring(0, index);
}
}
// eat the rest of header
do {
line = in.readLine();
} while ((line.length() != 0) && (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
if (path.length() != 0) {
return path;
} else {
throw new IOException("Malformed Header");
}
}
private ServerSocket server = null;
/**
* Constructs a ClassServer based on <b>ss</b> and
* obtains a file's bytecodes using the method <b>getBytes</b>.
*
*/
protected ClassServer(final ServerSocket ss) {
this.server = ss;
this.newListener();
}
/**
* Returns an array of bytes containing the bytes for
* the file represented by the argument <b>path</b>.
*
* #return the bytes for the file
* #exception FileNotFoundException if the file corresponding
* to <b>path</b> could not be loaded.
* #exception IOException if error occurs reading the class
*/
public abstract byte[] getBytes(String path) throws IOException, FileNotFoundException;
/**
* Create a new thread to listen.
*/
private void newListener() {
(new Thread(this)).start();
}
/**
* The "listen" thread that accepts a connection to the
* server, parses the header to obtain the file name
* and sends back the bytes for the file (or error
* if the file is not found or the response was malformed).
*/
#Override
public void run() {
Socket socket;
// accept a connection
try {
socket = this.server.accept();
} catch (final IOException e) {
System.out.println("Class Server died: " + e.getMessage());
e.printStackTrace();
return;
}
// create a new thread to accept the next connection
this.newListener();
try {
final OutputStream rawOut = socket.getOutputStream();
final PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(rawOut)));
try {
// get path to class file from header
final BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
final String path = getPath(in);
// retrieve bytecodes
final byte[] bytecodes = this.getBytes(path);
// send bytecodes in response (assumes HTTP/1.0 or later)
try {
out.print("HTTP/1.0 200 OK\r\n");
out.print("Content-Length: " + bytecodes.length + "\r\n");
out.print("Content-Type: text/html\r\n\r\n");
out.flush();
rawOut.write(bytecodes);
rawOut.flush();
} catch (final IOException ie) {
ie.printStackTrace();
return;
}
} catch (final Exception e) {
e.printStackTrace();
// write out error response
out.println("HTTP/1.0 400 " + e.getMessage() + "\r\n");
out.println("Content-Type: text/html\r\n\r\n");
out.flush();
}
} catch (final IOException ex) {
// eat exception (could log error to log file, but
// write out to stdout for now).
System.out.println("error writing response: " + ex.getMessage());
ex.printStackTrace();
} finally {
try {
socket.close();
} catch (final IOException e) {}
}
}
}
I've created a jar file for both the ClassFileServer.jar and SSLSocketClientWithClientAuth.jar.
I first start the server-side with:
java -jar ClassFileServer.jar 2001 c:\ TLS true
And then the client-side with (the test.txt is a sample file I created to see if it can read this file and print its content):
java -jar SSLSocketClientWithClientAuth.jar 127.0.0.1 2001 C:\temp\localhost\test.txt
But I'm getting the following Exceptions:
Server-side output:
USAGE: java ClassFileServer port docroot [TLS [true]]
If the third argument is TLS, it will start as
a TLS/SSL file server, otherwise, it will be
an ordinary file server.
If the fourth argument is true,it will require
client authentication as well.
javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at server.ClassServer.getPath(ClassServer.java:68)
at server.ClassServer.run(ClassServer.java:156)
at java.lang.Thread.run(Unknown Source)
Client-side output:
127.0.0.1
2001
C:\temp\localhost\test.txt
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
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at client.SSLSocketClientWithClientAuth.main(SSLSocketClientWithClientAuth.java:127)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
... 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 15 more
If I google the exception, I'm mainly getting solutions (like these or these) stating I should add the certificate to my Java JVM. I could do this by adding the following lines to the batch file that created the certificate:
SET CACERT_PATH="%JAVA_HOME%\lib\security\cacerts"
SET CACERTS_PASS=changeit
...
echo "put the newly created myKeystore.jks (from certificate-file %CERT_PUB%) for this alias %EXPORT_ALIAS% also in the %CACERT_PATH% file for this server-side"
%KEYTOOL% -importcert -file %CERT_PUB% -keypass %PASS% -alias %EXPORT_ALIAS% -keystore %CACERT_PATH% -storepass %CACERTS_PASS%
And then it indeed works. However, shouldn't this also work by using my own certificate keystore somehow, instead of the Java JVM's default cacerts one? I prefer to not have to add this certificate to the Java JVM cacert on every server I want to use it, especially when I'm adding this to our production code and start rolling out this update to customers in the future.
Any idea how I could modify the code so it won't give this error anymore, but I also won't have to add my certificate to the Java JVM?
This error "PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target" happens when the certification path is not found for a certificate.
This is resolved by adding the certificate of the root Certification Authority in the trust store and including any intermediate CA's as well in the certificate itself. In your case, as you realized, it is resolved simply by adding your self-signed certificate in the cacerts.
You can configure your own cacert to be used by using the property javax.net.ssl.trustStore:
System.setProperty("javax.net.ssl.trustStore", path_to_your_jks_file);
In the following Java code, I consume two different URLs with the same hostname but different port numbers. They both serve exactly the same certificate (I downloaded and diffed them). But the one with port 6443 gives an SSLHandshakeException, while the one with port 443 succeeds. Why would Java object to the certificate for the 6443 URL?
package httpsrequesttest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
public class HttpsRequestTest {
public static void main(String[] args) {
String[] urls = new String[]{
"https://geoeventsample1.esri.com:6443",
"https://geoeventsample1.esri.com"
};
for (String url : urls) {
try {
InputStream inputStream = new URL(url).openStream();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
System.out.printf("%s\n\tSuccess\n\tFirst line: %s\n", url, in.readLine());
} catch (IOException ex) {
System.out.printf("%s\n\tFailure\n\tError message: %s\n", url, ex.getClass().getSimpleName() + ": " + ex.getMessage());
}
}
}
}
The output:
https://geoeventsample1.esri.com:6443
Failure
Error message: SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
https://geoeventsample1.esri.com
Success
First line: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
Trying to setup a simple RMI server with SSL encryption. It's for a simple chat application that has a java server app and a java client app, however, I can't even get it working with a simple RMI example at the moment!
The only way I can get it to work is if both the client & server have both the same truststore & keystore. To me though, this sounds incorrect as it means each client has the server's private key too..
I followed this guide to create the trust/keystores. I first tried generating a keystore & truststore and just running the server with the keystore & the client with the truststore. That didn't work so I then generated a pair for each and loaded as shown in the code below.
It think I might be missing something obvious somewhere just can't for the life of my figure out what I'm doing wrong. I currently have the following, but when running the server I get the errors below:
Error:
Server exception: java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
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
java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
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
at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.newCall(Unknown Source)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at Server.main(Server.java:38)
Hello.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
Server.java
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
public class Server extends UnicastRemoteObject implements Hello {
private static final long serialVersionUID = 5186776461749320975L;
protected Server(int port) throws IOException {
super(port, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
}
#Override
public String sayHello() {
return "Hello, world!";
}
public static void main(String[] args) throws RemoteException, IllegalArgumentException {
try {
setSettings();
Server server = new Server(2020);
LocateRegistry.createRegistry(2020, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
System.out.println("RMI registry running on port " + 2020);
Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());
registry.bind("Hello", server);
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
private static void setSettings() {
String pass = "password";
System.setProperty("javax.net.ssl.debug", "all");
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\serverkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\servertruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);
}
}
Client.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.rmi.ssl.SslRMIClientSocketFactory;
public class Client {
private Client() {}
public static void main(String[] args) {
try {
setSettings();
Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());
Hello hello = (Hello) registry.lookup("Hello");
String message = hello.sayHello();
System.out.println(message);
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
private static void setSettings() {
String pass = "password";
System.setProperty("javax.net.ssl.debug", "all");
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\clientkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\clienttruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);
}
}
The PKIX error means that the client didn't trust the server certificate, where the server in this case was the Registry.
To clarify, you need two private keys and two keystores to hold them in, one each. You then need to create certificates in each keystore, export them, and import them into the peer's truststore. The server's truststore must trust the client's keystore, and vice versa.
Your code looks mostly OK. The result of createRegistry() should be stored in a static variable, to prevent it being GC'd. You don't need a serialVersionUID in the server class, whatever your IDE may tell you. It doesn't get serialized, at least not by RMI.
EDIT The problem is here:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks");
which should be:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks");
and here:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks"
which should be:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks"
EDIT 2 The underlying problem is that the trust store you need when binding to the Registry is the client truststore, but the truststore you need when running the server is the server truststore.
There are at least three possible solutions, in increasing order of merit:
Set up a subclass of SslRMIClientSocketFactory with its own SSLContext with its own TrustManager loaded from the client truststore, and override createSocket(). Ouch.
Import the server's certificate into the server's truststore as well.
Use the return value of createRegistry() to do the bind() instead of calling getRegistry() in the server at all, and avoid the whole problem.
I have the following code:
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HostnameVerifier;
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 java.security.cert.X509Certificate;
public class TrackWrapper {
public static void main(String[] args) throws Exception {
/*
* fix for
* Exception in thread "main" 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
*/
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) { }
}
};
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() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/*
* end of the fix
*/
URL url = new URL("https://somedomain.com:1234");
URLConnection con = url.openConnection();
con.connect();
}
}
The first part of that is simply a copypasted quickfix to accept every certificate I've got from another StackOverflow Question (I'm sure that this isn't exactly ready for production), on the second part I try to connect to some SSL-secured site whichs client certificate is in my keystore, I receive the following error message:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1806)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:986)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at TrackWrapper.main(TrackWrapper.java:54)
As I admittedly am rather clueless about SSL I'd be grateful for some insight and a walkthrough on how to fix this problem.
After some tries I now get the following error:
Exception in thread "main" java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:830)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1555)
at com.sun.net.ssl.internal.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:103)
at com.sun.net.ssl.internal.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:689)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:985)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:904)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:238)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at TrackWrapper.main(TrackWrapper.java:54)
You should have correct SSL certificate in your keystore, of server to whom you are trying to connect. Check these examples. These are working for me.
example 1
example 2
You can export that server certificate from browser (if accessible) or there are other ways to get certificates over the internet. Your certificates should match. Once you get certificate you can make keystore from any tool. alternatively you can make keystore from this code.
Have you checked if you need a client certificate?
The error message could also be from the server side.
Also start your client with the parameter -Djavax.net.debug=all. There you should see some more hints about what failed.
This code connects to a HTTPS site and I am assuming I am not verifying the certificate. But why don't I have to install a certificate locally for the site? Shouldn't I have to install a certificate locally and load it for this program or is it downloaded behind the covers? Is the traffic between the client to the remote site still encrypted in transmission?
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
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;
public class TestSSL {
public static void main(String[] args) 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) {
}
} };
// Install the all-trusting trust manager
final 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() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
URL url = new URL("https://www.google.com");
URLConnection con = url.openConnection();
final Reader reader = new InputStreamReader(con.getInputStream());
final BufferedReader br = new BufferedReader(reader);
String line = "";
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} // End of main
} // End of the class //
The reason why you don't have to load a certificate locally is that you've explicitly chosen not to verify the certificate, with this trust manager that trusts all certificates.
The traffic will still be encrypted, but you're opening the connection to Man-In-The-Middle attacks: you're communicating secretly with someone, you're just not sure whether it's the server you expect, or a possible attacker.
If your server certificate comes from a well-known CA, part of the default bundle of CA certificates bundled with the JRE (usually cacerts file, see JSSE Reference guide), you can just use the default trust manager, you don't have to set anything here.
If you have a specific certificate (self-signed or from your own CA), you can use the default trust manager or perhaps one initialised with a specific truststore, but you'll have to import the certificate explicitly in your trust store (after independent verification), as described in this answer. You may also be interested in this answer.
But why don't I have to install a certificate locally for the site?
Well the code that you are using is explicitly designed to accept the certificate without doing any checks whatsoever. This is not good practice ... but if that is what you want to do, then (obviously) there is no need to install a certificate that your code is explicitly ignoring.
Shouldn't I have to install a certificate locally and load it for this program or is it downloaded behind the covers?
No, and no. See above.
Is the traffic between the client to the remote site still encrypted in transmission?
Yes it is. However, the problem is that since you have told it to trust the server's certificate without doing any checks, you don't know if you are talking to the real server, or to some other site that is pretending to be the real server. Whether this is a problem depends on the circumstances.
If we used the browser as an example, typically a browser doesn't ask the user to explicitly install a certificate for each ssl site visited.
The browser has a set of trusted root certificates pre-installed. Most times, when you visit an "https" site, the browser can verify that the site's certificate is (ultimately, via the certificate chain) secured by one of those trusted certs. If the browser doesn't recognize the cert at the start of the chain as being a trusted cert (or if the certificates are out of date or otherwise invalid / inappropriate), then it will display a warning.
Java works the same way. The JVM's keystore has a set of trusted certificates, and the same process is used to check the certificate is secured by a trusted certificate.
Does the java https client api support some type of mechanism to download certificate information automatically?
No. Allowing applications to download certificates from random places, and install them (as trusted) in the system keystore would be a security hole.
Use the latest X509ExtendedTrustManager instead of X509Certificate as advised here: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
package javaapplication8;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
/**
*
* #author hoshantm
*/
public class JavaApplication8 {
/**
* #param args the command line arguments
* #throws java.lang.Exception
*/
public static void main(String[] args) throws Exception {
/*
* fix for
* Exception in thread "main" 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
*/
TrustManager[] trustAllCerts = new TrustManager[]{
new X509ExtendedTrustManager() {
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkClientTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
#Override
public void checkClientTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
#Override
public void checkServerTrusted(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);
/*
* end of the fix
*/
URL url = new URL("https://10.52.182.224/cgi-bin/dynamic/config/panel.bmp");
URLConnection con = url.openConnection();
//Reader reader = new ImageStreamReader(con.getInputStream());
InputStream is = new URL(url.toString()).openStream();
// Whatever you may want to do next
}
}
Java and HTTPS url connection without downloading certificate
If you really want to avoid downloading the server's certificate, then use an anonymous protocol like Anonymous Diffie-Hellman (ADH). The server's certificate is not sent with ADH and friends.
You select an anonymous protocol with setEnabledCipherSuites. You can see the list of cipher suites available with getEnabledCipherSuites.
Related: that's why you have to call SSL_get_peer_certificate in OpenSSL. You'll get a X509_V_OK with an anonymous protocol, and that's how you check to see if a certificate was used in the exchange.
But as Bruno and Stephed C stated, its a bad idea to avoid the checks or use an anonymous protocol.
Another option is to use TLS-PSK or TLS-SRP. They don't require server certificates either. (But I don't think you can use them).
The rub is, you need to be pre-provisioned in the system because TLS-PSK is Pres-shared Secret and TLS-SRP is Secure Remote Password. The authentication is mutual rather than server only.
In this case, the mutual authentication is provided by a property that both parties know the shared secret and arrive at the same premaster secret; or one (or both) does not and channel setup fails. Each party proves knowledge of the secret is the "mutual" part.
Finally, TLS-PSK or TLS-SRP don't do dumb things, like cough up the user's password like in a web app using HTTP (or over HTTPS). That's why I said each party proves knowledge of the secret...
A simple, but not pure java solution, is to shell out to curl from java, which gives you complete control over how the request is done. If you're just doing this for something simple, this allows you to ignore certificate errors at times, by using this method. This example shows how to make a request against a secure server with a valid or invalid certificate, pass in a cookie, and get the output using curl from java.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class MyTestClass
{
public static void main(String[] args)
{
String url = "https://www.google.com";
String sessionId = "faf419e0-45a5-47b3-96d1-8c62b2a3b558";
// Curl options are:
// -k: ignore certificate errors
// -L: follow redirects
// -s: non verbose
// -H: add a http header
String[] command = { "curl", "-k", "-L", "-s", "-H", "Cookie: MYSESSIONCOOKIENAME=" + sessionId + ";", "-H", "Accept:*/*", url };
String output = executeShellCmd(command, "/tmp", true, true);
System.out.println(output);
}
public String executeShellCmd(String[] command, String workingFolder, boolean wantsOutput, boolean wantsErrors)
{
try
{
ProcessBuilder pb = new ProcessBuilder(command);
File wf = new File(workingFolder);
pb.directory(wf);
Process proc = pb.start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
StringBuffer sb = new StringBuffer();
String newLine = System.getProperty("line.separator");
String s;
// read stdout from the command
if (wantsOutput)
{
while ((s = stdInput.readLine()) != null)
{
sb.append(s);
sb.append(newLine);
}
}
// read any errors from the attempted command
if (wantsErrors)
{
while ((s = stdError.readLine()) != null)
{
sb.append(s);
sb.append(newLine);
}
}
String result = sb.toString();
return result;
}
catch (IOException e)
{
throw new RuntimeException("Problem occurred:", e);
}
}
}
If you are using any Payment Gateway to hit any url just to send a message, then i used a webview by following it :
How can load https url without use of ssl in android webview
and make a webview in your activity with visibility gone. What you need to do : just load that webview.. like this:
webViewForSms.setWebViewClient(new SSLTolerentWebViewClient());
webViewForSms.loadUrl(" https://bulksms.com/" +
"?username=test&password=test#123&messageType=text&mobile="+
mobileEditText.getText().toString()+"&senderId=ATZEHC&message=Your%20OTP%20for%20A2Z%20registration%20is%20124");
Easy.
You will get this: SSLTolerentWebViewClient from this link:
How can load https url without use of ssl in android webview