Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to use private CA certificate and key pair to issue certificates #43

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Envek
Copy link

@Envek Envek commented Sep 22, 2020

Fixes #13

What's inside:

  • Code
  • Readme
  • Tests (I will write some when you will be okay with API)

What's changed

Receive optional ca option object into generate with your own Certificate Authority certificate and private key used to sign certificates.

How to use it

  1. Generate CA keypair with selfsigned itself

    const selfsigned = require('selfsigned')
    const fs = require('fs-extra')
    
    const rootCA = selfsigned.generate(
      [
        { name: 'commonName', value: 'Development Certificate Authority' },
        { name: 'countryName', value: 'RU' },
        { name: 'organizationName', value: 'Evil Martians' }, 
      ],
      {
        keySize: 2048,
        algorithm: 'sha256',
        extensions: [
          {
            name: 'basicConstraints',
            cA: true,
          },
        ]
      }
    )
    
    // Import ca.crt into your browsers:
    // - Chrome: chrome://settings/certificates at Authorities tab
    // - Firefox: about:preferences#privacy, Certificates, View certificates, Authorities tab
    fs.writeFileSync('./ca.crt', rootCA.cert)
  2. Generate certificate signed by this CA

    const cert = selfsigned.generate(
      [
        { name: 'commonName',  value: 'Our cool service' },
        { name: 'countryName', value: 'RU' },
        { name: 'organizationName', value: 'Evil Martians' }, 
      ],
      {
        keySize: 2048,
        ca: rootCA,
        algorithm: 'sha256',
        extensions: [
          {
            name: 'basicConstraints',
            cA: false,
          },
          {
            name: "keyUsage",
            keyCertSign: false,  // Must be set to false or Chrome won't accept this certificate otherwise
            digitalSignature: true,
            nonRepudiation: true,
            keyEncipherment: true,
            dataEncipherment: true,
          },
          {
            name: "extKeyUsage",
            serverAuth: true,
            clientAuth: true,
            codeSigning: true,
            timeStamping: true,
          },
          {
            name: "subjectAltName",
            altNames: [
              {
                // type 2 is DNS
                type: 2,
                value: "localhost",
              },
              {
                type: 2,
                value: "localhost.localdomain",
              },
              {
                type: 2,
                value: "evilmartians.com",
              },
              {
                // type 7 is IP
                type: 7,
                ip: "127.0.0.1",
              },
            ],
          },
        ],
      }
    )
  3. Test it!

    const https = require('https')
    const app = require('express')()
    
    app.get('/', (req, res) => res.send('ok'))
    
    const httpsServer = https.createServer(
      {
        key: cert.private,
        cert: cert.cert,
      },
      app
    )
    httpsServer.listen(4443)

What do you think?

@WayneYe
Copy link

WayneYe commented Feb 1, 2021

Thanks for submitting this improvement PR @Envek
I like it and I would like to see it got reviewed & merged soon, and if it is indeed gonna be merged, I'd hope the readme can cover this setup because IMHO running a local HTTP server recognized by mainstream browsers will be very common for developers.

@dagda1
Copy link

dagda1 commented Jun 15, 2021

is there any way to avoid manually importing the certs into the browser?

@Envek
Copy link
Author

Envek commented Jun 15, 2021

In some cases you can automate this. Here are examples for Firefox and Chrome on Linux

@jfromaniello
Copy link
Owner

Sorry for the delay, this actually looks cool!

Somewhat similar, I've been using mkcert for long time and it just awesome.

In development, I usually do for development is to check if mkcert is installed and spawn it.

@RikiReal
Copy link

Hello. Is there an ETA for merging this PR?

@ghost
Copy link

ghost commented Apr 10, 2022

@Envek @jfromaniello @RikiReal I don't know why but this branch doesn't work with the recent version of node-forge.

      throw new Error(ex);
      ^

Error: Error: Certificate could not be verified.

I believe cert.sign is broken somehow.

@ghost
Copy link

ghost commented Apr 10, 2022

And shouldn't signing certificates with CA follow this?

https://en.wikipedia.org/wiki/Certificate_signing_request

With forge it should be

forge.pki.createCertificationRequest()

@RikiReal
Copy link

@ayanamidev I ended up just using node-forge directly and it did what I needed it to do. Could you show me your code that throws the error? It sounds like there is something wrong with your certificate signature.

@ghost
Copy link

ghost commented Apr 11, 2022

@RikiReal It was this PR that throw the error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How can I generate self signed root CA certificate , and then generate certificates signed by the CA?
5 participants