How get client certification info when using Hapi? - node.js

I am using the Hapi framawork in my node.js project and I'd like to get the client certificate info.
I have searched the internet looking for this info but with no luck so far.
Either I am doing a bad search or there's not an easy way to do it.
Anyways I believe that must be a way to do so.
Does anyone know how to get cert's subject, fingerprint, and etc. while using Hapi?
const tls = {
key: fs.readFileSync('../certs/xyz.key'),
cert: fs.readFileSync('../certs/xyz.crt'),
passphrase: 'xxxxxxxxxx',
ca: fs.readFileSync('../certs/rootCA.crt'),
// should request the client cert
requestCert: true,
rejectUnauthorized: true
};
console.log(req.socket.getPeerCertificate()); /* doesn't work */

Related

Node httpAgent with proxy and certificates (https-proxy-agent with TLS)

So I'm trying to make a call inside my node test (AVA) that uses proxy and TLS authorization.
I'm using:
typescript: 3.9.3
ts-node: 8.10.2
axios: 0.21.1
https-proxy-agent: 5.0.0
What I've learnt so far:
AxiosProxyConfig is broken at the moment so I cannot use it:
Axios proxy is not working,
https-proxy-agent is indeed working as it was said by kraiz in bug thread, but... I cannot see anything about ca, cert and key I cannot provide those I was not able to find any docs except this one https-proxy-agent npm page.
So just to wrap up with some code, that's what I'm trying to do and I have no idea how to achieve that:
const httpsProxyAgent = new HttpsProxyAgent({
cert: this.cert,
key: this.key,
ca: this.ca,
host: PROXY_HOST,
port: PROXY_PORT,
});
// then later
const config: AxiosRequestConfig = {
httpsAgent: httpsProxyAgent,
headers: { ... }
proxy: false
};
Though HttpsProxyAgent seems to extend Agent those options (certs part) are not used and I get UNABLE_TO_VERIFY_LEAF_SIGNATURE error that indicates that ca is ignored.
Does anyone knows how to provide those certs to this agent?
I couldn't find any answers. I'm not a node expert so I might have missed something obvious.
Thanks in advance!
PS. I've also tried Objects.assign() like this
// this proxy agent is working for sure (tested)
const httpsProxyAgent = new HttpsProxyAgent('http://proxy:1234');
// trying to assign certs after creating httpsProxyAgent
Object.assign(httpsAgent.options, {
ca: this.ca,
key: this.key,
cert: this.cert
});
// then again passing it to AxiosRequestConfig.httpAgent and making a call
result was once again UNABLE_TO_VERIFY_LEAF_SIGNATURE.
PSS. I've seen this better-https-proxy-agent (git page) that seems to have solution, the only drawback is I cannot see any TS support.

How to log SSL handshake in node's https module

I have a server written in node which implements a secure two-way SSL web-server:
var https = require('https');
var express = require('express');
var app = express();
var options {
key: ...,
cert: ...,
ca: ...,
requestCert: true,
rejectUnauthorized: true
};
https.createServer(options, app).listen(port, host);
But for some unknown reason, the client fails to connect. So it would be great if I could get any logs on why the connection has failed.
So far, all the logs I can get come from app which is an express object. But the problem is that when a connection is rejected due to a certificate issues, it does not reach express so I get no error logs. How can I get logs from https server?
I've run into this problem as well and while I couldn't come up with a solution that logs all the errors within the https module, I was able to get it to log debug information by using:
NODE_DEBUG='tls,https' node server.js
This isn't ideal as it doesn't give you the exact error (eg: Bad SSL Handshake) and the related traceback, it does give you information like TLS: onhandshakestart which lets you figure out if there was an error if you can't find a corresponding TLS: onhandshakeend in the logs.
There is an option in the config for createServer called enableTrace that causes Node to print a ton of details about the handshake:
var options {
key: ...,
cert: ...,
ca: ...,
requestCert: true,
rejectUnauthorized: true,
enableTrace: true // Set this :)
};
See the docs for more info.

TLS connectivity in NodeJS using certificate and key from Certificate store

I have implemented TLS connectivity through MQTT as shown below.
mqttOptions = {
clientId: '100',
key: fs.readFileSync('test/certs/client.key'),
cert: fs.readFileSync('test/certs/client.crt'),
ca: fs.readFileSync('test/certs/ca.crt'),
secureProtocol: 'TLSv1_method',
rejectUnauthorized: false,
protocolId: 'MQIsdp',
protocolVersion: 3,
passphrase: 'edgenode',
keepAlive: 1000,
clean: false,
reconnectPeriod: '1000',
will: willMessage
};
var client = mqtt.connect(tls://localhost:8883, mqttOptions);
Here I'm passing in the client key, certificate and the CA certificate. Instead I need to connect using information from Windows certificate store. Assuming I have installed the client certificate in Windows Certificate Store, how can I read the private key from it using nodeJS and establish connectivity? Please advice.
Access to the Windows Keystore is via the MSCAPI.
I can't see any NodeJS wrappers for this API on npm but even if there were you would have to modify the mqtt library to work with it as it won't actually give you access to the private client keys, but instead you pass in data to be signed/encrypted using that key and it gives you back the signed/encrypted data like a hardware crypto device.
If you really need to use the Windows keystore I would suggest porting the client app to something like C, C# or Java as there are MSCAPI libraries for these that present the keys/certs using the language standard APIs

Self signed cert NodeJS rejectUnauthorized

I created a structure certificates to authenticate client-> server, allowing only certificates recognized by the CA using this step by step: https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html
I checked the authority with openssl, and it returns to me OK the certificate server and client, with the same CA. But by setting the parameter rejectUnauthorized to true on the server, the client can not connect.
Is there any extra parameter should I set up to allow authentication by a certificate that I generated?
---- Edit
On the client side I get the following error: ""ECONNRESET" socket hang up"
I spent a long time digging into a similar issue, and I wrote up this to talk about how to dig into various OpenSSL issues with node.js: http://www.thedreaming.org/2016/09/27/nodejs-ssl/
The short answer, though, is if you need to pass the ca parameter when creating you client connection. If you have the self-signed certificate stored in cert.pem, then the client code looks something like:
var https = require('https');
var fs = require('fs');
var certificate = fs.readFileSync('cert.pem');
var options = {
host: serverHost,
port: 443,
path: '/',
ca: [certificate]
};
https.request(options, function(res) {
res.pipe(process.stdout);
}).end();

TLS what exactly does 'rejectUnauthorized' mean for me?

So, I was having an issue earlier today where my client, written in node, was barfing because the server I was connecting to used self signed certs. So, I went and added the option rejectUnauthorized: false to my tls.connect command like any unwitting developer would do.
My question is now, what the hell does this mean for me? Is my TLS connection just a vanilla TCP connection that can also possibly be a TLS connection? Is writing this as a TLS stream totally useless?
More importantly, that server, you know the one with the self-signed certs? Is my stream between here and there actually encrypted?
As described in the documentation:
rejectUnauthorized: If true, the server certificate is verified against the list of supplied CAs. An error event is emitted if verification fails; err.code contains the OpenSSL error code. Default: true.
Since you're using self-signed certificates, obviously there won't be a match with the built-in CAs, so by default the connection would be rejected because it cannot verify the server is who they say they are.
By setting rejectUnauthorized: false, you're saying "I don't care if I can't verify the server's identity." Obviously this is not a good solution as it leaves you vulnerable to MITM attacks.
A better solution for self-signed certificates is to set the appropriate ca value to your custom CA when connecting client-side. Also, make sure your host value matches that of the Common Name of the server's self-signed certificate. For example:
var socket = tls.connect({
host: 'MyTLSServer',
port: 1337,
ca: [ fs.readFileSync('CA.pem') ],
}, function() {
// Connected!
});
// ...
No matter if you use rejectUnauthorized: false or set ca, the connection is encrypted.

Resources