javasslx509certificatex509x509trustmanager

Validate X.509 certificate against CA in Java


Lets say I have something like this (client side code):

TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        @Override
        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(null, trustAllCerts, null);

SocketFactory sf = sslc.getSocketFactory();
SSLSocket s = (SSLSocket) sf.createSocket("127.0.0.1", 9124);

This code is complete functional, but I really can not figure out, how to validate server's certificate against one concrete CA certificate that I have available in pem file.

All certificates are signed by my self-signed CA, and it is the CA I need to validate against (only against this one).

Every answer is appreciated.

EDIT:

In response to jglouie (thank you very much this way - can not vote up your answer).

I founded the solution:

new X509TrustManager() {

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        @Override
        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
                throws CertificateException {
            InputStream inStream = null;
            try {
                // Loading the CA cert
                URL u = getClass().getResource("tcp/cacert.pem");
                inStream = new FileInputStream(u.getFile());
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                X509Certificate ca = (X509Certificate) cf.generateCertificate(inStream);
                inStream.close();

                for (X509Certificate cert : certs) {
                    // Verifing by public key
                    cert.verify(ca.getPublicKey());
                }
            } catch (Exception ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    inStream.close();
                } catch (IOException ex) {
                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

        }
    }
};

Solution

  • I assume that the self-signed certificate of your CA is already loaded as follows:

    CertificateFactory cf = CertificateFactory.getInstance("X.509");   
    FileInputStream finStream = new FileInputStream("CACertificate.pem"); 
    X509Certificate caCertificate = (X509Certificate)cf.generateCertificate(finStream);  
    

    Then in the method to check certificate:

    @Override        
     public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)  throws CertificateException {
    
     if (certs == null || certs.length == 0) {  
          throw new IllegalArgumentException("null or zero-length certificate chain");  
     }  
    
     if (authType == null || authType.length() == 0) {  
                throw new IllegalArgumentException("null or zero-length authentication type");  
      }  
    
       //Check if certificate send is your CA's
        if(!certs[0].equals(caCertificate)){
             try
             {   //Not your CA's. Check if it has been signed by your CA
                 certs[0].verify(caCertificate.getPublicKey())
             }
             catch(Exception e){   
                  throw new CertificateException("Certificate not trusted",e);
             }
        }
        //If we end here certificate is trusted. Check if it has expired.  
         try{
              certs[0].checkValidity();
          }
          catch(Exception e){
                throw new CertificateException("Certificate not trusted. It has expired",e);
          }  
    }
    

    Disclaimer: Have not even atempted to compile the code