I'm trying to use the HiRedis API to perform a TLS connection to a Redis server fronted by a device that can perform TLS termination. My project has a need to send customer data over the internet to a Redis server hosted in the Cloud. I need to secure the data using TLS.
I see that HiRedis offers some limited support for TLS connections. I've created a prototype to try out the TLS code.
I have a server machine residing in AWS eu-west-1. I have confirmed by various means that I can insert records using the HiRedis 0.14.0 on port 6379.
I have an AWS Network Load Balancer in eu-west-1. I have port 443 with a private certificate going to a target group to port 6379 of the Redis server. I also have port 6379 open going to port 6379 to the Redis server. I have confirmed that the latter connection does work using the hiredis "example" compiled program.
I have an AWS cloud instance in us-east-1 to function as my client machine. I have installed hiredis 0.14.0 and compiled the examples with the OpenSSL libraries. I have installed/copied the private certificate and private key onto this machine. As mentioned above, I can use the "example" program on port 6379 and create sample data on the Redis server.
However, when attempting the TLS connection, I get the following:
[machine]# example-ssl <to-redis-host> 443 <cert_file> <private_key_file>
ST(0x10). before/connect initialization. R(0x1)U
ST(0x1001). before/connect initialization. R(0x1)U
ST(0x1001). SSLv2/v3 write client hello A. R(0x1)U
ST(0x1001). SSLv3 read server hello A. R(0x1)U
ST(0x4008). error. R(0x230)F
ST(0x1002). error. R(0xffffffff)U
ST(0x1002). error. R(0xffffffff)U
Couldn't initialize SSL!
Error: SSL_connect() failed
example-ssl file can be found here: https://github.com/redis/hiredis/blob/master/examples/example-ssl.c
My version of HiRedis has sslio.c, but it appears to be renamed ssl.c in the master branch: https://github.com/redis/hiredis/blob/master/ssl.c
How do I get this work?
As I was typing, I had the thought that I'm supposed to use the client certificate and private key (don't use server cert and key). I tried the instructions in https://gist.github.com/mtigas/952344 to generate the client cert and key, but I still cannot get the example-ssl to work.
So the problem was that the certificate verification failed.
if (c->err == 0) {
char err[512];
if (rv == SSL_ERROR_SYSCALL)
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",strerror(errno));
else {
unsigned long e = ERR_peek_last_error();
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",
ERR_reason_error_string(e));
}
__redisSetError(c, REDIS_ERR_IO, err);
}
return REDIS_ERR;
I incorporated the code into my program and then got the following useful error message:
ST(0x10). before/connect initialization. R(0x1)U
ST(0x1001). before/connect initialization. R(0x1)U
ST(0x1001). SSLv2/v3 write client hello A. R(0x1)U
ST(0x1001). SSLv3 read server hello A. R(0x1)U
ST(0x4008). error. R(0x230)F
ST(0x1002). error. R(0xffffffff)U
ST(0x1002). error. R(0xffffffff)U
Couldn't initialize SSL!
Error: SSL_connect() failed: certificate verify failed <-------------
I then followed the instructions on the following page to verify my self-signed certificate and installation: import self signed certificate in redhat. Turns out the certificate I had installed on my hiRedis client machine did not match the certificate loaded on my AWS NLB. This is a result of internal communication errors.
After updating the ca-trust, I modified the example-ssl.c file to the following:
const char *cert = NULL;
const char *key = NULL;
const char *ca = NULL;
ca = "/etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt";
For whatever reason, the "default" CA trust is either incorrect or not loaded. I specified the CA path which found the self-signed certificate. I changed the sslio.c code to re-insert the VERIFY_PEER functionality. Now the example-ssl is working correctly.
Just a note: The AWS Network Load Balancer (NLB) doesn't need client certificate verification. Therefore, I could set the and to be null. However, if you are using hiRedis (or any other Redis API for that matter) to connect to Redis Enterprise Cloud labs, they do require client-AUTH per their documentation.