node.js: HTTPS client certificate without server validation? - node.js

I have a https server and client in node.js.
For 'normal' HTTPS a host lets in any client, and the client authenticates the host.
However in my situation I would like to do the opposite:
I want the host to authenticate the client, but the client to connect to any host without authenticating it. ie: The host does not get a key/crt (but does trust the CA), while the client does gets a key/crt (and also trusts the CA).
The standard way for https with both sides authenticating each other is:
Server options:
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-crt.pem'),
ca: fs.readFileSync('ca-crt.pem'),
requestCert: true,
rejectUnauthorized: true
Client options:
key: fs.readFileSync('client-key.pem'),
cert: fs.readFileSync('client-crt.pem'),
ca: fs.readFileSync('ca-crt.pem') };
I removed key and crt from server, but how to tell the client not to request server/host cert? I can't seem to figure that part out? The documentation claims that for a client rejectUnauthorized must be set to true for the client to validate the server, so I set it to false. But the TLS handshake seems to be failing.

Related

How to authenticate user with CAC in Node/Express

I need to allow users to log into my react website using their DoD issued Common Access Card. I am using an express api as an authentication server. I've got the server configured to require a client cert:
const options = {
key: fs.readFileSync(config.ssl.keyPath),
cert: fs.readFileSync(config.ssl.certPath),
ca: [fs.readFileSync(config.ssl.caPath)],
requestCert: true,
rejectUnauthorized: false,
};
https.createServer(options, expressApp).listen(port);
How do I get my react app to request/load/read the certificate from the CAC?
You will need to create a .PFX cert and import it into the browser's certificate store. The certificate generated should be signed by the CA used to start your express server. The certificate imported into your browser should also be enabled for "Client Authentication".

NodeJS forwarding client SSL certificates

I am working on Node.js server application which is SSL enabled and accepts client certificates. I am using following code to create https server.
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
ca: fs.readFileSync('ca.pem'),
requestCert: true,
rejectUnauthorized: true
};
https.createServer(options,app).listen(8090, function(){
console.log("Listening on 8090");
});
Other Node.js based client apps are able to connect using their SSL certficate and get the service response.
However from my sever, I want to make another server call and wish to pass on the same client certificate I received. I simply want to forward the same ceritifcate, I understand I can get the certificate details in request object, but how to retrieve the crt and key from that object?
I am looking to do something like below:
app.get('/myservice', (req,res) => {
//req.socket.getPeerCertificate(true);
var agent = new https.Agent({
cert: somelibrary(req.socket.getPeerCertificate(true).??????),
key: somelibrary(req.socket.getPeerCertificate(true).??????),
});
fetch('http://AnotherServiceURL', { method: 'GET' agent}).then(function(response){
res.json(response);
});
});
Is there any library which can convert request certificate details in a way so as to forward those as key and cert? Or is there any other/better way of doing this?
I understand I can get the certificate details in request object, but how to retrieve the crt and key from that object?
While it would be possible to pass the client certificate itself it is impossible to use it again as client certificate in another TLS connection to the final target. For this you would need to have access to the private key of the client, which as the name says is private to the client. As for getting the client certificate (i.e. the public part) see Node.js: access the client certificate.

SSL chain of trust with browser-sync?

I'm trying to set up a gulp HTTPS server. My server's certificate is signed by my company's CA. In order for it to be validated by a browser, the CA's certificate itself also needs to be specified, so that the client browser can validate the chain of trust.
Node's HTTPS object has an option "ca" for listing trusted certificates to establish the chain of trust. Is there a way to specify ca certs in browser-sync? Optimally, I'd be looking for something like the snippet below, but I'd take a workaround, if there are any.
browserSync.instance = browserSync.init({
server: {
baseDir: "app",
index: "index.htm"
},
https: {
cert: './certs/serverCert.pem,
key: './certs/serverKey.pem',
ca: ['./certs/mycompany-ca.cer', './certs/mycompany-root-ca.cer']
}
});

Validate certificates NodeJS

Is there any way to validate certificates against a CA, similar to the command "openssl verify -CAfile"?
I need to do this to bypass the HTTPS check Node JS with rejectUnauthorized: true, because with selfsigned certificates already realized that it is virtually impossible to authenticate the client with SSL.

Socket.IO TLS requiring key/cert

I have a CA from an authorized server. I have set up my HTTPS and WebSocket setup as follows:
var httpsOptions = {
cert: fs.readFileSync(config.ssl.server_cert),
key: fs.readFileSync(config.ssl.server_key),
requestCert: true,
rejectUnauthorized: true,
passphrase: config.ssl.server_password
};
httpsServer.listen(config.https_port, function () {
console.info("HTTPS server running on %d", config.https_port);
});
io = io.listen(server);
io.sockets.on('connection', function (socket) {
console.log("connected: " + socket.id);
})
Now, my clients will have to sign up for an account. When they do, I want to create a private/public key for them, and sign it with the CA that I have. They then have to use them for any web socket connection. If these are not provided, I don't want to even allow a connection.
My client at the moment is then:
io.connect(url, {secure: true, 'force new connection': true});
But I cannot figure out how to A) pass the key to the server, and B) If this is even possible?
If you're talking about browsers, then the client certificate and private key has to be installed in the browser or OS certificate store (depending on which browser is being used). Once installed, the browser will automatically send the certificate.
Unfortunately, client certificate installation is not a user-friendly process.
If your client is a node process, a client cert option was (finally) added in socket.io 1.3.
Don't forget to validate that the presented certificate matches a user account in your system. rejectUnauthorized only validates that the client presented a certificate issued by any trusted CA.
Do you mean you have a SSL certificate for your server? You can't sign new certificates with that. No trusted root CA gives out certs that allow third parties to sign certs without a very long process and lots of money.
You can run your own CA that signs client certificates. You have to configure your server to trust your client certificate-issuing CA (via the ca option in createServer) since it will be untrusted by default.

Resources