Goal: The client should send data to trusted server (through self-signed certificates) and the server the same.
I’m running a Node.js TLS server and have many embedded clients which run openSSL TLS client in C. I have the entire setup working and I can see the data is encrypted (through Wireshark) but I’m not convinced I’m doing it the right way (especially the way I'm handling certificates).
What I have so far
- On the Server, I generated a 2048 private key (private-key.pem) and a self-signed certificate (public-cert.pem)
- Copied over the self-signed certificate (public-cert.pem) to the client
Node.js server code snippet
var tls = require('tls');
var fs = require('fs');
var options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('public-cert.pem')
};
tls.createServer(options, function (socket) {
socket.on('data', function(data) {
// do something
});
socket.on('close', function() {
socket.destroy();
});
}).listen(PORT);
C Client code snippet
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
// create new context object
ctx = SSL_CTX_new(TLSv1_2_client_method());
//load trust cert
if(! SSL_CTX_load_verify_locations(ctx, "public-cert.pem", NULL)){
printf("sslInitialize() Error: Cannot load certificate\n");
ERR_print_errors_fp(stderr);
if(ctx != NULL) {
SSL_CTX_free(ctx);
}
return;
}
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, & ssl);
if (ssl == NULL) {
printf("sslInitialize() Error: Can't locate SSL pointer\n");
ERR_print_errors_fp(stderr);
if(ctx != NULL){
SSL_CTX_free(ctx);
}
if(bio != NULL){
BIO_free_all(bio);
}
return;
}
BIO_set_conn_hostname(bio, HOST);
int connectStatus;
if((connectStatus = BIO_do_connect(bio)) <= 0) {
printf("Connect Status: %d",connectStatus);
printf("sslInitialize() Error: Cannot connect to server\n");
ERR_print_errors_fp(stderr);
sslCloseConnection();
return;
}
Observations
- I changed the certificate on the client to same random certificate and it still works (the certificate the server sent during ServerHello TLS handhake and the client loaded using SSL_CTX_load_verify_locations() were different). The makes me wonder as to how the client is trusting the certificate. How can I sort this out?
- As of now I've setup it up in such a way that the client verifies the server (although it isn't working) and sends data and the server blindly accepts it. How can I make the client send a certificate (self-signed by client) and the server only accepts it if it has that particular certificate on file.
- On the client-end I use
SSL_CTX_load_verify_locations(ctx, cert, NULL)
. The documentation says
specifies the locations for ctx, at which CA certificates for verification purposes are located. The certificates available via CAfile and CApath are trusted.
Does this mean the client checks this against the certificate received in ServerHello
message of the TLS handshake? If so, is there another function I should call to do this check?
- As always, I've gone through a lot of resources online (SO posts and openSSL man page) before asking this question. Node.js_TLS,openSSL,SO_1, SO_2 to name a few. I've also omitted header files and other boiler-plate code.
Any help will be appreciated. Thanks!