Wednesday, May 27, 2020

SSH improvements in Apache Karaf

Last year I contributed a number of SSH improvements to Apache Karaf, which I never found the time to blog about. In this post I'll cover how to use SSH with Apache Karaf, and also what the improvements were.

1) Using SSH with Apache Karaf

Download and extract Apache Karaf (4.2.8 was used for the purposes of this post). Start it by running "bin/karaf". By default, Karaf starts an SSH service which is configured in 'etc/org.apache.karaf.shell.cfg'. Here you can see that the default port is 8101. Karaf uses JAAS to authenticate SSH credentials - the default realm is "karaf". Associated with this realm is a PropertiesLoginModule, which authenticates users against the credentials stored in 'etc/users.properties'. Also note that the user must have a group defined that matches the value for "sshRole" in 'etc/org.apache.karaf.shell.cfg'. So let's try to SSH into Karaf using the default admin credentials, and it should work:
  • ssh karaf@localhost -p 8101

2) SSH algorithm update

The first improvement, which was merged for the 4.2.7 release, was to remove support by default for a number of outdated algorithms:
  • SHA-1 algorithms were removed
  • CBC ciphers were removed
  • Old ciphers such as 3-DES, Blowfish, Arcfour were removed
These can all be configured in 'etc/org.apache.karaf.shell.cfg' if necessary. The configuration values + defaults are now as follows:
  • ciphers = aes256-ctr,aes192-ctr,aes128-ctr
  • macs = hmac-sha2-512,hmac-sha2-256
  • kexAlgorithms = ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
So for example, the following now fails with Karaf 4.2.8 using the default configuration:
  • ssh karaf@localhost -p 8101 -c 3des-cbc

3) Elliptic curve support for SSH server keys 

The second improvement, which was also merged for 4.2.7, was to add support to configure Karaf with an elliptic curve SSH key. Previously only RSA keys were supported. When you start Karaf, it will generate an SSH key if one does not already exist, according to the "algorithm" (RSA) and "keySize" (2048) defined in 'etc/org.apache.karaf.shell.cfg', and store it in the "hostKey" (etc/host.key) file. As part of the improvement, the public key is also written out to a new configuration property "hostKeyPub" (etc/host.key.pub).

To see this in action, delete 'etc/host.key.*' and edit 'etc/org.apache.karaf.shell.cfg' and change:
  • keySize = 256
  • algorithm = EC
Now restart Karaf + try to ssh in using the "-v" parameter. You will see something like: "debug1: Server host key: ecdsa-sha2-nistp256 SHA256:sDa1k...".

4) Support for elliptic keys in the PublicKeyLoginModule

As well as supporting authentication using a password via the PropertiesLoginModule, Karaf also supports authentication using a public key via the PublickeyLoginModule. The PublickeyLoginModule authenticates a public key for SSH by comparing it to keys stored in 'etc/keys.properties'. I added support for Karaf 4.2.7 to be able to authenticate using elliptic keys stored in 'etc/key.properties', before only RSA public keys were supported.

To see how this works, generate a new elliptic curve key with an empty password:
  • ssh-keygen -t ecdsa -f karaf.id_ec
Now edit 'etc/keys.properties' and copy the public key that was written in "karaf.id_ec.pub". For example:
  • colm=AAAAE2VjZHNhLXNoY...0=,_g_:sshgroup
  • _g_\:sshgroup = group,ssh
 Now we can SSH into Karaf without a password prompt via:
  • ssh colm@localhost -p 8101 -i karaf.id_ec

5) Support for encrypted key password for SSH

Finally, I added support for encrypted key passwords for SSH. This change necessitated moving from using not-yet-commons-ssl to BouncyCastle for parsing SSH keys, as the former does not support encrypted keys or newer security algorithms in general. As a result, encrypted key passwords for SSH are not available in Karaf 4.2.x, but will be in the next major release (4.3.0). Note as well that encrypted key passwords only work for when Karaf is reading an externally generated encrypted private key.

To test this out, grab Karaf 4.3.x and generate a new RSA encrypted private key as follows (specifying a password of "security"):
  • openssl genpkey -out rsa.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -aes256
Edit 'etc/org.apache.karaf.shell.cfg' and change it as follows:
  • hostKey = ${karaf.etc}/rsa.pem
  • hostKeyPassword = security
Before starting Karaf, it's also necessary to register BouncyCastle as a security provider. Edit 'etc/config.properties' and add:
  • org.apache.karaf.security.providers = org.bouncycastle.jce.provider.BouncyCastleProvider
Now copy the BouncyCastle provider jar (e.g. bcprov-jdk15on-1.65.jar) to lib/ext and restart Karaf. It should be possible then to SSH into Karaf.

Tuesday, May 19, 2020

Recent deserialization CVEs in Apache Camel

Three security advisories have been published recently for Apache Camel that were found partly or entirely by me. CVE-2020-11971 relates to a JMX rebind flaw that'll be the subject of a future blog post. In this post I'll take a quick look at the other two issues, which both relate to Java object deserialization.

1) CVE-2020-11973

CVE-2020-11973 was caused by the fact that the Camel Netty component enabled Java Object serialization by default, without any whitelisting of acceptable packages associated with classes that are being deserialized. This is problematic as a malicious user could try to exploit a "gadget chain" to perform a remote code execution, or else create a denial of service type attack by creating a recursive object graph.

The fix was to remove object deserialization by default for the Netty component in 2.25.1 + 3.2.0. Users who still wish to avail of object serialization can explicitly enable object encoders/decoders on the component.

2) CVE-2020-11972

CVE-2020-11972 is for the exact same issue as for CVE-2020-11973 above, but in the Camel RabbitMQ component. From Camel 2.25.1 and 3.2.0, a new configuration option called "allowMessageBodySerialization" is introduced, which defaults to false.

Users who wish to avail of object serialization/deserialization can set this configuration option to true, (bearing in mind that this is not secure!) which enables the following behaviour:
  • The outbound message will be serialized on the producer side using Java serialization, if no type converter is available to handle the message body.
  • On the consumer side, the message body will be deserialized using Java deserialization if the message contains a "CamelSerialize" header.
If you are using either the Netty or RabbitMQ components with Camel, then please make sure to update to the latest releases ASAP.