10

Is it possible in pure JavaScript (no openssl binary) to use Node's crypto library to generate a self-signed certificate? Here is my script that uses openssl to generate a certificate:

#!/bin/bash
FQDN="*"

# Create a private key
openssl genrsa \
    -out server-key.pem \
    2048

# Create a certificate signing request
openssl req \
    -new \
    -key server-key.pem \
    -out certificate-signing-request.csr \
    -subj "/C=US/ST=StateL=City/O=Full Name/CN=${FQDN}"

# Sign the certificate signing request to create the server certificate
openssl x509 \
    -req -in certificate-signing-request.csr \
    -signkey server-key.pem \
    -out server-certificate.pem \
    -days 36159

I'm curious if this could all be done using JavaScript and the classes and methods available here:

https://nodejs.org/api/crypto.html

If so, what would the code look like to create files above?

Vale
  • 1,912
  • 16
  • 22
Kirk Ouimet
  • 27,280
  • 43
  • 127
  • 177
  • 1
    Check out [`selfsigned`](https://github.com/jfromaniello/selfsigned), which uses [`forge`](https://github.com/digitalbazaar/forge) under the hood. – robertklep Jul 25 '15 at 08:00

1 Answers1

17

You can't use Node's crypto to generate a certificate, from their API docs there aren't any functions for creating one (they suggest using openSSL). You could certainly sign a certificate but that requires external actions.

What you can do, if you'd like a solution that does all of it in JS (as suggested also by @robertklep), is using a native implementation in JavaScript like Forge.

In this code sample you create a certificate, self-sign it and export it in PEM format. Forge has everything you need for it, so crypto isn't required.

var forge = require('node-forge');
var pki = forge.pki;

// generate a keypair or use one you have already
var keys = pki.rsa.generateKeyPair(2048);

// create a new certificate
var cert = pki.createCertificate();

// fill the required fields
cert.publicKey = keys.publicKey;
cert.serialNumber = '01';
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);

// use your own attributes here, or supply a csr (check the docs)
var attrs = [{
  name: 'commonName',
  value: 'example.org'
}, {
  name: 'countryName',
  value: 'US'
}, {
  shortName: 'ST',
  value: 'Virginia'
}, {
  name: 'localityName',
  value: 'Blacksburg'
}, {
  name: 'organizationName',
  value: 'Test'
}, {
  shortName: 'OU',
  value: 'Test'
}];

// here we set subject and issuer as the same one
cert.setSubject(attrs);
cert.setIssuer(attrs);

// the actual certificate signing
cert.sign(keys.privateKey);

// now convert the Forge certificate to PEM format
var pem = pki.certificateToPem(cert);
console.log(pem);

The process is pretty straighforward with relatively low amounts of code needed. The forge readme lists all other options, like supplying a csr for attributes and extensions instead of doing it all in code.

Vale
  • 1,912
  • 16
  • 22
  • Is this still true in 2020 with stuff like https://stackoverflow.com/q/51942824/2715716? I'm wondering if the stuff Forge offers to make this possible includes hard-code crypto stuff that isn't in the crypto module or if you could get the key pair and the signing to work using the crypto module and implement PEM serialization yourself. – Tomáš Hübelbauer Nov 08 '20 at 21:20