Apache Qpid – Securing Connections With SSL

In some cases you may want to allow connections to your brokers from outside the firewall. For obvious security reasons it’s recommended to use some form of encryption for such connections. Apache Qpid provides two options for securing connections.

  • SSL
  • SASL security layer

This articles focuses on how to secure your connections between the C++ broker (on Linux) and the JMS and C++ clients with SSL.
I plan to write an entry explaining how to use the SASL security layer in the future.

Disclaimer : The SSL tools/techniques used below for creating certificates are for illustration/testing purposes only. For production you need to use certificates from a competent third-party CA or use Professional grade CA software.

1.0 Installing SSL Support

1.1 Installing SSL Support For C++ Broker & Client
The C++ Broker/Client uses Mozilla’s Network Security Services Library (SSL) for SSL support.

1.1.1 Installing From RPMs
For Broker support

yum install qpidd-ssl

For Client

yum install qpidc

1.1.2 Building From Source

  • Download a released source tarball from here
  • Make sure you have the following dependencies installed
    • nss
    • nspr
  • Follow the build instructions given in the INSTALL file located in the source directory

1.2 Installing Java Client
Download the Java client from here.

2.0 Creating the SSL Certificates For Testing
Lets create the required certificates for testing our SSL setup. For this purpose we are using the Mozilla certutil tool.
For more details please read [1].

2.1 Setting Up The CA
We need to setup the CA and the self signed root CA certificate.

  • Create a new certificate database in the CA_db directory.
                 >mkdir CA_db
                 >certutil -N -d CA_db
                 
  • Create the self-signed Root CA certificate, specifying the subject name for the certificate.
                 >certutil -S -d CA_db -n "MyRootCA" -s "CN=MyRootCA,O=ACME,ST=Ontario,C=CA" -t "CT,," -x -2
                
    • It will prompt you for a password. Enter the password you specified when creating the root CA database.
    • Type “y” for “Is this a CA certificate [y/N]?”
    • Press enter for “Enter the path length constraint, enter to skip [<0 for unlimited path]: >”
    • Type “n” for “Is this a critical extension [y/N]?”
  • Extract the CA certificate from the CA’s certificate database to a file.
               >certutil -L -d CA_db -n "MyRootCA" -a -o CA_db/rootca.crt
              

2.2 Creating The Certificates For The Server (Qpid Broker)

  • Create a certificate database for the Qpid Broker.
                  >mkdir server_db
                  >certutil -N -d server_db
                 
  • Import the CA certificate into the broker’s certificate database, and mark it trusted for issuing certificates for SSL client and server authentication.
                >certutil -A -d server_db -n "MyRootCA" -t "TC,," -a -i CA_db/rootca.crt
                
  • Create the server certificate request, specifying the subject name for the server certificate. We make the common name (CN) be identical to the hostname of the server. Note that this step generates the server’s private key, so it must be done in the server’s database directory.
                 >certutil -R -d server_db -s "CN=localhost.localdomain,O=ACME,ST=Ontario,C=CA" -a -o server_db/server.req
                 
  • This step simulates the CA signing and issuing a new server certificate based on the server’s certificate request. The new cert is signed with the CA’s private key, so this operation uses the CA’s databases. This step leaves the server’s new certificate in a file.
                >certutil -C -d CA_db -c "MyRootCA" -a -i server_db/server.req -o server_db/server.crt -2 -6
                
    • Select “0 – Server Auth” at the prompt
    • Press 9 at the prompt
    • Type “n” for “Is this a critical extension [y/N]?”
    • Type “n” for “Is this a CA certificate [y/N]?”
    • Enter “-1″ for “Enter the path length constraint, enter to skip [<0 for unlimited path]: >”
    • Type “n” for “Is this a critical extension [y/N]?”
    • When prompted password, enter the password you specified when creating the root CA database.
  • Import (Add) the new server certificate to the broker’s certificate database in the server_db directory with the appropriate nickname. Notice that no trust is explicitly needed for this certificate.
               >certutil -A -d server_db -n localhost.localdomain -a -i server_db/server.crt -t ",,"
               

2.3 Creating The Certificates For The C++ Client

  • Create a new certificate database in the client_db directory.
                  >mkdir client_db
                  >certutil -N -d client_db
            
  • Import the CA certificate into the client's certificate database, and mark it trusted for issuing certificates for SSL client and server authentication.
                  >certutil -A -d client_db -n "MyRootCA" -t "TC,," -a -i CA_db/rootca.crt
                 
  • Create the client certificate request, specifying the subject name for the certificate.
                  >certutil -R -d client_db -s "CN=CppClient,O=ACME,ST=Ontario,C=CA" -a -o client_db/client.req
                  
  • This step simulates the CA signing and issuing a new client certificate based on the client's certificate request. The new cert is signed with the CA's private key, so this operation uses the CA's databases. This step leaves the client's new certificate in a file.
                 >certutil -C -d CA_db -c "MyRootCA" -a -i client_db/client.req -o client_db/client.crt -2 -6
                 
    • Select "1 - Client Auth" at the prompt
    • Press 9 at the prompt
    • Type "n" for "Is this a critical extension [y/N]?"
    • Type "n" for "Is this a CA certificate [y/N]?"
    • Enter "-1" for "Enter the path length constraint, enter to skip [<0 for unlimited path]: >"
    • Type "n" for "Is this a critical extension [y/N]?"
    • When prompted password, enter the password you specified when creating the root CA database.
  • Add the new client certificate to the client's certificate database in the client_db directory with the appropriate nickname. Notice that no trust is required for this certificate.
                 >certutil -A -d client_db -n "CppClient" -a -i client_db/client.crt -t ",,"
                 

2.4 Creating The Certificates For The JMS Client

  • Import the CA certificate in to the trust store.
                 keytool -import -v -keystore trust-store.jks -storepass password -alias RootCA -file CA_db/rootca.crt
                 
  • Import the CA certificate in to the key store. (need for client authentication)
                 keytool -import -v -keystore key-store.jks -storepass password -alias RootCA -file CA_db/rootca.crt
                 
  • Generate keys for the client certificate.
                 keytool -genkey -alias java-client -keyalg RSA -sigalg MD5withRSA -validity 356 -keystore key-store.jks -storepass password
                 

    Answer the questions accordingly and press enter when prompted for the password to select the same password as the key-store.

  • Create a certificate request.
                 keytool -certreq -alias java-client -sigalg MD5withRSA -keystore key-store.jks -storepass password -v -file java-client.req
                 

    Answer the questions accordingly and press enter when prompted for the password to select the same password as the key-store.

  • Create a certificate request.
                 keytool -certreq -alias java-client -sigalg MD5withRSA -keystore key-store.jks -storepass password -v -file java-client.req
                 

    Answer the questions accordingly and press enter when prompted for the password to select the same password as the key-store.

  • Sign the certificate request using CA certificate.
                 certutil -C -d CA_db -c "MyRootCA" -a -i java-client.req -o java-client.crt  -2 -6
                 
    • Select "1 - Client Auth" at the prompt
    • Press 9 at the prompt
    • Type "n" for "Is this a critical extension [y/N]?"
    • Type "n" for "Is this a CA certificate [y/N]?"
    • Enter "-1" for "Enter the path length constraint, enter to skip [<0 for unlimited path]: >"
    • Type "n" for "Is this a critical extension [y/N]?"
    • When prompted password, enter the password you specified when creating the root CA database.
  • Import the certificate into the key store.
                 keytool -import -v -alias java-client -keystore key-store.jks -storepass password -file java-client.crt
                 

3.0 Configuring The C++ Broker To Use SSL

  • The $CERT_LOC denotes the directory where we created the CA_db, server_db, client_db, trust-store.jks and key-store.jks
  • The broker-pfile needs to contain the password you entered while creating the server_db
  • If you want to use client authentication, add --ssl-require-client-authentication to the broker options

If starting the broker from an installation.

/usr/sbin/qpidd --ssl-cert-db $CERT_LOC/server_db/ 
                       --ssl-cert-password-file $CERT_LOC/broker-pfile 
                       --ssl-cert-name localhost.localdomain 
                       --ssl-port 5674

If starting the broker from a source build

./src/qpidd --load-module ./src/.libs/ssl.so
                 --ssl-cert-db $CERT_LOC/server_db/ 
                 --ssl-cert-password-file $CERT_LOC/broker-pfile 
                 --ssl-cert-name localhost.localdomain 
                 --ssl-port 5674

4.0 Configuring The C++ Client To Use SSL
The following steps needs to be followed to enable SSL on the C++ client side.
The client side options are specified using environment variables.

  1. Load the SslConnector.so
    If running from source

                           export QPID_LOAD_MODULE=./src/.libs/sslconnector.so
                  
  2. To open an SSL enabled connection, set the protocol to ssl in the ConnectionSettings passed to Connection::open():
                    #include 
                    #include 
                    #include 
    
                    using namespace qpid::client;
    
                    int main(int , char** ) {
    
                    ConnectionSettings connectionSettings;
                    connectionSettings.host = "localhost";
                    connectionSettings.port = 5674;
                    connectionSettings.protocol="ssl";
    
                    Connection connection;
                    try {
                         connection.open(connectionSettings);
                    ......
                
  3. If client authentication is used, then we need to specify the clients certificate.
                     export QPID_SSL_CERT_DB=$CERT_LOC/client_db/
                     export QPID_SSL_CERT_NAME=CppClient
                     export QPID_SSL_CERT_PASSWORD_FILE=$CERT_LOC/cpfile
                 

4.0 Configuring The JMS Client To Use SSL
The following steps needs to be followed to enable SSL on the JMS client side.

  1. You need to specify the ssl option and the correct port in the Connection URL
                     amqp://guest:guest@test/?brokerlist='tcp://localhost:5674?ssl='true''
                  
  2. Specify the trust store which contains the CA certificate
                    -Djavax.net.ssl.trustStore=$CERT_LOC/trust-store.jks 
                    -Djavax.net.ssl.trustStorePassword=password 
                
  3. If client authentication is used, you need to specify the trust store and the key store which contains the client's certificate
                    -Djavax.net.ssl.keyStore=$CERT_LOC/key-store.jks 
                    -Djavax.net.ssl.keyStorePassword=password 
                    -Djavax.net.ssl.trustStore=$CERT_LOC/trust-store.jks 
                    -Djavax.net.ssl.trustStorePassword=password 
                
  4. In case you run into issues adding "-Djavax.net.debug=ssl" will enable logging in the Java SSL code

If you have any questions please feel free to contact us at users@qpid.apache.org.



8 Comments

  1. jason wrote:

    Thanks for the great post!
    Does qpid support the checking of certificate revocation?

  2. rajith wrote:

    @jason
    Thanks for your comment.
    We don’t check for certificate revocation atm. Would you like to create a JIRA for this ? We can look at getting it done in time for 0.7

  3. jason wrote:

    Sure, I just created one https://issues.apache.org/jira/browse/QPID-2535 , look forward to your next qpid article!

  4. Sam Hendley wrote:

    I have translated this into an executable linux script which I have posted as a gist:

    http://gist.github.com/468595

  5. rajith wrote:

    @Sam – thx a lot for sharing this with us.
    I am sure folks will find that very useful for creating certificates for testing.

  6. Roger wrote:

    Rajith: Thanks for the steps to create SSL certificates. They are very helpful. I have used these steps to create the client and server certificates. Then I have verified them:
    certutil -V -d ${CERT_LOC}/server_db -u V -n loalhost.localdomain
    certutil -V -d ${CERT_LOC}/client_db -u C -n CppClient
    It says they are valid. The broker starts fine and says it is listening for SSL connections on port 5674. However, when I run your C++ client above with only the QPID_LOAD_MODULE set, I get an “Unknown protocol: ssl” exception. When I run the client with the certificate env variables, I get an NSS 8054 error “You are attempting to import a cert with the same issuer/serial as an existing cert, but that is not the same cert.” Any idea what I might be doing wrong? I am currently on QPID 0.12. Thanks.

  7. [...] > I google it with “qpidd ssl” and i found this : > http://rajith.2rlabs.com/2010/03/01/apache-qpid-securing-connections-with-ssl/ > > I think you need to install qpidd-ssl and configure a certificat to use > with. > > Mehdi [...]

  8. rajith wrote:

    @Roger

    Sorry I haven’t run into the issue you mentioned. Would you like to post your question on the Qpid user list? Perhaps somebody else might have encountered this issue before.

    Regards,

    Rajith