Using .cer certificate to make an HTTPS request

I've already saw this question: Need to do a GET&POST HTTPS Request using a .cer certificate

Mine is quite different:

It is possible to make an HTTPS request using Java (vanilla, or using any library), trusting a server certificate and providing a client certificate, without using a keystore but using plain certificates?

I have both certs in X.509 format, and I don't want to have every certificate in a keystore.

2 answers

  • answered 2017-10-11 10:21 Shashwat Kumar

    If you really don't want to create a new keystore file, then can use KeyStore API to create in memory and load certificate directly.

    InputStream is = new FileInputStream("somecert.cer");
    // You could get a resource as a stream instead.
    
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    X509Certificate caCert = (X509Certificate)cf.generateCertificate(is);
    
    TrustManagerFactory tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(null); // You don't need the KeyStore instance to come from a file.
    ks.setCertificateEntry("caCert", caCert);
    
    tmf.init(ks);
    
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);
    

    Alternatively, if you want to avoid modifying your default cacerts file, then you'll need to implement your own TrustManager. However a TrustManager needs a keystore to load, so you can either create a new keystore file importing just your certificate.

    keytool -import -alias ca -file somecert.cer -keystore truststore.jks -storepass changeit
    

    And use something like following snippet to load the keystore file.

    TrustManagerFactory tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    // Using null here initialises the TMF with the default trust store.
    tmf.init((KeyStore) null);
    
    // Get hold of the default trust manager
    X509TrustManager defaultTm = null;
    for (TrustManager tm : tmf.getTrustManagers()) {
        if (tm instanceof X509TrustManager) {
            defaultTm = (X509TrustManager) tm;
            break;
        }
    }
    
    FileInputStream myKeys = new FileInputStream("truststore.jks");
    
    // Do the same with your trust store this time
    // Adapt how you load the keystore to your needs
    KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    myTrustStore.load(myKeys, "password".toCharArray());
    
    myKeys.close();
    
    tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(myTrustStore);
    
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);
    

  • answered 2017-10-11 11:15 mr mcwolf

    This is a rough example. Represents the X509KeyManager decorator.

    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(null, null);
    
    X509KeyManager manager = (X509KeyManager) kmf.getKeyManagers()[0];
    KeyManager km = new X509KeyManager() {
        @Override
        public String[] getClientAliases(String s, Principal[] principals) {
            return manager.getServerAliases(s, principals);
        }
    
        @Override
        public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
            return manager.chooseClientAlias(strings, principals, socket);
        }
    
        @Override
        public String[] getServerAliases(String s, Principal[] principals) {
            return manager.getServerAliases(s, principals);
        }
    
        @Override
        public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
            return manager.chooseServerAlias(s, principals, socket);
        }
    
        @Override
        public X509Certificate[] getCertificateChain(String s) {
            // You can use `s` to select the appropriate file
    
            try {
                File file = new File("path to certificate");
    
                try(InputStream is = new FileInputStream(file)) {
                    CertificateFactory factory = CertificateFactory.getInstance("X.509");
                    return new X509Certificate[] {
                            (X509Certificate) factory.generateCertificate(is)
                    };
                }
            }
            catch (CertificateException| IOException  e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        @Override
        public PrivateKey getPrivateKey(String s) {
            // You can use `s` to select the appropriate file
    
            // load and private key from selected certificate
            // this use for certificate authorisation
    
            try {
                File file = new File("private key file");
                byte buffer[] = Files.readAllBytes(file.toPath());
    
                KeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
                KeyFactory factory = KeyFactory.getInstance("RSA");
    
                return factory.generatePrivate(keySpec);
            }
            catch (NoSuchAlgorithmException | IOException | InvalidKeySpecException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    };
    
    TrustManager tm = new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    
        }
    
        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    
        }
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            try {
                File file = new File("path to certificate");
    
                try(InputStream is = new FileInputStream(file)) {
                    CertificateFactory factory = CertificateFactory.getInstance("X.509");
                    return new X509Certificate[] {
                            (X509Certificate) factory.generateCertificate(is)
                    };
                }
            }
            catch (CertificateException| IOException  e) {
                e.printStackTrace();
            }
    
            return null;
        }
    };
    
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init((KeyStore)null); //use java system trust certificates
    
    TrustManager managers[] = new TrustManager[tmf.getTrustManagers().length + 1];
    System.arraycopy(tmf.getTrustManagers(), 0, managers, 0, tmf.getTrustManagers().length);
    managers[managers.length - 1] = tm;
    
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(new KeyManager[]{ km }, managers, new SecureRandom());
    
    URL url = new URL("https://............/");
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    connection.setSSLSocketFactory(connection.getSSLSocketFactory());
    
    connection.connect();