Sunday, May 29, 2016

Securing client-node communication in Cassandra Part1


Recently I came across this nosql database stuff, I did some researches and I landed in Cassandra world.
You can find information about Cassandra here: http://cassandra.apache.org/.
One of the issues I encountered working with Cassandra was securing the database, there is an excellent post (http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html) about  how to set up node to node encryption using Certificates and CA, but I didn't find a good tutorial for client to node encryption.
In this post I will do my best to show how to setup a secure communication in Cassandra between a client and a node, but first of all let's see how easy it is to sniff a client to node communication.
In the following pictures I sniffed with wireshark cqlsh asking Cassandra cql version (SELECT cql_version FROM system.local;)


and Cassandra answering (3.2.1)




I am too much paranoiac to let it be, I want an encrypted version, otherwise I won't have good dreams.

So first first of all let's create a CA that will sign SSL certificates, then we will make ourselves  sure that Cassandra is using a certificate signed by our "trusted" CA in order to set up a secure (encrypted) connection.

I use Linux so all the commands I will show in the following will work on a Linux system.
For the sake of my mind I prefer to keep separate the user that will act as CA from the user that will manage Cassandra, even if those users are always me.
Create the user that will act as a CA, he will generate the pair of keys, he will publish his public certificate and he will sign the request from the other user:

# useradd user-ca
# passwd user-ca

Create two directory, one to store the private key and one for the certificates:

#mkdir certs private

Protect the private directory so that only the CA user can read, write and enter in it:

#chmod 700 private

Create the serial file that will track the serial number of the certificates and the index.txt file that act as a database of signed certificates

#echo '01' > serial
#touch index.txt

Create a gen_ca_cert.conf like this:

[ ca ]
default_ca ={CAname}

[ {CAname} ]
dir =./
certificate = $dir/cacert.pem
database = $dir/index.txt
serial = $dir/serial
new_certs_dir = $dir/certs
private_key = $dir/private/privkey.pem

default_days = 365
default_md = md5
policy = CAuser_policy

[ CAuser_policy ]
stateOrProvinceName = optional
countryName = supplied
organizationName = supplied
organizationalUnitName =optional


commonName = supplied

[ req ]
distinguished_name = req_distinguished_name
prompt = no
default_bits = 2048
default_keyfile =./private/privkey.pem

[ req_distinguished_name ]
C = {COUNTRY}
ST = {PROVINCE}
L = {CITY}
O = {ORGANITATION}
OU = {ORGANITATION UNIT}
CN = {COMMON NAME}
emailAddress = {EMAIL ADDRESS}

where instead of the words between brackets and brackets themselves put the stuff that make sense for you.
Now it is possible to generate the CA private key and CA certificate:

#openssl req -config gen_ca_cert.conf -new -x509 -out cacert.pem

where
  • req: it is used to emit the root self signed certificate
  • -config specifies to user the conf file created before
  • -new specifies to generate a new certificate request
  • -x509 specifies the certificate format
  • -out specifies the name of the file that will be generated
A password will be required to protect the private key and it will be prompted to be inserted.

Now private key and certificate are generated, the key is stored in directory named private and the certificate in userCA home:

#ls -l
total 20
-rw-rw-r--. 1 CAuser CAuser 1314 May 25 14:24 cacert.pem
drwxrwxr-x. 2 CAuser CAuser 4096 May 25 11:52 certs
-rw-rw-r--. 1 CAuser CAuser 656 May 25 14:39 gen_ca_cert.conf
-rw-rw-r--. 1 CAuser CAuser 0 May 25 11:58 index.txt
drwx------. 2 CAuser CAuser 4096 May 25 14:23 private
-rw-rw-r--. 1 CAuser CAuser 3 May 25 11:58 serial
#ls -l private/
total 4
-rw-rw-r--. 1 CAuser CAuser 1834 May 25 14:24 privkey.pem

Now we can create the certificate and private key for each node, login as Cassandra administrator and issue the following command:

#keytool -genkeypair -keyalg RSA -alias client -keystore {KEYSTORENAME}.jks -storepass {PASSWORD} -keypass {PASSWORD} -validity 365 -keysize 2048 -dname "CN={IPADDRESS}, OU={ORGANIZATION UNIT}, O={ORGANIZATION}, L={LOCATION}, S={STATE},C={COUNTRY}"

where instead of the words between brackets and brackets themselves you put the stuff that make sense for you.
I use keytool instead of openssl for two reasons, first I found tutorials using it, and I copy from them, second it already generates the keystore in the format  Cassandra uses.

Keytool can be found in the bin directory of JDK distribution, I use jdk1.8.0_77
Now that {KEYSTORENAME}.jks is generated the certificate request can be generated:

#keytool -keystore {KEYSTORENAME}.jks -alias client -certreq -file {CERT-REQ} -keypass {KEYSTOREPASSWORD} -storepass {KEYSTOREPASSWORD}

this will create {CERT-REQ} that can be passed to the CA so that it can sign it.

We are now CAuser:

#openssl ca -config gen_ca_cert.conf -in {CERT-REQ}

Now the signed certificate is ready and stored in the certs directory:

#ls -la certs/
drwxrwxr-x. 2 CAuser CAuser 4096 May 25 17:59 .
drwx------. 13 CAuser CAuser 4096 May 26 09:33 ..
-rw-rw-r--. 1 CAuser CAuser 3963 May 25 17:59 01.pem

Give 01.pem back to Cassandra admin.

Let's change hat again, we are Cassandra admin.
The CA certificate and the signed certificate of the node should now be stored in the {KEYSTORENAME}.jks

#keytool -keystore {KEYSTORENAME}.jks -alias CARoot -import -file cacert.pem -noprompt -keypass {PASSWORD} -storepass {PASSWORD}

for the CA certificate

#keytool -keystore {KEYSTORENAME}.jks -alias client -import -file 01.pem -keypass {KEYSTOREPASSWORD} -storepass {KEYSTOREPASSWORD}

and for the signed certficate.

Copy the {KEYSTORENAME}.jks in a directory accessible from Cassandra, e.g. I copy it in the configuration directory of Cassandra that in my system is in /etc/cassandra/conf/ and as I installed Cassandra as a service I give the ownership of the file to the service/user

Login as root, or use sudo and type:

#cp {KEYSTORENAME}.jks /etc/cassandra/conf/{KEYSTORENAME}.jks
#chown cassandra:cassandra
#exit

Now cassandra.yaml has to be modified as following go to the  client_encryption_options section and change it as in the following:

client_encryption_options:
enabled: true
# If enabled and optional is set to true encrypted and unencrypted connections are handled.
optional: false
keystore: /etc/cassandra/conf/{KEYSTORENAME}.jks
keystore_password: {KEYSTOREPASSWORD}
#truststore:truststore.jks
#truststore_password: cassandra
require_client_auth: false
# Set trustore and truststore_password if require_client_auth is true
# More advanced defaults below:
protocol: TLS
algorithm: SunX509
store_type: JKS
cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]

Restart Cassandra.

Now you can try to connect to Cassandra:

#cqlsh –ssl
Validation is enabled; SSL transport factory requires a valid certfile to be specified. Please provide path to the certfile in [ssl] section as 'certfile' option in /home/ieio/.cassandra/cqlshrc (or use [certfiles] section) or set SSL_CERTFILE environment variable.

Now cqlsh  (the client) doesn't trust Cassandra node anymore, it needs the CA certificate in order to be sure that Cassandra is using a certificate signed by the CA.
Modify or create ~/.cassandra/cqlshrc as in the following:

[connection]
hostname = 127.0.0.1
port = 9042
factory = cqlshlib.ssl.ssl_transport_factory

[ssl]
certfile = ~/.cassandra/cacert.pem
# Optional, true by default
validate = true

and of course, copy the CA certificate in the directory you specify in the certfile and give right permission; as root if needed.
Now cqlsh can trust Cassandra and connect to it:

#cqlsh --ssl
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.1.14 | CQL spec 3.2.1 | Native protocol v3]
Use HELP for help.
>

If you trying to sniff the traffic with wireshark you cannot easily understand what is going on... phew now I can sleep.
But we want to always to  move further with security so let's force Cassandra to ask for a username and password each time we want to connect to it, in order to do that we just have to modify cassandra.yaml as in the following:

authenticator: PasswordAuthenticator

Restart Cassandra. If we now try to connect to it we will receive an error:

#cqlsh --ssl
Connection error: ('Unable to connect to any servers', {'127.0.0.1': AuthenticationFailed('Remote end requires authentication.',)})

So we must now add a username to the cqlsh command and a promt asking for a password will appear (default password is cassandra):

#cqlsh --ssl -u cassandra
Password:
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.1.14 | CQL spec 3.2.1 | Native protocol v3]
Use HELP for help.
>


Now we have a secure connection and the client can trust the node if we want to move even further we can force Cassandra to ask us for a signed certificate so that Cassandra can trust the client, but this will be the subject of one of the next posts.

Sunday, March 8, 2015

Build and run Nuttx inside Eclipse


In the previous posts I showed how to get started with Nuttx and set up and test simple network features, here I would like to show how to integrate Nuttx building environment with Eclipse.

First of all we need to download Eclipse and, of course JRE (Java Runtime Environment) that is used to run Eclipse.
Please refer to the following links to download all the necessary:

In the specific I used JRE Version 1.8.0_31 end Eclipse Luna SR2.

In order to install Eclipse we just need to unzip and untar the tarball downloaded.
I did it in my home directory:

#cd
#tar zxvf eclipse-cpp-luna-SR2a-linux-gtk.tar.gz

and install JRE:

#cd eclipse/
#tar zxvf jre-8u31-linux-i586.tar.gz
# mv jre1.8.0_31 jre

Let's now move on the top of the home directory
# cd ..
and let's create a simple and convenient text file to launch Eclipse.

Use your preferred text editor and create a text file starteclipse containing:

PATH=/home/user/nuttx_workdir/nuttx-code/misc/buildroot/build_arm/staging_dir/bin:/home/user/nuttx_workdir/nuttx-stellaris/misc/buildroot/build_arm_nofpu/staging_dir/bin:$PATH ./eclipse/eclipse

give execution permission to the file:

#chmod +x starteclipse

and launch it:

#./starteclipse

If everything went right you should see eclipse appearing on your desktop.
We can now import Nuttx building environment in it:
As showed in the screen-shoot below select File->New->Makefile Project with Existing Code 



A wizard will pop up, be sure to fill it with Project Name ad Existing Code Location and press Finish.


Now in the Project explorer you will see the Nuttx project, right-click it and select Properties from the context menu:


Select Environment on the Properties Windows and add a New Environment Variable as showed in the picture: CROSSDEV= arm-elf-, basically we are setting the same environment as we do from command line (see the previous post).

Press OK on the “New Variable” window and OK on the “Properties” window.




We are now ready, we can build Nuttx within Eclipse, just right click the Build in the context Menu

 


You can now “Clean Project” or modify it and “Rebuild Project” in a easy and handy way.

I also found really handy to launch the simulator inside Eclipse; in order to do it, select Run->External Tools->External Tools Configuration...



Here you can instruct Eclipse, to launch Qemu emulating the Stellaris platform and run Nuttx image.
In the Windows that will appear:
  1. select New,
  2. give a Name (e.g. start_qemu_stellaris),
  3. select the location where Qemu has been installed, if you use Xubuntu 14.04 /usr/bin/qemu-system-arm
  4. insert the Qemu parameters we used on the command line in the previous post
  5. click Run


You can now run Qemu just selecting it from Run->External Tools.
In case you have a real target you can use External Tools to run OpenOCD.

Saturday, February 28, 2015

Getting started with Nuttx Networking

In my previous post I explained how to get started with Nuttx on Qemu emulating Stellaris Soc.

In the following I show how to go further and configure the network in order to perform simple networking operations like ping and telnet.

So first of all let's update the Nuttx version:

$cd nuttx
$export PATH=`pwd`/../misc/buildroot/build_arm_nofpu/staging_dir/bin:$PATH
$export CROSSDEV=arm-elf-
$git pull

As I write the latest commit, the one I use, is d4e59915c6072e917b5017d5fefe2afb840d4097

Now we can configure the Nuttx

$cd tools
$./configure.sh lm3s6965-ek/nsh
$cd ..
$make menuconfig

At this point we should have a menu like the one showed below, here you can configure almost all the features of Nuttx.
Select ARP feature:
Networking Support →ARP Configuration→ ARP send




We must now modify few things in the Nuttx's Ethernet driver of the Stellaris chip.
You can apply the following patch with the command:
$patch -p1 < patch

diff --git a/nuttx/arch/arm/src/tiva/lm3s_ethernet.c b/nuttx/arch/arm/src/tiva/lm3s_ethernet.c
index 87334ab..98e5285 100644
--- a/nuttx/arch/arm/src/tiva/lm3s_ethernet.c
+++ b/nuttx/arch/arm/src/tiva/lm3s_ethernet.c
@@ -368,6 +368,7 @@ static void tiva_ethreset(struct tiva_driver_s *priv)
putreg32(regval, TIVA_SYSCON_RCGC2);
nllvdbg("RCGC2: %08x\n", regval);
+#if 0
/* Put the Ethernet controller into the reset state */
regval = getreg32(TIVA_SYSCON_SRCR2);
@@ -387,7 +388,7 @@ static void tiva_ethreset(struct tiva_driver_s *priv)
/* Wait just a bit, again. If we touch the ethernet too soon, we may busfault. */
up_mdelay(2);
-
+#endif
/* Enable Port F for Ethernet LEDs: LED0=Bit 3; LED1=Bit 2 */
#ifdef CONFIG_TIVA_ETHLEDS
@@ -1198,11 +1199,13 @@ static int tiva_ifup(struct net_driver_s *dev)
*/
nlldbg("Waiting for link\n");
+#if 0
do
{
phyreg = tiva_phyread(priv, MII_MSR);
}
while ((phyreg & MII_MSR_LINKSTATUS) == 0);
+#endif
nlldbg("Link established\n");
/* Reset the receive FIFO */

Actually I am removing some code using the #if 0 preprocessor macro.
The first #if 0 is to avoid to write at offset 0x048 (SRCR2) as you can see from
http://git.qemu.org/?p=qemu.git;a=blob;f=hw/arm/stellaris.c;h=cb515ec76520d3237c793d2ba406d27cd0b392f5;hb=HEAD#l546
Qemu does not implement write on this offset and it will end up in an annoying “Peripheral reset not implemented” log when you start Qemu.
The second #if 0 is to avoid Nuttx waiting for link up forever as the emulator does not seem to report the link status correctly.

Compile the new Nuttx image

$make

We now need to set up a basic virtual network between the host and Qemu, with the real board we would connect the board to a PC throught an ethernet cable.
So let's create a virtual device acting as a tap (tap means it emulate the ethernet)

$sudo ip tap add mode tap
let's give it a ip address:

$sudo ifconfig tap0 10.0.0.1
We are now ready to start our Qemu:

$qemu-system-arm -M lm3s6965evb -kernel nuttx -net nic,model=stellaris -net tap,ifname=tap0,script=no,downscript=no

Basically we are telling Qemu to emulate lm3s6965 evaluation board, using the image we built, a network interface that is the one of the stallaris SOC, and is linked to tap0 of the host and to not run any script associated to that tap.

As Qemu starts we could press CRTL+ALT+3 in order to get the console, we can now configure the Stellaris network interface inside the Qemu console and ping the host:

nsh> ifconfig 10.0.0.2 gw 10.0.0.1
nsh> ping 10.0.0.1



Just to end we could give a try to the telnet server run by Nuttx, from a host console give the command:

# telnet 10.0.0.2

this is what you will get.

user@nuttx-VirtualBox:~/nuttx_workdir/nuttx-stellaris/nuttx$ telnet 10.0.0.2
Trying 10.0.0.2...
Connected to 10.0.0.2.
Escape character is '^]'.

NuttShell (NSH)
nsh> help
help usage: help [-v] [<cmd>]

[ df hexdump mkdir ping sleep
? echo ifconfig mkfatfs ps test
break exec ifdown mkfifo put true
cat exit ifup mkrd pwd umount
cd false kill mh rm unset
cp free losetup mount rmdir usleep
cmp get ls mv set wget
dd help mb mw sh xd

nsh>