# List all entries in a JKS keytool -list -keystore mykeystore.jks -storepass changeit # List all entries in a PKCS12 keytool -list -keystore mykeystore.jks -storepass changeit -storetype pkcs12 # List detailed information about all entries in a JKS keytool -list -v -keystore mykeystore.jks -storepass changeit # Rename an alias in a JKS keytool -changealias -alias "client01" -destalias "client02" -keystore mykeystore.jks -storepass changeit # Remove an alias in a JKS keytool -delete -alias "client01" -keystore mykeystore.jks -storepass changeit # Create a JKS with a self-signed certificate keytool -genkey -keyalg RSA -alias client01 -keystore mykeystore.jks -storepass changeit -validity 365 -keysize 2048 # Create a JKS and import certificate from file (if keystore does not exist it will be created) keytool -keystore mykeystore.jks -storepass changeit -import -file mycertfile.crt # Import a certificate to trust to a jks keytool -import -alias server01 -file server01.crt -keystore mykeystore.jks # Change JKS keystore password keytool -storepasswd -keystore mykeystore.jks # Change a JKS key's password: keytool -keypasswd -alias <key_name> -keystore mykeystore.jks # Extract certificate from a jks keystore keytool -export -keystore mykeystore.jks -alias client01 -file client01.crt # Convert a PKCS12 (p12) certificate to JKS keytool -importkeystore -srckeystore mysourcekeystore.p12 -destkeystore mydestkeystore.jks -srcstoretype PKCS12 -deststoretype JKS -srcstorepass mysourcepassword -deststorepass mydestpassword -srcalias mysourcecertalias -destalias mydetscertalias -srckeypass mysourcekeypassword -destkeypass mydestkeypassword # Convert a JKS keystore to a PKCS12 keystore keytool -importkeystore -srckeystore mykeystore.jks -destkeystore mykeystore.p12 -deststoretype pkcs12 # Generate a self-signed certificate and put it into a JKS (valid for 720 days) keytool -genkey -keyalg RSA -alias server -keystore selfsigned.jks -validity 720 -keysize 2048 Tested on Red Hat 7 and Java 8
Category Archives: Java - Page 9
My Java Keytool cheat sheet
My Play Framework Systemd script
Ubuntu deprecated Upstart so I had to turn to Systemd for my app controls in Ubuntu 18.04. In this script I set 2 environment variables (HOME and LANG), change directory to the app directory and starts the Play Framework application
# Myapp systemd script # # Location:/lib/systemd/system/myapp.service # # Useful commands: # # Start Myapp: systemctl start myapp.service # Stop Myapp: systemctl stop myapp.service # Restart Myapp: systemctl restart myapp.service # Show status: systemctl status myapp.service # Enable start on boot: systemctl enable myapp.service # Disable start on boot:systemctl disable myapp.service # # List all services running: systemctl # Check config: systemd-analyze verify myapp.service # #################################################################################### [Unit] Description=Job that runs my app daemon [Service] Type=forking Environment=HOME=/opt/myapp/app Environment=LANG=en_US.UTF-8 ExecStartPre=/bin/bash -c 'cd /opt/myapp/app' ExecStart=/bin/bash -c 'bin/myapp -J-Xms256M -J-Xmx768m -J-server -Dhttp.port=80 -Dconfig.file=conf/application.conf -Dlogger.file=conf/application-logger.xml' [Install] WantedBy=multi-user.target
The arguments for the Play service are what I normally use for AWS. You might need other settings
Tested on Ubuntu 18.04 and Play Framework 2.3
Setup IBM MQ v9 for Java clients over SSL
Time for another IBM MQ example. This time it is for connecting to IBM MQ with a Java client over SSL. I’m going to use self-signed certificates in this example to eliminate any certificate chain problems. The source code for the Java client can be found below. Time to start creating the user to use for this
A. Create a new user that the client can use to connect with. Let’s call him “bob”
* Bob needs to be created on OS level since this is what IBM MQ uses to authorise users
* Bob should NOT be a member of the mqm group since it would make him a privileged user (and privileged users are blocked by default)
* Bob does not need login privileges on OS level (/sbin/nologin)
B. Now we need to grant this user some basic privileges
I am here going to use the setmqaut program but you can also use MQExplorer if you like a GUI more
setmqaut -m MYQM01 -t qmgr -p bob -all +connect +inq setmqaut -m MYQM01 -t queue -n MYQUEUE -p bob -all +put +get
Connect and inquiry for the queue manager and get and put on our example queue.
C. Time to create the client certificate and place it into a jks
For this I am going to use the ikeycmd program shipped with MQ (<mqserver installation dir>/java/jre64/jre/bin/ikeycmd)
Create client database
ikeycmd -keydb -create -db "client.jks" -pw clientpass -type jks
Create client certificate
ikeycmd -cert -create -db "client.jks" -pw clientpass -label ibmwebspheremqbob -dn "CN=bob,OU=bob,O=Bobs Company,C=SE" -expire 365
One thing to note here is the label for the client certificate. This has to be in the form of: ‘ibmwebspheremq’ + ‘client username’ (all lower case)
In our case ‘ibmwebspheremqbob’ since our user is called Bob
To check that the certificate is in the jks
ikeycmd -cert -list -db "client.jks" -pw clientpass
This will give you the label of the certificates in the jks. In our case: ‘ibmwebpsheremqbob’
D. Let us create the server certificate now
Create server database
ikeycmd -keydb -create -db "/var/mqm/qmgrs/MYQM01/ssl/MYQM01.kdb" -pw serverpass -type cms -expire 1000 -stash
Create server certificate
ikeycmd -cert -create -db "/var/mqm/qmgrs/MYQM01/ssl/MYQM01.kdb" -pw serverpass -label ibmwebspheremqmyqm01 -dn "CN=MYQM01,OU=ICC,O=GU,C=SE" -expire 1000 -sig_alg SHA256_WITH_RSA
A word about the certificate label here. Default name for this certificate is in the form of: ‘ibmwebspheremq’ + ‘queue manager name’ (all lower case)
In our case this becomes: ‘ibmwebpsheremqmyqm01’
If you need to change the label (or want to be able to present different certificates on different channels) you can set the CERTLABL property on the queue manager (or channel). The CERTLABL label should then correspond to the label in the .kbd file
To check that the certificate is in the kbd
ikeycmd -cert -list -db "/var/mqm/qmgrs/MYQM01/ssl/MYQM01.kdb" -pw serverpass
This will give you the label of the certificates in the kbd. In our case: ‘ibmwebpsheremqmyqm01’
E. Time for the certificate exchange between client and server
Extract the public part of the client certificate
ikeycmd -cert -extract -db "client.jks" -pw clientpass -label ibmwebspheremqbob -target client.crt -format ascii
Add the client cert to the server
ikeycmd -cert -add -db "/var/mqm/qmgrs/MYQM01/ssl/MYQM01.kdb" -pw serverpass -label ibmwebspheremqbob -file client.crt -format ascii
Check so that both certificates are in the kbd
ikeycmd -cert -list -db "/var/mqm/qmgrs/MYQM01/ssl/MYQM01.kdb" -pw serverpass
This should yield the result:
ibmwebspheremqbob ibmwebspheremqmyqm01
F. and now from the server to the client
Extract the public part of the server certificate
ikeycmd -cert -extract -db "/var/mqm/qmgrs/MYQM01/ssl/MYQM01.kdb" -pw serverpass -label ibmwebspheremqmyqm01 -target MYQM01.crt -format ascii
Add the server certificate to the client jks
ikeycmd -cert -add -db "client.jks" -pw clientpass -label ibmwebspheremqmyqm01 -file MYQM01.crt -format ascii
Check so that both certificates are in the jks
ikeycmd -cert -list -db "client.jks" -pw clientpass
This should now yield the result:
ibmwebspheremqmyqm01 ibmwebspheremqbob
Certificates are now done. Time to setup the MQ objects. For this I’m going to use the runmqsc program, eq. runmqsc MYQM01
G. Queue manager needs to know where the kdb file is
ALTER QMGR SSLKEYR('/var/mqm/qmgrs/MYQM01/ssl/MYQM01')
NOTE: We omit the ‘.kbd’ when setting the path in the queue manager
Another thing we are going to do is to set FIPS to false in this example
ALTER QMGR SSLFIPS(NO)
H. There is also need for a server connection channel for the client to connect to
DEFINE CHANNEL('CLIENTS') CHLTYPE(SVRCONN) TRPTYPE(TCP) SSLCIPH(TLS_RSA_WITH_AES_128_CBC_SHA256) MCAUSER('bob') SSLCAUTH(REQUIRED) REPLACE
A few words on SSLCIPH and SSLCAUTH. SSLCIPH is the encryption cipher to use. This cipher has to exist both on the MQ server and in the Java installation that the client runs on.
SSLCAUTH(REQUIRED) tells MQ that the client also should present a certificate when connecting, so called two-way certificate exchange.
I. When all MQ objects have been created/changed we need to refresh the SSL cache in MQ
REFRESH SECURITY TYPE(SSL)
J. Time to test our setup with a little bit of java code
——————————————–
JAVA EXAMPLE CLIENT CODE
——————————————–
import java.io.IOException; import java.util.Hashtable; import com.ibm.mq.*; import com.ibm.mq.constants.MQConstants; public class MQClients { static private String CHANNEL = "CLIENTS"; static private int PORT = 1414; static private String HOST = "mymqhost.se"; static private String QMANAGER = "MYQM01"; static private String QUEUE = "MYQUEUE"; static private String USER = "bob"; static private Hashtable<String, Object> props = new Hashtable<String, Object>(); static MQQueueManager qMgr = null; static private void putMsgOnQueue(String message) { // Disabling IBM cipher suite mapping due to // using Oracle Java and not IBM Java System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false"); // Enabling SSL debug to view the communication //System.setProperty("javax.net.debug", "ssl:handshake"); System.setProperty("javax.net.ssl.trustStore","client.jks"); System.setProperty("javax.net.ssl.trustStorePassword","clientpass"); System.setProperty("javax.net.ssl.keyStore","client.jks"); System.setProperty("javax.net.ssl.keyStorePassword","clientpass"); props.put(MQConstants.CHANNEL_PROPERTY, CHANNEL); props.put(MQConstants.PORT_PROPERTY, PORT); props.put(MQConstants.HOST_NAME_PROPERTY, HOST); props.put(MQConstants.USER_ID_PROPERTY, USER); props.put(MQConstants.PASSWORD_PROPERTY, "secret"); // Bobs OS password props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, "TLS_RSA_WITH_AES_128_CBC_SHA256"); try { qMgr = new MQQueueManager(QMANAGER, props); // MQOO_OUTPUT = Open the queue to put messages // MQOO_INPUT_AS_Q_DEF = Using queue-defined defaults int openOptions = MQConstants.MQOO_OUTPUT; // creating destination MQQueue queue = qMgr.accessQueue(QUEUE, openOptions); // specify the message options... MQPutMessageOptions pmo = new MQPutMessageOptions(); // Default // MQPMO_ASYNC_RESPONSE = MQPUT operation is completed without the // application waiting for the queue manager to complete the call // Using this option can improve messaging performance, // particularly for applications using client bindings. pmo.options = MQConstants.MQPMO_ASYNC_RESPONSE; // create message MQMessage mqMessage = new MQMessage(); System.out.println("Writing message to queue: " + QUEUE); mqMessage.writeString(message); // Put message on queue queue.put(mqMessage, pmo); // Close queue queue.close(); // Get status MQAsyncStatus asyncStatus = qMgr.getAsyncStatus(); // Print status code (0 = successful) System.out.println(asyncStatus.reasonCode); } catch (MQException e) { System.out.println("The connection to MQ could not be established." + e.getMessage()); } catch (IOException e) { System.out.println("Error while writing message." + e.getMessage()); } finally { try { qMgr.disconnect(); } catch (MQException e) { System.out.println("The connection could not be closed." + e.getMessage()); } } } static private void getMsgsFromQueue(){ // Disabling IBM cipher suite mapping due to // using Oracle Java and not IBM Java System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false"); // Enabling SSL debug to view the communication //System.setProperty("javax.net.debug", "ssl:handshake"); System.setProperty("javax.net.ssl.trustStore","client.jks"); System.setProperty("javax.net.ssl.trustStorePassword","clientpass"); System.setProperty("javax.net.ssl.keyStore","client.jks"); System.setProperty("javax.net.ssl.keyStorePassword","clientpass"); props.put(MQConstants.CHANNEL_PROPERTY, CHANNEL); props.put(MQConstants.PORT_PROPERTY, PORT); props.put(MQConstants.HOST_NAME_PROPERTY, HOST); props.put(MQConstants.USER_ID_PROPERTY, USER); props.put(MQConstants.PASSWORD_PROPERTY, "secret"); // Bobs OS password props.put(MQConstants.SSL_CIPHER_SUITE_PROPERTY, "TLS_RSA_WITH_AES_128_CBC_SHA256"); try { qMgr = new MQQueueManager(QMANAGER, props); // MQOO_INPUT_SHARED = Open the queue to read messages int openOptions = MQConstants.MQOO_INPUT_SHARED; // creating destination MQQueue queue = qMgr.accessQueue(QUEUE, openOptions); // specify the message options... MQGetMessageOptions gmo = new MQGetMessageOptions(); // Default gmo.options = MQConstants.MQPMO_ASYNC_RESPONSE; // create message MQMessage mqMessage = new MQMessage(); // Get message from queue System.out.println("Fetching message from queue: " + QUEUE); queue.get(mqMessage, gmo); // Get a message from MQMessage String message = mqMessage.readStringOfByteLength(mqMessage.getMessageLength()); // Display message System.out.println(message); // Close queue queue.close(); // Get status MQAsyncStatus asyncStatus = qMgr.getAsyncStatus(); // Print status code (0 = successful) System.out.println(asyncStatus.reasonCode); } catch (MQException e) { System.out.println("The connection to MQ could not be established." + e.getMessage()); } catch (IOException e) { System.out.println("Error while fetching the message." + e.getMessage()); } finally { try { qMgr.disconnect(); } catch (MQException e) { System.out.println("The connection could not be closed." + e.getMessage()); } } } public static void main(String[] args) { putMsgOnQueue("world "); getMsgsFromQueue(); } }
NOTE: The SSL_CIPHER_SUITE_PROPERTY in the client must be the same cipher that is defined on the channel SSLCIPH property.
A few troubleshooting tips
* IBM MQ and Java does not always agree on naming so the cipher you choose in MQ might have another name in Oracle/Sun/IBM Java - be sure to check the cipher name translation table on IBM site before giving up * The error logs for the queue manager can be found in /var/mqm/qmanagers/MYQM01/errors * Make sure the GSKit is installed in your MQ installation. If not you are in the risk of getting strange errors like "MQRC_UNSUPPORTED_CIPHER_SUITE" even though they are correct * To enable SSL verbose logging uncomment the line System.setProperty("javax.net.debug", "ssl:handshake") in the example code above
Tested on IBM MQ 9.0.5.0 on Red Hat 7, client using Java version 1.8.0_141 and IBM com.ibm.mq.allclients v9.0.4.0 on OSX 10.13.6