Closed Andrewiski closed 2 years ago
editing /lib.client.js and calling getPeerCertificate() on creating allows it to be used later.
function Client(server, conn){ this.server = server; this.conn = conn; this.encoder = server.encoder; this.decoder = new server.parser.Decoder(); this.id = conn.id; this.request = conn.request; this.cert = conn.request.client.getPeerCertificate(); this.setup(); this.sockets = {}; this.nsps = {}; this.connectBuffer = []; }
socket.client.cert is populated when accessed in io.on('connection', function(socket){ if( socket.client.cert){ console.log("this works " + socket.client.cert.subject.CN); } }
I could indeed reproduce the issue you're describing, sorry for the delay. I think one should be able to fetch the certificate at the Engine.IO level:
io.engine.on("connection", (rawSocket) => {
rawSocket.peerCertificate = rawSocket.request.client.getPeerCertificate();
});
io.on("connection", (socket) => {
console.log(socket.conn.peerCertificate);
});
Not sure about the impact of adding it in the library directly though. What do you think?
I have my pull request changes running on a production server for the past year, I only have about 50 clients devices connected to a single management server but I don't seem to have any ill effect. This functionality was there in an older version it wasn't clear as to why it got dropped and if it was a socket.io or a node.js change that dropped it. If I remember it had more to do with node.js version upgrade dropping some of the underlaying request object properties after connection to save memory or something.
I've added an example in the documentation: https://socket.io/docs/v4/server-initialization/#with-an-https-server
Please reopen if needed.
did this PR make it into the latest version I upgraded to latest 2 months ago and it wasn't there, I did create an example as well using openssl and a way to create client certs with CA so more complicated in code example wise but shows how you can use client Auth but got pulled off on another project so never got to testing it like I wanted. I will try to work on it when I get home next week. https://github.com/Andrewiski/socket.io-chat-client-certificate this is not yet complete .
This https://github.com/Andrewiski/socket.io is my version of latest Sockte.IO with getPeerCertificate fix, but I had to namespace it as with Type Script I have to do a build to "compile/convert" Typescript to Javascript which then must be deployed to npm so not as simple as it was with straight JavaScript.
Anyways the fix is the same.
if ( conn && conn.request && conn.request.client && conn.request.client.getPeerCertificate ) { this.peerCertificate = conn.request.client.getPeerCertificate(); } else { this.peerCertificate = null; }
https://socket.io/docs/v4/server-initialization/#with-an-https-server In this example I would suggest you actually do something with the client certs IE see see which client connected using the cert subject.
let cert = socket.client.peerCertificate
if (cert.subject) {
debug(`Client Certificate ${cert.subject.CN}, certificate was issued by ${cert.issuer.CN}, serial ${cert.serialNumber}, fingerprint ${fingerprint256} !`);
}
Please try this simple example
https://github.com/Andrewiski/socket.io-certificate-test
toggle between my library and current socket.io in server.js
const socketio = require('@andrewiski/socket.io');
const socketio = require('socket.io');
Note how using my pull request @Andrewiski/socket.io you can determine who is connected via socket by using the client cert.
Note how using your example (https://socket.io/docs/v4/server-initialization/#with-an-https-server) does not work as no client certificate can be used as it is always null.
// This always returns null socket.request.client.getPeerCertificate()
if(socket.request.client.getPeerCertificate) {
let cert = socket.request.client.getPeerCertificate();
if (cert){
debug("io.onConnection", socket.id, "socket.request.client.getPeerCertificate() client certificate was presented use,", cert.subject.CN, " issued by ", cert.issuer.CN );
}else{
debug("io.onConnection", socket.id, "socket.request.client.getPeerCertificate() is null");
}
}
//This only successfull if running @Andrewiski/socket.io
if(socket.client.peerCertificate) {
let cert = socket.client.peerCertificate;
if (cert){
debug("io.onConnection", socket.id, "Andrewiski socket.client.peerCertificate certificate was presented use,", cert.subject.CN, " issued by ", cert.issuer.CN );
}else{
debug("io.onConnection", socket.id, "no client.peerCertificate certificate");
}
}
If client certificates are enabled on the server there is no way to get to the underlying clientCertificate as socket.client.request.client.getPeerCertificate() always returns null.
This happens even if the the client certificate is valid and authorized.
socket.client.request.client.authorized = true
I belive this is the result of a change in node tls functionality.
https://github.com/nodejs/node/commit/eff8c3e02417652b78436eaa10d049e8c60e5275
`
var httpsOptions = { key: fs.readFileSync(path.join(dirname, 'serverkey.pem')), cert: fs.readFileSync(path.join(dirname, 'servercert.pem')), requestCert: true, rejectUnauthorized:false }; https_srv = https.createServer(httpsOptions, app).listen(objOptions.httpsport, function () { //console.log('Express server listening on port ' + port); writeToLog("info",'Express server listening on https port ' + objOptions.httpsport); }); io.attach(https_srv);
io.on('connection', function (socket) { let cert = socket.client.request.client.getPeerCertificate(); if (cert) { console.log(cert.subject.CN); }else{ console.log("cert is null"); } } `