I have started writing a wrapper for an API which requires all requests to be over HTTPS. Instead of making requests to the actual API while I am developing and testing it I would like to run my own server locally which mocks the responses.
I am confused about how to generate the certificates I need to create a HTTPS server and send requests to it.
My server looks something like this:
var options = { key: fs.readFileSync('./key.pem'), cert: fs.readFileSync('./cert.pem') }; https.createServer(options, function(req, res) { res.writeHead(200); res.end('OK\n'); }).listen(8000);
The pem files were generated with:
openssl genrsa 1024 > key.pem openssl req -x509 -new -key key.pem > cert.pem
And a request looks something like this:
var options = { host: 'localhost', port: 8000, path: '/api/v1/test' }; https.request(options, function(res) { res.pipe(process.stdout); }).end();
With this setup I get Error: DEPTH_ZERO_SELF_SIGNED_CERT
, so I think I need to add a ca
option for the request.
So my question is how should I generate the following:
key
?cert
?ca
for the request?I have read a few things about generating self signed certificates with openssl, but can't seem to wrap my head around it and figure out which keys and certificates to use where in my node code.
Update
The API provides a CA certificate to use instead of the defaults. The following code works using their certificate and this is what I want to reproduce locally.
var ca = fs.readFileSync('./certificate.pem'); var options = { host: 'example.com', path: '/api/v1/test', ca: ca }; options.agent = new https.Agent(options); https.request(options, function(res) { res.pipe(process.stdout); }).end();
To start your https server, run node app. js (here, app. js is name of the file) on the terminal. or in your browser, by going to https://localhost:8000 .
Or would real certificates get the job done better? Have you considered any of these?
(Note: Let's Encrypt can also issue certificates to private networks)
https://coolaj86.com/articles/how-to-create-a-csr-for-https-tls-ssl-rsa-pems/
https://github.com/coolaj86/nodejs-self-signed-certificate-example
Using localhost.greenlock.domains
as an example (it points to 127.0.0.1):
'use strict'; var https = require('https') , port = process.argv[2] || 8043 , fs = require('fs') , path = require('path') , server , options ; require('ssl-root-cas') .inject() .addFile(path.join(__dirname, 'server', 'my-private-root-ca.cert.pem')) ; options = { // this is ONLY the PRIVATE KEY key: fs.readFileSync(path.join(__dirname, 'server', 'privkey.pem')) // You DO NOT specify `ca`, that's only for peer authentication //, ca: [ fs.readFileSync(path.join(__dirname, 'server', 'my-private-root-ca.cert.pem'))] // This should contain both cert.pem AND chain.pem (in that order) , cert: fs.readFileSync(path.join(__dirname, 'server', 'fullchain.pem')) }; function app(req, res) { res.setHeader('Content-Type', 'text/plain'); res.end('Hello, encrypted world!'); } server = https.createServer(options, app).listen(port, function () { port = server.address().port; console.log('Listening on https://127.0.0.1:' + port); console.log('Listening on https://' + server.address().address + ':' + port); console.log('Listening on https://localhost.greenlock.domains:' + port); });
'use strict'; var https = require('https') , fs = require('fs') , path = require('path') , ca = fs.readFileSync(path.join(__dirname, 'client', 'my-private-root-ca.cert.pem')) , port = process.argv[2] || 8043 , hostname = process.argv[3] || 'localhost.greenlock.domains' ; var options = { host: hostname , port: port , path: '/' , ca: ca }; options.agent = new https.Agent(options); https.request(options, function(res) { res.pipe(process.stdout); }).end();
And the script that makes the certificate files:
#!/bin/bash FQDN=$1 # make directories to work from mkdir -p server/ client/ all/ # Create your very own Root Certificate Authority openssl genrsa \ -out all/my-private-root-ca.privkey.pem \ 2048 # Self-sign your Root Certificate Authority # Since this is private, the details can be as bogus as you like openssl req \ -x509 \ -new \ -nodes \ -key all/my-private-root-ca.privkey.pem \ -days 1024 \ -out all/my-private-root-ca.cert.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com" # Create a Device Certificate for each domain, # such as example.com, *.example.com, awesome.example.com # NOTE: You MUST match CN to the domain name or ip address you want to use openssl genrsa \ -out all/privkey.pem \ 2048 # Create a request from your Device, which your Root CA will sign openssl req -new \ -key all/privkey.pem \ -out all/csr.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}" # Sign the request from Device with your Root CA openssl x509 \ -req -in all/csr.pem \ -CA all/my-private-root-ca.cert.pem \ -CAkey all/my-private-root-ca.privkey.pem \ -CAcreateserial \ -out all/cert.pem \ -days 500 # Put things in their proper place rsync -a all/{privkey,cert}.pem server/ cat all/cert.pem > server/fullchain.pem # we have no intermediates in this case rsync -a all/my-private-root-ca.cert.pem server/ rsync -a all/my-private-root-ca.cert.pem client/ # create DER format crt for iOS Mobile Safari, etc openssl x509 -outform der -in all/my-private-root-ca.cert.pem -out client/my-private-root-ca.crt
For example:
bash make-certs.sh 'localhost.greenlock.domains'
Hopefully this puts the nail in the coffin on this one.
And some more explanation: https://github.com/coolaj86/node-ssl-root-cas/wiki/Painless-Self-Signed-Certificates-in-node.js
You need to create a copy of the root ca certificate a DER format with a .crt extension:
# create DER format crt for iOS Mobile Safari, etc openssl x509 -outform der -in all/my-private-root-ca.cert.pem -out client/my-private-root-ca.crt
Then you can simply serve that file with your webserver. When you click the link you should be asked if you want to install the certificate.
For an example of how this works you can try installing MIT's Certificate Authority: https://ca.mit.edu/mitca.crt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With