101

I'm using the Express framework in Node.js to create a web server. I want to use ssl for the web server's connection.

The code to create the https web server is as below.

var app = express.createServer({
  key: fs.readFileSync('./conf/key.pem'),
  cert: fs.readFileSync('./conf/cert.pem')
});
module.exports = app;

Question: How to create the key.pem and cert.pem required by express?

whiterook6
  • 3,270
  • 3
  • 34
  • 77
Jeffrey
  • 4,436
  • 9
  • 38
  • 54

3 Answers3

219

The two files you need are a PEM encoded SSL certificate and private key. PEM encoded certs and keys are Base64 encoded text with start/end delimiters that look like -----BEGIN RSA PRIVATE KEY----- or similar.

To create an SSL certificate you first need to generate a private key and a certificate signing request, or CSR (which also contains your public key).You can do this in a variety of ways, but here's how in OpenSSL.

openssl req -newkey rsa:2048 -new -nodes -keyout key.pem -out csr.pem

This will cause you to enter an interactive prompt to generate a 2048-bit RSA private key and a CSR that has all the information you choose to enter at the prompts. (Common Name is a legacy location where domain names used to go, but modern browsers require an extension called SubjectAlternativeName now. However, when submitting to a CA they will put CN values in SAN) Once you've done this you would normally submit this CSR to a trusted certificate authority and once they've validated your request you would receive a certificate.

If you don't care about your certificate being trusted (usually the case for development purposes) you can just create a self-signed certificate. To do this, we can use almost the same line, but we'll pass some extra parameters. The interactive prompt doesn't support Subject Alternative Name (SAN), which is required in most modern clients, so we pass it on the CLI via the -addext flag. You'll need to change mydnsname.com to the right name for your uses. Be sure to keep DNS: though!

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem -addext "subjectAltName = DNS:mydnsname.com"

This will give you a cert (valid for 10 years) and key pair that you can use in the code snippet you posted.

Paul Kehrer
  • 13,466
  • 4
  • 40
  • 57
  • 3
    what about for client certificate and key? – nkint Jul 08 '14 at 22:08
  • 1
    This post is complete, run both of the two commands he pasted to win the keys+cert. The client doesn't establish trust, only the server. – Ninjaxor Aug 01 '15 at 23:58
  • @paul Can you please tell me where are these .pem key and cert generated to? I mean which directory? I am using Ubuntu 14 – StormTrooper Oct 19 '15 at 06:03
  • 2
    They'll write to the current working directory of your shell. – Paul Kehrer Oct 20 '15 at 03:07
  • 2
    Note that the self-signed certificate generated this way is version 1, containing CN, but no SAN. "Since version 58, Chrome requires SSL certificates to use SAN (Subject Alternative Name) instead of the popular Common Name (CN), thus CN support has been removed." [Fixing Chrome 58+ [missing_subjectAltName] with openssl when using self signed certificates](https://alexanderzeitler.com/articles/Fixing-Chrome-missing_subjectAltName-selfsigned-cert-openssl/) – Zhiyong Jun 30 '17 at 06:46
  • How do i do this in Windows – Sanchit Jain May 20 '20 at 04:56
  • No cert file is generated for me. Any ideas? Ran both commands. – Oliver Dixon Nov 02 '21 at 15:42
  • Where do thse files go on linux – Lutaaya Huzaifah Idris Jan 01 '23 at 12:23
13

Just follow this procedure :

  1. create the folder where you want to store your key & certificate :

    mkdir conf


  1. go to that directory :

    cd conf


  1. grab this ca.cnf file to use as a configuration shortcut :

    wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/ca.cnf


  1. create a new certificate authority using this configuration :

    openssl req -new -x509 -days 9999 -config ca.cnf -keyout ca-key.pem -out ca-cert.pem


  1. now that we have our certificate authority in ca-key.pem and ca-cert.pem, let's generate a private key for the server :

    openssl genrsa -out key.pem 4096


  1. grab this server.cnf file to use as a configuration shortcut :

    wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/server.cnf


  1. generate the certificate signing request using this configuration :

    openssl req -new -config server.cnf -key key.pem -out csr.pem


  1. sign the request :

    openssl x509 -req -extfile server.cnf -days 999 -passin "pass:password" -in csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem

I found this procedure here, along with more information on how to use these certificates.

John Slegers
  • 45,213
  • 22
  • 199
  • 169
1

An alternative is to generate the certificates with the pem library using the createCertificate method of the class.

The process would be as follows:

Install openssl in your system if not there already, for instance for windows 10 the a compiled version of the sources (seems like the most open one) can be found here: https://curl.se/windows/ the explanations of how it is compiled and safeguarded are here: https://wiki.openssl.org/index.php/Binaries. For the source https://www.openssl.org/community/binaries.html For windows, you may want to add the diretory of the openssl.bin file to the system environment path variable (https://www.architectryan.com/2018/08/31/how-to-change-environment-variables-on-windows-10/) or pass the location of the file to the PEM library.

Instal pem using (documentation here: https://github.com/Dexus/pem

npm i pem

at the command line at the root of the server.

From the documentation you can see that a simple https server with the keys can be created simply by:

const https = require('https')
const pem = require('pem')

pem.createCertificate({ days: 1, selfSigned: true }, (err, keys) => {
  if (err) {
    throw err
  }
  https.createServer({ key: keys.clientKey, cert: keys.certificate }, (req, res)  => {
    res.end('o hai!')
  }).listen(443)
})

or using express npm i express at the command line at the root of the server):

const https = require('https')
const pem = require('pem')
const express = require('express')

pem.createCertificate({ days: 1, selfSigned: true }, (err, keys) => {
  if (err) {
    throw err
  }
  const app = express()

  app.get('/', (req, res) => {
    res.send('o hai!')
  })

  https.createServer({ key: keys.clientKey, cert: keys.certificate }, app).listen(443)
})

Just changed the var for const as appropiate, and functions for arrow functions

Tamir Abutbul
  • 7,301
  • 7
  • 25
  • 53
Julio Spinelli
  • 587
  • 3
  • 16