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
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;
}
SSL_CTX_load_verify_locations(ctx, cert, NULL)
. The documentation saysspecifies 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?
Any help will be appreciated. Thanks!
For the C client, you may want to ensure that the client is verifying the server certificate by calling OpenSSL's SSL_CTX_set_verify()
function explicitly:
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
before calling BIO_new_ssl_connect()
. Note that this may not be necessary.
And yes, the certificates you set via SSL_CTX_load_verify_locations()
are the ones used for verifying the server certificate (which is part of the ServerHello
). The checking of the server certificate against those verification certificates happens as part of the default OpenSSL verification callback.
Per the Nodejs tls createServer
docs, you might need to provide a couple more options for your TLS server, specially the ca
array and the requestCert
and rejectUnauthorized
booleans:
var options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('public-cert.pem'),
ca: [ fs.readFileSync('ca-cert.pem') ],
requestCert: true,
rejectUnauthorized: true
};
tls.createServer(options, function (socket) {
The requestCert
boolean instructs the server to request the client's certificate. In TLS, the server has to explicitly request a cert from the client; the client does not supply one unless asked by the server. And without setting rejectUnauthorized
to true
, your TLS server would request the cert, but ignore any validation error and allow the connection to proceed, which is not desirable. And the ca
array configures the list of verification certificates (similar to OpenSSL's SSL_CTX_load_verify_locations()
that Nodejs will use for verifying the client certificate).
Ideally, rather than using a self-signed certificate for the server, and a separate self-signed certificate for the client, you would have three certificates: a CA certificate (which is self-signed by definition), a server certificate (which was issued/signed by that CA), and a separate client certificate (also issued/signed by the CA). Since you control both the clients and the server, there is no particular need for you to buy these certificates from a public CA; those are needed for browsers (since the public CA's certificates are in the browsers' trust stores), but that doesn't sound like it's needed for your use case (and thus you can save some money by generating/using your own CA). This site provides example commands for doing just this.
This way, your server would have its certificate (and private key), and the CA cert; your client would have its certificate (and private key), and the CA cert. The CA cert, then, would be the certificate configured in the SSL_CTX_load_verify_locations()
paths/files, and in the ca
option for tls.createServer
.
As a bonus, you might consider adding support TLS session caching, as described here.
Hope this helps!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句