Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a SSL Checker using Java

Tags:

java

ssl

x509

Does anyone know of any good tutorials, sites, and or books on writing a SSL checker in Java? I'm trying to do what can be found here: http://www.sslshopper.com/ssl-checker.html . I'm not trying to create a self signed cert or use a a keystore. I want to be able to go out to any site determine if a valid SSL Certificate exists, determine if the hostname on the Cert matches the named entered, and determine when this Cert will expire. I have googled this topic but "How to create a SSL shopper using Java" hasn't yielded me anything and my other searches only brought me links on how to create a self-signed Cert. Any help would be greatly appreciated.

like image 737
W3B5T4R Avatar asked Dec 17 '11 15:12

W3B5T4R


People also ask

How set SSL certificate in Java?

The steps to install a new certificate into the Java default truststore are: extract cert from server: openssl s_client -connect server:443. import certificate into truststore using keytool: keytool -import -alias alias.server.com -keystore $JAVA_HOME/jre/lib/security/cacerts.

How do I make my site HTTPS in Java?

Therefore, if you want to create an HTTPS connection from within your applet code, simply specify HTTPS as your protocol when creating an instance of the URL class: URL url = new URL("https://[your server]");

How does SSL work in Java?

A Java SSL certificate works on the technology regarded as “public key infrastructure” (PKI). PKI involves a trusted and recognized certificate authority (CA) that issues the certificate. However, the certificate is only issued when it has verified the identity of the party requesting it.


2 Answers

To get the server certificate in the first place in order to do the verification manually, irrespectively of whether it's valid or not, the easiest is to connect via an SSLSocket after having disabled any certificate verification.

Create an SSLContext that lets anything through:

SSLContext sslContext = SSLContext.getInstance("TLS");
X509TrustManager passthroughTrustManager = new X509TrustManager() {
    @Override
    public void checkClientTrusted(X509Certificate[] chain,
            String authType) throws CertificateException {
    }

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

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
};
sslContext.init(null, new TrustManager[] { passthroughTrustManager },
        null);

(Side note: for people looking for a way to use test certificates internally, I'd recommend building your own test CA rather than disabling checks, just in case those dummy checks are left over in production code by mistake, and also because it makes the tests more realistic.)

Create a socket, connect and start the handshake explicitly (since you're not really going to read form it):

SSLSocketFactory ssf = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) ssf.createSocket(
        "the.host.name", 443);
socket.startHandshake();

Get the peer certificates chain. The first item is the actual server certificate.

X509Certificate[] peerCertificates = (X509Certificate[]) socket
        .getSession().getPeerCertificates();

If you want to validate against the default trust anchors (the default trusted CA certificates), build a X509TrustManager based on the default values (this is effectively what the passthroughTrustManager above disabled):

// By default on Oracle JRE, algorithm is PKIX
TrustManagerFactory tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
// 'null' will initialise the tmf with the default CA certs installed
// with the JRE.
tmf.init((KeyStore) null);
X509TrustManager tm = (X509TrustManager) tmf.getTrustManagers()[0];

Now, check whether the certificate is currently valid in time, whether it's verified against a trusted anchor and whether it has the right extensions according to RFC 3280.

try {
    // Assuming RSA key here.
    tm.checkServerTrusted(peerCertificates, "RSA");
} catch (CertificateException e) {
    // Here you may check which subclass of CertificateException to know what the error is.
}

All the above makes use of the JSSE API.

Alternatively, if you want to dig deeper into the details of PKIX, you can use the Java Certification Path API (which is used by JSSE).

(If you only want valid certificates anyway to start with, just use SSLContext sslContext = SSLContext.getDefault() at the start, create the socket and do the handshake.)

To get the server certificate directly, you can use this:

X509Certificate serverCert = peerCertificates[0];

X509Certificate has a number of methods regarding dates and various extensions. For example:

Date expirationDate = serverCert.getNotAfter();

The hostname verification should follow RFC 6125 (or at least RFC 2818). In short, check whether the hostname you intended to connect to is one of the Subject Alternative Names (SAN) DNS entry. Failing that, fall back on checking whether the hostname is in the CN RDN of your certificate (for this, you need to split the Subject DN into RDNs). You may also be interested in this discussion (on the specific case of using IP addresses).

It all depends on how much "manual" verification you want to make. There are a number of specifications to read (RFC 5280/RFC 3280 and RFC 6125/RFC 2818 at least), in addition to the API documentations.

This question on Security.SE should also be of interest:

  • What data should I validate when validating X.509 certificates using Java?
  • How are possible uses for X.509 (SSL) certificates denoted?
like image 197
Bruno Avatar answered Oct 13 '22 11:10

Bruno


What you can do is implement your own checker on top of e.g Apache's HttpClient
You should initialize an SSL context and override the TrustManagers to do any checking you want.

The hostname verification can be done automatically by the library.

E.g. the following will configure the SSL socket handling to throw an exception if the hostname does not match the certificate's info:

SSLSocketFactory sf = new SSLSocketFactory(
    SSLContext.getInstance("TLS"),
    SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
like image 22
Cratylus Avatar answered Oct 13 '22 09:10

Cratylus