Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it Possible to Dynamically Return an SSL Certificate in NodeJS?

I want to dynamically return an ssl certificate info in my NodeJS application. I have two domain names linked to the same node application. I only see that the ssl settings can be specified when the server is created. Is it possible to dynamically return ssl certificates based on the requested url?

Otherwise, if I must instead create a second sever instance on another port, will I be able to transparently pipe each request to the original port? Can I make it appear like it's not running on a second port?

Thanks, Jeff

like image 432
philmaker Avatar asked Aug 31 '12 17:08

philmaker


People also ask

What are dynamic certificates?

Dynamic routing certificate. The certificate that is presented by the plug-in to the controller when the plug-in tries to connect to the dynamic routing service on a collective controller.

Does SSL take time to propagate?

The SSL kicks in immediately when installed. Let's encrypt SSL installations need a few minutes. The Premium SSL certificates are installed within a few hours in most cases.

Can SSL be forged?

Our results indicate that 0.2% of the SSL connections analyzed were tampered with forged SSL certificates, most of them related to antivirus software and corporate-scale content filters. We have also identified some SSL connections intercepted by malware.


2 Answers

Yes, it is possible to do it with one server. But the caveat is that it works on clients that support SNI - which is most modern browsers.

This is how you do it:

//function to pick out the key + certs dynamically based on the domain name function getSecureContext (domain) {     return crypto.createCredentials({         key:  fs.readFileSync('/path/to/domain.key'),         cert: fs.readFileSync('/path/to/domain.crt'),         ca: [fs.readFileSync('/path/to/CA_cert_1.crt'), fs.readFileSync('/path/to/CA_cert_2.crt'), <include all CA certs that you have to> ... ]       }).context; }  //read them into memory var secureContext = {     'domain1': getSecureContext('domain1'),     'domain2': getSecureContext('domain2'),     .     . }  //provide a SNICallback when you create the options for the https server var options = {     SNICallback: function (domain) {         return secureContext[domain];     }, //SNICallback is passed the domain name, see NodeJS docs on TLS     cert: fs.readFileSync('/path/to/server.crt'),     key: fs.readFileSync('/path/to/server.key'),                     } }  //create your https server var server = require('https').createServer(options, [requestListener]); //using Express var server = require('https').createServer(options, require('express')()); server.listen(<someport>); 

This works because the options for https is similar to tls.createServer(). Make sure you include all required CA intermediate and root certificates in the crypto.createCredentials call. Also if you have a CA bundle, split them up into multiple single crt files before using them as 'ca' accepts an array of certificates.

like image 53
clusterfork Avatar answered Sep 26 '22 10:09

clusterfork


crypto.createCredentials() is deprecated, so use tls.createSecureContext() instead.

tls.createServer() must have key and cert in the options, because they are required in the manual. Perhaps tls.createServer() uses these parameters as defaults in case SNICallback is not supported.

var secureContext = {     'mydomain.com': tls.createSecureContext({         key: fs.readFileSync('../path_to_key1.pem', 'utf8'),         cert: fs.readFileSync('../path_to_cert1.crt', 'utf8'),         ca: fs.readFileSync('../path_to_certificate_authority_bundle.ca-bundle1', 'utf8'), // this ca property is optional     }),     'myotherdomain.com': tls.createSecureContext({         key: fs.readFileSync('../path_to_key2.pem', 'utf8'),         cert: fs.readFileSync('../path_to_cert2.crt', 'utf8'),         ca: fs.readFileSync('../path_to_certificate_authority_bundle.ca-bundle2', 'utf8'), // this ca property is optional     }), } try {     var 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'),      }     https.createServer(options, function (req, res) {         res.end('Your dynamic SSL server worked!')         // Here you can put proxy server routing here to send the request          // to the application of your choosing, running on another port.         // node-http-proxy is a great npm package for this     }).listen(443); } catch (err){     console.error(err.message);     console.error(err.stack); } 

Inside the server you can use nodejs package http-proxy to route your https request to your various applications.

like image 39
steampowered Avatar answered Sep 23 '22 10:09

steampowered