1

Total newbie to SSL. I know I should use HTTPS SSL (/ TLS?) to send my data to my server from my client application. Or at least that's what I want to do.

My previous implementation in Java used HttpURLConnection and looked something like this:

    HttpURLConnection conn = null;

    try
    {
        URL url = new URL(urlString);
        conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        OutputStream os = conn.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
        osw.write(dataString);
        osw.flush();
        osw.close();
        os.close();
        conn.connect();

        if(conn.getResponseCode() != 200)
            throw new MyServerException();

        BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
        String output;
        StringBuilder sb = new StringBuilder();

        while ((output = br.readLine()) != null) {
            sb.append(output);
        }

        if(conn != null)
            conn.disconnect();

        return sb.toString();
    }
    catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    catch (ProtocolException e) {
        e.printStackTrace();
    }
    catch (MalformedURLException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        if(conn != null)
            conn.disconnect();
    }

    throw new MyServerException();

... and this works just fine. I found this web page which kind of suggests all I need to do is switch my HttpURLConnection to HttpsURLConnection and everything should work fine.

On the other hand, on my server's cPanel I found a Lets Encrypt section which enabled me to apply certificates to my server domains.

Setting this up produced, amongst other things, PEM-Encoded Certificate and PEM-Encoded Issuer certificates.

But then I'm a bit stumped. Do I just assume my code above updated to use HttpsURLConnection works? How do I know it's working. For example, if I remove the issued certificates from my cPanel, then the above code still works...

Things I've found out since posting

If I make my urlString a http it throws and exception, whereas if it's an https address it does not, so that's good I guess.

Also, this this post would suggest I am on the right track, as I'm not getting any errors as suggested there, and nobody has mentioned that way is the wrong way to do it.

Of possible interest, which actually points out that "SSL is now called Transport Layer Security (TLS)," which simplifies things already.

This looks like a great article. I also notice this mentions we have to set up SSL/TLS on the cPanel too, in addition to the Lets Encrypt option. Makes sense really, didn't see that originally. More: Turns out Lets Encrypt is a free service which provides you with an automatic certificate to use, rather than buying one from a service provider. However, you can also sign your own certificates which are free, but then not "recognised" by any trusted Certificate Authority (CA).

2 Answers2

0

I've usually used method like make https url connection trust any certificate as follows.

try {
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, new X509TrustManager[]{new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
    }}, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch(NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch(KeyManagementException e) {
    e.printStackTrace();
}

And make a secure request to a server with certificates that do not have host name.

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
});

Then, you can get a HttpURLConnection object as a HttpsURLConnection object.

HttpURLConnection connection = null;
try
{
    URL _url = new URL(url);
    String scheme = _url.getProtocol();

    if(scheme.equals("https")) {
       connection = (HttpsURLConnection)new URL(url).openConnection();
    }
 }catch(...){} 
tommybee
  • 2,409
  • 1
  • 20
  • 23
  • thanks for the answer. Does this creates a secure TLS connection between client and the server? I think I get where you're coming from. E.g. the only reason I would need a certificate that I actually paid for would be if I had a web-based client where I would want the browser to recognise my web page server as secure (with the green pad lock appearing). But as it is I'm dealing with mobile and desktop apps, which don't have this caveat of modern browsers... –  Apr 24 '18 at 19:55
  • ... so I could sign my own certificate without having to use Lets Encrypt or buy a certificate from a CA ... ? So long as I've got a secure connection, that's all that matters. –  Apr 24 '18 at 19:57
  • Basically, it would be no problem, if you have your own http client. I have been using the code i presented in my android app but we have a sever with public cert. I also have push client with my own generated cert by openssl, it is still working. – tommybee Apr 24 '18 at 23:51
0

Ok I finally worked this out after a full day altogether. Firslty SSL and TLS generally mean the same think, with TLS the replacement for the older SSL. Next up, to get a secure connection you need to install a certificate on your server. This is actually very easy via the cPanel. In fact I recommend using Lets Encrypt, which offers free certificates which last 90 days. You can automatically renew your certificates server side by setting up a crontab job, so not only are they free but they are also perpetual.

Once your certificate is set up, you can establish a secure connection and POST using the following code:

    SSLContext sc = null;
    HttpsURLConnection conn = null;

    try {
        URL httpsURL = new URL(urlString);
        sc = SSLContext.getInstance("TLSv1.2");
        sc.init(null, null, new java.security.SecureRandom());
        conn  = (HttpsURLConnection) httpsURL.openConnection();
        conn.setSSLSocketFactory(sc.getSocketFactory());

        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        OutputStream os = conn.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
        osw.write(dataString);
        osw.flush();
        osw.close();
        os.close();
        conn.connect();

        if(conn.getResponseCode() != 200)
            throw new MyServerException();

        BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
        String output;
        StringBuilder sb = new StringBuilder();

        while ((output = br.readLine()) != null) {
            sb.append(output);
        }

        if(conn != null)
            conn.disconnect();

        return sb.toString();
    }
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    catch (KeyManagementException e) {
        e.printStackTrace();
    }
    catch (MalformedURLException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }

    if(conn != null)
        conn.disconnect();

    throw new MyServerException();

Nice and easy really. Perhaps I also need some kind of host name verifier like @tommybee mentioned in his answer.