Description of TLS related files

The purpose of this README file is to show how to generate SSL-related key pairs and self-signed certificates for testing, and how to configure the RocketMQ TLS configuration file parameters.

1. Generating SSL related files

CA certificate and key file generation (directly generate CA key and its self-signed certificate)

openssl req -newkey rsa:2048 -passout pass:123456 -keyout ca_rsa_private.pem -x509 -days 365 -out ca.crt -subj "/C=CN/ST=BJ/L=BJ/O=COM/OU=NSP/CN=CA/emailAddress=youremail@apache.com"

Server certificate and key file generation (directly generate server key and certificate to be signed)

openssl req -newkey rsa:2048 -passout pass:server -keyout server_rsa_private.pem  -out server.csr -subj "/C=CN/ST=BJ/L=BJ/O=COM/OU=NSP/CN=SERVER/emailAddress=youremail@apache.com"

Signing a server certificate with a CA certificate and key

openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out server.crt
# Alternatively, convert the encrypted RSA key to an unencrypted RSA key, avoiding the requirement to enter the decryption password for each read.
openssl rsa -in server_rsa_private.pem -out server_rsa_private.pem.unsecure -passin pass:server

Client certificate and key file generation (directly generate client key and certificate to be signed)

openssl req -newkey rsa:2048 -passout pass:client -keyout client_rsa_private.pem -out client.csr -subj "/C=CN/ST=BJ/L=BJ/O=COM/OU=NSP/CN=CLIENT/emailAddress=youremail@apache.com"

Signing a client certificate with a CA certificate and key

openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out client.crt
# Alternatively, convert the encrypted RSA key to an unencrypted RSA key
openssl rsa -in client_rsa_private.pem -out client_rsa_private.pem.unsecure -passin pass:client

PKCS8 processing of the client and server keys (Reason: see Appendix 1)

openssl pkcs8 -topk8 -v1 PBE-SHA1-RC4-128 -in  server_rsa_private.pem   -out server_rsa_private_pkcs8.pem  -passout pass:server -passin pass:server
openssl pkcs8 -topk8 -v1 PBE-SHA1-RC4-128 -in client_rsa_private.pem -out client_rsa_private_pkcs8.pem  -passout pass:client -passin pass:client

2. RocketMQ TLS Configuration Instructions

ssl.properties (Note: there should be no spaces after the attribute value)

## client setting
tls.client.certPath=/home/rocketmq/ssl/client.crt
tls.client.keyPath=/home/rocketmq/ssl/client_rsa_private_pkcs8.pem
tls.client.keyPassword=client
tls.client.trustCertPath=/home/rocketmq/ssl/ca.crt

## server setting
tls.server.certPath=/home/rocketmq/ssl/server.crt
tls.server.keyPath=/home/rocketmq/ssl/server_rsa_private_pkcs8.pem
tls.server.keyPassword=server
tls.server.trustCertPath=/home/rocketmq/ssl/ca.crt
#server.auth.client
tls.server.need.client.auth=required

3. Use the SSL config on RocketMQ

  1. Client Side (System Properties)
   -Dtls.enable=true 
   -Dtls.client.authServer=true # force verifying server cert
   -Dtls.test.mode.enable=false # not a test mode
   -Dtls.config.file=/home/rocketmq/ssl/ssl.properties 
  1. Broker Side (System Properties)
   -Dtls.test.mode.enable=false #not a test mode
   -Dtls.config.file=/home/rocketmq/ssl/ssl.properties 
   -Dtls.server.need.client.auth=required

4. Appendix

  1. It's a bug in Java: https://bugs.openjdk.java.net/browse/JDK-8076999
$ docker logs rmqbroker
java.lang.IllegalArgumentException: Input stream does not contain valid private key.
	at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:278)
	at org.apache.rocketmq.remoting.netty.TlsHelper.buildSslContext(TlsHelper.java:124)
	at org.apache.rocketmq.remoting.netty.NettyRemotingClient.<init>(NettyRemotingClient.java:133)
	at org.apache.rocketmq.remoting.netty.NettyRemotingClient.<init>(NettyRemotingClient.java:99)
	at org.apache.rocketmq.broker.out.BrokerOuterAPI.<init>(BrokerOuterAPI.java:74)
	at org.apache.rocketmq.broker.out.BrokerOuterAPI.<init>(BrokerOuterAPI.java:70)
	at org.apache.rocketmq.broker.BrokerController.<init>(BrokerController.java:189)
	at org.apache.rocketmq.broker.BrokerStartup.createBrokerController(BrokerStartup.java:210)
	at org.apache.rocketmq.broker.BrokerStartup.main(BrokerStartup.java:58)
Caused by: java.io.IOException: ObjectIdentifier() -- data isn't an object ID (tag = 48)
	at sun.security.util.ObjectIdentifier.<init>(ObjectIdentifier.java:257)
	at sun.security.util.DerInputStream.getOID(DerInputStream.java:314)
	at com.sun.crypto.provider.PBES2Parameters.engineInit(PBES2Parameters.java:267)
	at java.security.AlgorithmParameters.init(AlgorithmParameters.java:293)
	at sun.security.x509.AlgorithmId.decodeParams(AlgorithmId.java:132)
	at sun.security.x509.AlgorithmId.<init>(AlgorithmId.java:114)
	at sun.security.x509.AlgorithmId.parse(AlgorithmId.java:372)
	at javax.crypto.EncryptedPrivateKeyInfo.<init>(EncryptedPrivateKeyInfo.java:95)
	at io.netty.handler.ssl.SslContext.generateKeySpec(SslContext.java:907)
	at io.netty.handler.ssl.SslContext.getPrivateKeyFromByteBuffer(SslContext.java:963)
	at io.netty.handler.ssl.SslContext.toPrivateKey(SslContext.java:953)
	at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:276)
	... 8 more

For illustration purposes:

openssl genrsa -out private_openssl.pem
openssl pkcs8 -topk8 -v1 PBE-SHA1-RC4-128 -in private_openssl.pem -out private_pkcs8_v1.pem -passout pass:123456
openssl pkcs8 -topk8 -v2 des3 -in private_openssl.pem -out private_pkcs8_v2.pem -passout pass:123456
KSE can open private_pkcs8_v1.pem just fine (that is when running under Java8, things are even worse with Java7), while trying to open private_pkcs8_v2.pem will cause java.io.IOException: ObjectIdentifier() -- data isn't an object ID (tag = 48).