Broken HTTPS SSL in express-js server (net::ERR_CERT_COMMON_NAME_INVALID) - node.js

I have an express js application that I want to listen on HTTPS.
I had a .key file and a .crt file that were already in PEM format (they contained readable text, as this answer says to check), so I used OpenSSL with these commands (taken from the answer linked above, and before finding that answer I had tried using the .key and .crt files I already had and using .pem files created by just renaming those two files into .pem, with no success):
openssl x509 -in public.crt -out public.pem -outform PEM
openssl rsa -in private.key -out private.pem -outform PEM
When I try to access the website at https://localhost, though, this is the error I get:
How can I make it work as intended?
Note that the certificate and key are VALID since I'm already using them on an existing website, it's not a self-signed test certificate.
Also, the client page tries to get the resource "/hey" but in addition to the HTTPS error in the certificate, instead of the resource the page gets a response that says "Cannot GET/"
Here is the code to the node.js app:
var express = require('C:/Users/f.fiore/AppData/Roaming/npm/node_modules/express');
var fs = require('fs');
var http = require('http');
var https = require('https');
var key = fs.readFileSync('./private.key');
var cert = fs.readFileSync('./public.crt')
var options = {
key: key,
cert: cert
};
var PORT = 8000;
var HOST = 'localhost';
var app = express();
var httpServer = https.createServer(app);
var httpsServer = https.createServer(options, app);
httpServer.listen(PORT);
httpsServer.listen(443);
// routes
app.get('/hey', function(req, res) {
sendToClient("HO!", res, 200, "text/plain");
});
function getHeader(type){
return {"Content-Type": type};
}
function sendToClient(data, res, code, type){
res.writeHead(code, getHeader(type));
(type === "text/html" || type === "text") ? res.end(data, "utf-8") : res.end(data);
}

Your certificate is valid, however the provider of the certificate is not the original issuer of this certificate.
So you need to provide the whole chain certificate at your localhost to make it work.
https://certificatechain.io/ seems like they are providing a service for this, but haven't tried. Better way is to check with your certificate provider.
Self signed certificates also bring such an error.
EDIT
Seems like the problem was more basics. Updating the solution
Try to play with your etc/hosts file to show the real domain name at your localhost. Right now it is looking for a domain called localhost and I don't think that you get a certificate for your localhost :) \Windows\System32\drivers\etc\hosts at windows environment
For your basic request of /hey please insert this codeblock
app.get('/hey', function(req, res){
res.send('HO!');
});

Related

nodejs pem generated openssl self signed certificate generation for intranet CIPHER_MISMATCH

I am using the module "pem" for nodejs && express to generate openssl self signed certificates for a demo webserver run over a local intranet.
The issue I am having is that when I attempt to load pages off the webserver I am receiving the error: "The client and server don't support a common SSL protocol version or cipher suite."
How would I be able to utilize pem ( or other ) in a way to allow me run my webserver over https via my intranet?
I am running/testing this on a ubtuntu machine and also testing on a windows machine. Both are generating the same error - the accessible machine over the intranet would be from the linux box. I am using nodejs 10 and tested on firefox, chrome, edge and safari
...
pem.createCertificate({ days: 365, selfSigned: true }, this.start);
...
start(err, keys) {
if (err) {
throw err
}
let server = https.createServer(app,
{ key: keys.serviceKey, cert: keys.certificate });
server.listen(port,
() => console.log(`API/NG running on https://localhost:${port}`)
);
}
According to the documentation of the pem module, the order of arguments is in reverse order, like follows:
var serverOptions = {
key: keys.serviceKey,
cert: keys.certificate
};
var app = express();
var server = https.createServer(serverOptions, app);

NodeJS load PFX certificate from file

I am writing a small project using Node.JS and TypeScript, once of the requirements is to read a PFX certificate from a .pfx file and use this in the code to encrypt the payload body
I have a certificate public/private key file called cert1.pfx, my code requires this certificate as below
...
const cert = loadPfx("cert1.pfx");
const p: Payload = new Payload();
p.addReaderCertificate(cert);
...
I have searched around but cannot find a way to load the PFX for my use case, I have seen examples of loading a PFX for HTTPS server or Express.JS, I looked a node-x509 but that is for BASE64 encoded CER or PEM certificates, I also looked at node-rsa but thats for encrypt/decrypt using public/private keys.
Does anyone know if this is possible? If so would appreciate some pointers on how to accomplish.
So after a LOT of research and trawling the Google archives I came across a package called pem and this has the following method:
pem.readPkcs12(bufferOrPath, [options], callback)
This can read a PKCS#12 file (or in other words a *.pfx or *.p12 file) amongst other things, I must have missed this in my earlier research.
Usage:
const pem = require("pem");
const fs = require("fs");
const pfx = fs.readFileSync(__dirname + "/test.pfx");
pem.readPkcs12(pfx, { p12Password: "password" }, (err, cert) => {
console.log(cert);
});
Output:
{ cert: "...", ca: ["subca", "rootca"], key: "..." }
You can find more here and here.
It sounds like you only need to use Node's own https capabilities. Node can read the PFX file directly. (Https.createServer, SSL Options)
Example from Node.js site:
const https = require('https');
const fs = require('fs');
const options = {
pfx: fs.readFileSync('test/fixtures/test_cert.pfx'),
passphrase: 'sample'
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
I was also stuck on a similar problem #neil-stevens solution helped me to read the .pfx file but what i find is one feature/bug ( i don't know exactly what it is) of pem that it returns encrypted private key mostly in RSA , but if you need actual private key you need to export encrypted key into pkcs8,which can be done using Node RSA.
Usage :
const RSAKey = cert.key;
const key = new NodeRSA(RSAKey);
const privateKey = key.exportKey("pkcs8");
Complementing the answer of Neil Stevens (Sorry, idk how to quote).
I hade that issue of getting a empty object only, but so i just observe that i was not loging the err. So i did that, after that i was able to resolve my problems
1º You need to have installed openSSL or libressl how described on https://github.com/Dexus/pem.
Tip: To install if you already have configured and instaled Chocolatey. Just Run the command: "choco install openssl". (with eleveted permissions)
2º I had to use pem.config() to set exatcly path of openSSL folder. I think you can also define in the Environment Variables, i just not tested this way yet.
3º Finally my code it was left like this:
const pem = require("pem");
const fs = require("fs");
const pfx = fs.readFileSync("./cert.pfx");
let certificate = '';
pem.config({
pathOpenSSL: 'C:\\Program Files\\OpenSSL-Win64\\bin\\openssl'
})
const getPrivateKey = async () => {
return new Promise(async (resolve, reject) => {
pem.readPkcs12(pfx, { p12Password: 'myPassWordStr' }, (err, cert) => {
console.log('err::: ', err);
// console.log('cert::: ', cert);
resolve(cert);
});
});
}
const start = async () => {
certificate = await getPrivateKey();
console.log('privateKey::: ', certificate);
}
start();
I arrived here while trying to find a way to configure a local web server with HTTPS for local development using the development certificate generated by the .NET CLI (as this is easily created / trusted / removed).
Thanks to Neil Stephen's answer I was able to create a working solution on Windows, using a combination of npm, dotnet CLI, openssl and npm package pem.
Git ships with a copy of OpenSSL, so I didn't need to install it separately :)
.env
OPENSSL_PATH=C:\Program Files\Git\usr\bin\openssl
CERT_PASSWORD=SecurePassword123
CERT_PFX=cert/localhost.pfx
CERT_PEM=cert/localhost.pem
CERT_KEY=cert/localhost.key
PORT=443
ENTRYPOINT=src/index.html
package.json
"scripts": {
"start": "env-cmd -x parcel $ENTRYPOINT --https --cert $CERT_PEM --key $CERT_KEY --port $PORT --open",
"build": "env-cmd -x parcel build $ENTRYPOINT",
"dev-certs": "run-s dev-certs:create dev-certs:convert",
"dev-certs:create": "env-cmd -x dotnet dev-certs https -ep $CERT_PFX -p $CERT_PASSWORD --verbose --trust",
"dev-certs:convert": "node ./cli/cert.mjs",
"dev-certs:clean": "dotnet dev-certs https --clean"
},
cert.mjs
import pem from "pem";
import { PFX2PEM } from "pem/lib/convert.js";
import fs from "fs";
import "dotenv/config";
pem.config({
pathOpenSSL: process.env.OPENSSL_PATH
});
const pass = process.env.CERT_PASSWORD;
// GET .KEY FILE - without this, HMR won't work
const pfx = fs.readFileSync(process.env.CERT_PFX);
pem.readPkcs12(pfx, { p12Password: pass }, (err, cert) => {
if (!!err) {
console.error(err);
return;
}
// console.log(cert.key);
fs.writeFileSync(process.env.CERT_KEY, cert.key);
});
// GET .PEM FILE
PFX2PEM(process.env.CERT_PFX, process.env.CERT_PEM, pass, (errPem, successPem) => {
if (!successPem) {
console.error(errPem);
return;
}
console.log(`Certificate '${process.env.CERT_PEM}' created!`);
});
Repository is here: https://github.com/zplume/parcel-https and the README contains details of how it works.

How to set connect server (node) to work on HTTPS? Error: error:0906D06C:PEM routines:PEM_read_bio:no start line

I am using connect server, and I need to create my localhost under https (even if certificates are not valid).
At the moment I am using the following script which createa a server listing at http://127.0.0.1:8080/
I need to set it up as: https://127.0.0.1:8080/
How to configure connect server?
gulp.task('dev:connect', function () {
// runs connect server for rapid development
connect.server({
root: ''
});
});
I am also trying this but with not success:
var https = require('https');
var options = {
key: fs.readFileSync('b.key'),
cert: fs.readFileSync('a.crt')
};
var app = connect(); // error here object is not a function
https.createServer(options, app).listen(8080);
Try to run the following, I think the key is protected:
$ openssl rsa -in b.key -out b-unprotected.key
$ cat b-unprotected.key a.crt > a.pem
Let me know if this works

Server HTTPS on node.js doesn't work

I'm trying to create an HTTPS server. I have generated privatekey.pem and certicate.pem with Cygwin64 following these instructions:
openssl genrsa -out privatekey.pem 1024
openssl req -new -key privatekey.pem -out certrequest.csr
openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
while my server code is this:
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('privatekey.pem'),
cert: fs.readFileSync('certificate.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8001);
When i try to connect to address https://localhost:8001, the web page is not available. Can anyone help me?
Your code is absolutely working fine. I have tested it in my localhost. I think the issue is with your key generation. Try to generate once again the keys and run your server. I hope it will work.
Note: The certificate you are generating, will work only in localhost. So do not try this in any online IDE(like codio.com, koding.com, cloud9.com etc). If you want to do to you have to purchase the SSL Certificate from the company like Verysign.
OR
If not try the below code.
Step 1: Open your terminal and run the following command to generate private key file 'key.pem'.
$ openssl genrsa 1024 > key.pem
Step 2: Now run the following command to generate SSL Certificate file 'key-cert.pem'.
$ openssl req -x509 -new -key key.pem > key-cert.pem
Step 3: Now write the 'server.js' file with the following content.
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('key-cert.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8001);
Step 4: Now run the server file using following command.
$ node server.js
Step 5: Now in the browser hit the url 'https://localhost:8001' and accept the certificate and you will see the 'hello world' message on the page.

Can't start NodeJS HTTPS server. v0.10.23

Some time ago I tried pretty much the same code on previous version of nodejs and it worked (suppose we have router already)
var https = require('https');
var fs = require("fs");
var crypto = require("crypto");
var private_key = fs.readFileSync("cert/domainname.key").toString();
var cert = fs.readFileSync("cert/domainname.crt").toString();
var options = crypto.createCredentials({
key: private_key,
cert: cert
});
var server = https.createServer(options, router);
server.listen(8080);
I got error Missing PFX or certificate + private key. Why is that? I passed both private key and certtificate.
You shouldn't need to use crypto.createCredentials() or .toString() the file contents:
var options = {
key: fs.readFileSync('cert/domainname.key'),
cert: fs.readFileSync('cert/domainname.crt')
};
var server = https.createServer(options, router):
https.createServer() expects an options Object, with either a pfx or key and cert, rather than a credentials object created by crypto.createCredentials().
And using .toString() on the Buffers from readFileSync() will attempt to treat the binary as UTF-8 and convert to a UTF-16 String, which may actually cause data loss.
Side note: Unlike require(), fs paths like 'cert/domainname.key' will be relative to the current working directory. To treat them as relative to the current module file, you can combine them with __dirname.
fs.readFileSync(__dirname + '/cert/domainname.key')
See an example of using https with express here: https://github.com/steinfletcher/https-expressjs-example/blob/master/README.md

Resources