1 Reply Latest reply on Jul 9, 2013 5:25 PM by atulkc

    How to configure custom trust manager when SSL is enabled

    atulkc

      I am using JBoss 7.2.0 Final and need some help in configuring custom trust manager on our application client when SSL is enabled.

       

      In our application we need to enable SSL between client and server for JMS, EJB as well as http traffic. I enabled SSL on all three. Attached is the standalone xml file.

       

      On client side we maintain our own truststore and have our own trustmanager to add/remove the certificates from the truststore. Basically when client connects to server for first time it will popup a dialog indicating that the server is not trusted (if the root CA is not already present in truststore) and user then has an option to accept or reject the certificate. We were earlier using JBoss 5.1 and were able to setup custom SSLSocketFactory by setting system property "org.jboss.remoting.defaultSocketFactory" as follows:

       

      System.setProperty("org.jboss.remoting.defaultSocketFactory", "com.dcm.common.http.ssl.CustomSSLSocketFactory");
      

       

      This CustomSSLSocketFactory was responsible for providing custom TrustManager implementation.

       

      In order to test setting custom trust manager I wrote a small test program that looks up JMS topic and publishes a message on it (I also have a similar test program for invoking an EJB method). Here's the code:

       

      import java.util.Properties;
      import javax.jms.Connection;
      import javax.jms.ConnectionFactory;
      import javax.jms.Destination;
      import javax.jms.JMSException;
      import javax.jms.MessageProducer;
      import javax.jms.Session;
      import javax.jms.TextMessage;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      
      
      public class CommonTopicPublisher {
        
        private MessageProducer producer;
        private Session session;
        private Connection connection;
        
        public static final String NAMING_CONTEXT_FACTORY = "org.jboss.naming.remote.client.InitialContextFactory";
      
      
        public CommonTopicPublisher() {
      
      
        }
        
        public static Properties getJmsEnvironment() {
          Properties environment = new Properties();
          // Configure the environment    
          environment.setProperty(Context.PROVIDER_URL, "remote://10.24.49.148:4447");
          environment.setProperty(Context.INITIAL_CONTEXT_FACTORY, NAMING_CONTEXT_FACTORY);
          environment.put(Context.SECURITY_PRINCIPAL, "testuser");
          environment.put(Context.SECURITY_CREDENTIALS, "passw0rd!");
          environment.put("jboss.naming.client.remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED","true");
          environment.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_STARTTLS","true");    
          return environment;
        }
      
      
        public void setup() throws NamingException, JMSException {
          InitialContext context = new InitialContext(getJmsEnvironment());
          ConnectionFactory connFactory = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
          System.out.println("Got connection factory");
          connection = connFactory.createConnection("testuser", "passw0rd!");
          System.out.println("Created Connection");
          
          session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
          System.out.println("Created session");
          
          Destination dest = (Destination) context.lookup("topic/dcfm/Common");
          System.out.println("Got common destination");
          
          producer = session.createProducer(dest);
          System.out.println("Created Producer");
          
          System.out.println("Added message listener");
        }
        
        public void sendMessage() throws JMSException {
          TextMessage msg = session.createTextMessage("Hello There");
          producer.send(msg);
          System.out.println("Message sent");
        }
        
        public void cleanUp() throws JMSException {
          producer.close();
          session.close();
          connection.close();
        }
      
      
        public static void main(String[] args) {
          CommonTopicPublisher publisher = null;
          try {
            System.out.println("Setting up common topic listener");
            
            System.setProperty("org.jboss.remoting.defaultSocketFactory","com.dcm.common.http.ssl.CustomSSLSocketFactory");
      
            publisher = new CommonTopicPublisher();
            publisher.setup();
            System.out.println("Common topic publisher setup");
            publisher.sendMessage();
          } catch (Exception e) {
            e.printStackTrace();
          } finally {
            if (publisher != null) {
              try {
                publisher.cleanUp();
              } catch (JMSException e) {
                e.printStackTrace();
              }
            }
          }
      
      
        }
          
      }
      

       

      I tried setting the system property as above but I get the following error on client side:

       

      javax.naming.NamingException: Failed to connect to any server. Servers tried: [remote://10.24.49.148:4447]
                at org.jboss.naming.remote.client.HaRemoteNamingStore.failOverSequence(HaRemoteNamingStore.java:200)
                at org.jboss.naming.remote.client.HaRemoteNamingStore.namingStore(HaRemoteNamingStore.java:131)
                at org.jboss.naming.remote.client.HaRemoteNamingStore.namingOperation(HaRemoteNamingStore.java:112)
                at org.jboss.naming.remote.client.HaRemoteNamingStore.lookup(HaRemoteNamingStore.java:223)
                at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:79)
                at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:83)
                at javax.naming.InitialContext.lookup(InitialContext.java:411)
                at com.brocade.dcm.as7.test.CommonTopicPublisher.setup(CommonTopicPublisher.java:79)
                at com.brocade.dcm.as7.test.CommonTopicPublisher.main(CommonTopicPublisher.java:113)
      

       

      and on server side I see following message:

       

      JBREM000200: Remote connection failed: javax.net.ssl.SSLException: Received fatal alert: certificate_unknown
      

       

      indicating that client does not recognize the server certificate.

       

      Since to enable SSL on client I had to use org.xnio.Options, I went through the xnio code and found that it is using SSL_JSSE_TRUST_MANAGER_CLASSES to instantiate the trust manager so I added following line to getJmsEnvironment method of my class and removed the System.setProperty that was setting SSLSocketFactory.

       

      environment.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_JSSE_TRUST_MANAGER_CLASSES","com.dcm.common.http.ssl.NullX509TrustManager");       
      

       

      With this change too I get the same error.

       

      I put a break point in xnio code (org.xnio.ssl.JsseSslUtils.createSSLContext method) to see whether it is able to get the trust manager I am setting however the breakpoint is never hit.

       

      So the question is how do I set custom trust manager on client side?

       

      Note that if I pass in truststore path (truststore that has the server certificate imported) and password as VM arguments then the above code works fine and I am able to publish message on JMS topic.

       

      Thanks,

      Atul

        • 1. Re: How to configure custom trust manager when SSL is enabled
          atulkc

          OK, after some more debugging through jboss remoting and xnio code I found that we have to include following property in the environment as well:

           

          environment.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_PROTOCOL","TLSv1.2");
          

           

          With this Xnio is now picking up the trust manager classes that are specified in SSL_JSSE_TRUST_MANAGER_CLASSES.

           

          So to summarize the environment for InitialContext (using Jboss remoting) will look as follows:

           

              environment.setProperty(Context.PROVIDER_URL, "remote://10.24.49.148:4447");
              environment.setProperty(Context.INITIAL_CONTEXT_FACTORY, NAMING_CONTEXT_FACTORY);
              environment.put(Context.SECURITY_PRINCIPAL, "testuser");
              environment.put(Context.SECURITY_CREDENTIALS, "passw0rd!");
              environment.put("jboss.naming.client.remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED","true");
              environment.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_STARTTLS","true");   
                  environment.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_PROTOCOL","TLSv1.2");
                  environment.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_JSSE_TRUST_MANAGER_CLASSES","<fully qualified class name of trust manager>");
          
          
          

           

          For EJB lookups if using Jboss ejb client environment should be as follows:

           

              
                  environment.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "true");
                  environment.put("remote.connection.<connection name>.connect.options.org.xnio.Options.SSL_STARTTLS", "true");
               environment.put("remote.connection.<connection name>.connect.options.org.xnio.Options.SSL_PROTOCOL","TLSv1.2");
                  environment.put("remote.connection.<connection name>.connect.options.org.xnio.Options.SSL_JSSE_TRUST_MANAGER_CLASSES","<fully qualified class name of trust manager>");