Nodejs, TLS and only allow certain client certificates - node.js

I'm running NodeJS with TLS and have created a server like so:
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
rejectUnauthorized: true,
requestCert: true,
ca: [ fs.readFileSync('clientX-cert.pem') ]
};
const server = tls.createServer(options, (socket) => {
console.log('server connected', socket.authorized ? 'authorized' : 'unauthorized');
socket.on('data', function (data) {
socket.write(data);
});
});
server.listen(5000);
I'm trying to only approve client with a specific client certificate clientX-cert.pem, but it seems to fail as my client is getting an Error: socket hang up at his end.
When not having requestCert it does work, but then everyone is allowed with a TLS certificate.
Have I misunderstood the rejectUnauthorized: true, requestCert: true and ca: options?

Related

websocket connection to 'wss://url_from_aws_domain/socket.io/?EIO=4&transport=websocket' failed?

I have implemented a real time notification using socket.io(https://cdnjs.com/libraries/socket.io) on my local and it is working fine. But when I try to implement it on the live server deployed at AWS domain, the frontend that is establishing socket connection to server got error, websocket is unable to connect on the server throwing error:
websocket connection to
'wss://url_from_aws_server/socket.io/?EIO=4&transport=websocket'
failed?
Front-end Side(notification sender)
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
<script>
var socket = io('https://app.url_from_aws_server.com:4492', { transports: ['websocket', 'polling', 'flashsocket'] });
$(document).on("click",'#confirmSlot',function(){
socket.emit("notify_platform", {
"shop": locationName,
"therapist": therapistName,
"date": therapistDate,
"time": therapistTime,
});
}
</script>
Server Side
const express = require('express');
const app = express();
...
const sslOptions = {
key: fs.readFileSync(path.join(__dirname, '../ssl/key.pem')),
cert: fs.readFileSync(path.join(__dirname, '../ssl/cert.pem')),
requestCert: false,
rejectUnauthorized: false,
};
const https = require('https').createServer(sslOptions, app);
const io = require('socket.io')(https, {
cors: {
origin: 'https://app.url_from_aws_server.com:4492',
methods: ['GET', 'POST'],
},
});
...
https.listen(process.env.SSL_PORT, () => {
console.log(
`HTTPS Server started at ${process.env.SSL_PORT}, Database - ${process.env.MONGODB_URI}`
);
io.on('connection', function(socket){
console.log('Auth value:' + socket.id);
socket.on('notify_platform', function(details){
socket.broadcast.emit('notify_platform', details);
})
})
});

Adding SSL Certificate to Nodejs

I am trying to add an SSL certificate to my Nodejs website.
const fs = require('fs');
const https = require('https');
const options = {
key: fs.readFileSync('./ssl/private.key', 'utf8'),
cert: fs.readFileSync('./ssl/certificate.crt', 'utf8'),
requestCert:true,
rejectUnauthorized: false
};
var server = https.createServer(options, app);
app.listen(process.env.PORT || 443, () => {
console.log('Server is running on 3000!')
})
The app does not throw any error but if I try to connec, I still get the connection is not secure in chrome.
I changed my code to:
https.createServer({
key: fs.readFileSync('./ssl/private.key'),
ca:fs.readFileSync('./ssl/ca_bundle.crt'),
cert: fs.readFileSync('./ssl/certificate.crt')
}, app).listen(443);
and it worked

How can i connect to node server with letsencrypt https activated

I have a problem since i activated letsencrypt on my domain and did'nt have problem with http server before.
Here is my app.js code:
var app = require('express')();
var fs = require('fs');
var https = require('https');
var secureServer = https.createServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert'),
ca: fs.readFileSync('server.cacert'),
requestCert: true,
rejectUnauthorized: false
}, app).listen(5221, function() {
console.log("Secure Express server listening on port "+ 5221);
});
var io = require('socket.io')(secureServer);
The Secure Express server listening on port 5221 prints out but nothing more and the codes in:
io.on('connection', function (socket) {
console.log(`Socket ${socket.id} connected.`);
}
Is not working at all.
I've also tested with .pem files, with ca.crt or without that... but nothing changes.

Client-side websocket certificate in NodeJS

I have a NodeJS websocket client app, using ws https://www.npmjs.com/package/ws - this NodeJS app connects as a client to a websocket server.
I can use HTTPS by specifying wss:// as the protocol.
How can I make the TLS connection use a client certificate for authentication?
i.e. the websocket client should use a certificate to prove its identity to the server.
I found:
it('connects to secure websocket server with client side certificate', function(done) {
const server = https.createServer({
cert: fs.readFileSync('test/fixtures/certificate.pem'),
ca: [fs.readFileSync('test/fixtures/ca1-cert.pem')],
key: fs.readFileSync('test/fixtures/key.pem'),
requestCert: true
});
let success = false;
const wss = new WebSocket.Server({
verifyClient: (info) => {
success = !!info.req.client.authorized;
return true;
},
server
});
wss.on('connection', () => {
assert.ok(success);
server.close(done);
wss.close();
});
server.listen(0, () => {
const ws = new WebSocket(`wss://localhost:${server.address().port}`, {
cert: fs.readFileSync('test/fixtures/agent1-cert.pem'),
key: fs.readFileSync('test/fixtures/agent1-key.pem'),
rejectUnauthorized: false
});
});
});
on https://github.com/websockets/ws/blob/14d9088391ac4495d04e64d76c3b83d4e75f80e2/test/websocket.test.js

a specific case: UNABLE_TO_VERIFY_LEAF_SIGNATURE

I've been trying to do a test about TLS connection between server and client. (SSL-Client Authentication)
I have a self-signed key pair.
If I try to connect my API server using tls.connect(), my connection seems as unauthorized and authorizationError value is UNABLE_TO_VERIFY_LEAF_SIGNATURE as shown the below screenshot.
However, if I try to connect https://api.twitter.com instead of https://hellolarim.club then there is no error and authorization value is true. Also when I trying to Twitter I don't have to use rejectUnauthorized: false parameter.
I added the below server.jscodes too.
Question: I'm wondering that why I cannot connect as authorized: true ?
I have to implement SSL-Client Authentication to my API server.
The attempt to connect to my API server
client.js
var tls = require('tls');
var fs = require('fs');
var options = {
key: fs.readFileSync('client-private-key.pem'),
cert: fs.readFileSync('client-certificate.pem'),
rejectUnauthorized: false,
};
{
var cleartextStream = tls.connect(443, 'www.hellolarim.club', options, function() {
console.log('\nclient connected', cleartextStream.authorized ? 'authorized' : 'unauthorized');
if(!cleartextStream.authorized) {
console.log("authorizationError: " + cleartextStream.authorizationError);
}
process.stdin.resume();
process.stdin.pipe(cleartextStream);
});
cleartextStream.setEncoding('utf8');
cleartextStream.on('data', function(data) {
console.log("\n" + data);
});
cleartextStream.on('end', function() {
server.close();
});
The attempt to connect to Twitter API server
Server.js
var tls = require('tls');
var fs = require('fs');
var options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
requestCert: true,
rejectUnauthorized: true,
ca: [ fs.readFileSync('../client/client-certificate.pem') ]
};
var server = tls.createServer(options, function(cleartextStream) {
console.log(cleartextStream.getPeerCertificate());
console.log('server connected',
cleartextStream.authorized ? 'authorized' : 'unauthorized');
cleartextStream.write("Hello from server to client!\n");
cleartextStream.setEncoding('utf8');
cleartextStream.pipe(cleartextStream);
});
server.listen(443, function() {
console.log('server bound');
});
The problem is on client side.
Client cannot recognize server's certificate despite the certificate had been gotten from a commercial CA because there is no ca parameter on client options!
And if we have a lot of root certificates we can install them by transforming a string array like the below or use node-ssl-root-cas.
var CAcerts = [
// A Root CA cert.
"-----BEGIN CERTIFICATE-----\n" +
"MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE\n" +
"BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\n" +
"tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW\n" +
"sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp\n" +
"7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I\n" +
"LaZRfyHBNVOFBkpdn627G190\n" +
"-----END CERTIFICATE-----\n",
// Another Root CA cert.
"-----BEGIN CERTIFICATE-----\n" +
"MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE\n" +
"BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\n" +
"tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW\n" +
"sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp\n" +
"7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I\n" +
"LaZRfyHBNVOFBkpdn627G190\n" +
"-----END CERTIFICATE-----\n"
];
var options = {
key: fs.readFileSync('client-private-key.pem'),
cert: fs.readFileSync('client-certificate.pem'),
ca: CAcerts,
requestCert: true,
rejectUnauthorized: true,
};

Resources