DEV Community

Dimitrios Desyllas
Dimitrios Desyllas

Posted on

why I cannot get the domain names out of a certificate in nodejs?

As I ask in stackoverflow I try to mane a multi-certificate https server.

const fs = require('fs');
  const { exit } = require('process');

  let https;
  try {
    https = require('node:https');
  } catch (err) {
    console.log('https support is disabled!');
  }

  const cert_dir = '/etc/myapp/certs';
  const secureContext = {}

  fs.stat(cert_dir,(err,cb) => {
    if(err){
        console.log(err);
        exit(-1);
    }

    fs.readdir(cert_dir,(err, files) => {
        if (err){
            console.log(err);
        } else {
            files.filter(item => {
                return path.extname(item)=='.cert'
            }).forEach(file => {
                console.log(file);
                const cert = path.join(cert_dir,file);
                const key = path.join(cert_dir,(path.basename(file,".cert")+".key"))

                fs.stat(key, (err, stat) => {
                    if(err == null){
                        const x509 = new X509Certificate(fs.readFileSync(cert));
                        console.log("cert Info",x509);

                        // get domain here
                    }
                });
            });
        }
    });

  });

  const options = {
    SNICallback: function (domain, cb) {
        if (secureContext[domain]) {
            if (cb) {
                cb(null, secureContext[domain]);
            } else {
                // compatibility for older versions of node
                return secureContext[domain]; 
            }
        } else {
            throw new Error('No keys/certificates for domain requested');
        }
    },
    // must list a default key and cert because required by tls.createServer()
    key: fs.readFileSync('../path_to_key.pem'), 
    cert: fs.readFileSync('../path_to_cert.crt'), 
  };

  const server = https.createServer(options,handle);
  server.listen(449);
Enter fullscreen mode Exit fullscreen mode

But I cannot find a way to match a certificate by its domain. DO you know how I can find the domain out of random certificate?

I mean in Java I am able to do so:
https://stackoverflow.com/a/14020952/4706711

But why not in nodejs (despite being different and complete opposite)

Top comments (5)

Collapse
 
akeimsuth profile image
akeimsuth

You can use the tls module. This module provides an API for implementing secure networking in Node.js. Here is an example of how you can use the tls module to find the domain of a certificate:
`const tls = require('tls');

const certificate = // your certificate

const domain = tls.getServerIdentity(certificate).name;
`
The tls.getServerIdentity() function is used to get the server identity of the certificate, which includes the domain. The name property of the returned object contains the domain.

Collapse
 
pcmagas profile image
Dimitrios Desyllas

I also wonder if can I open a TLS socket and on top of that use the Http module?
On other words I want to manually provide my own socket instead of letting the http module to handle it.

Collapse
 
pcmagas profile image
Dimitrios Desyllas

I tried that:

const fs = require('fs');
const { exit } = require('process');
const tls = require('tls');
const path = require('path');

  let https;
  try {
    https = require('node:https');
  } catch (err) {
    console.log('https support is disabled!');
    exit(-1)
  }

  const cert_dir = '/etc/http_manipulator/ssl/usr';
  const secureContext = {}

  fs.readdir(cert_dir,(err, files) => {
    if (err){
        console.log(err);
    } else {
        files.filter(item => {
            return path.extname(item)=='.cert'
        }).forEach(file => {
            console.log(file);
            const cert = path.join(cert_dir,file);
            const key = path.join(cert_dir,(path.basename(file,".cert")+".key"))

            fs.stat(key, (err, stat) => {
                if(err == null){
                  const domain = tls.getServerIdentity(cert).name;
                  console.log("DOMAIN "+domain);
                }
            });
        });
    }
});

  const options = {
    SNICallback: function (domain, cb) {
        if (secureContext[domain]) {
            if (cb) {
                cb(null, secureContext[domain]);
            } else {
                // compatibility for older versions of node
                return secureContext[domain]; 
            }
        } else {
            throw new Error('No keys/certificates for domain requested');
        }
    },
    // must list a default key and cert because required by tls.createServer()
    key: fs.readFileSync( path.join(cert_dir,'/../default.key')), 
    cert: fs.readFileSync(path.join(cert_dir,'/../default.cert')), 
  };

  const handle = (req,res)=>{
    res.writeHead(200);
    res.end("hello world\n");
  };

  const server = https.createServer(options,handle);
  server.listen(449);
Enter fullscreen mode Exit fullscreen mode

Could not make it work:

/home/node/app/src/so.js:30
                  const domain = tls.getServerIdentity(cert).name;
                                     ^

TypeError: tls.getServerIdentity is not a function
    at /home/node/app/src/so.js:30:38
    at FSReqCallback.oncomplete (node:fs:208:5)

Enter fullscreen mode Exit fullscreen mode
Collapse
 
akeimsuth profile image
akeimsuth

Yes, it is possible to open a TLS socket and use the HTTP module on top of it. The HTTP module provides an interface for sending and receiving HTTP requests and responses over the network. It can be used with any type of socket, including TLS sockets.
// import the TLS and Http modules
const tls = require('tls');
const http = require('http');

// create the TLS socket
const socket = tls.connect({
port: 443,
host: 'example.com'
});

// use the socket to create an HTTP request
const request = http.request({
socket: socket,
method: 'GET',
path: '/',
});

// send the request
request.end();

Thread Thread
 
pcmagas profile image
Dimitrios Desyllas

I was looking the other way around using a Server tls socket and use that to listen for Http. That will aid me to capture raw http requests that server receives.