How to create a Certificate Authority 'CA' using pem lib NodeJs? - node.js

Creating a CA using node
This is how to create a certificate using OpenSSL
OpenSSL Certificate Authority
I tried with pem
This is my closed Issue can't create CSR from private key #244 GitHub
When I trying to generate a CSR
var csrOptions = {
clientKey: '/root/ca/intermediate/private/client.key.pem',
clientKeyPassword: '123456',
hash: 'sha256',
country: 'US',
state: 'California',
locality: 'Mountain View',
organization: 'Alice Ltd',
organizationUnit: 'Alice Ltd Web Services',
commonName: 'pass:client',
}
pem.createCSR( csrOptions , function(err, csr) {
if (err) {
throw err
} else {
console.log(csr.clientKey)
console.log(csr.csr)
}
});
I get this error
/root/sslnode/index2.js:37
throw err
^
% openssl req -new -sha256 -config /root/ca/intermediate/openssl.cnf -key /tmp/54f976cb9cbd0e2dd53b755badb6e6e3fe2256ad -passin file:/tmp/3f4640f1d95ca955f1c44c7f2c4b729347813a5f
unable to load Private Key
140563986715072:error:0906D06C:PEM routines:PEM_read_bio:no start >line:../crypto/pem/pem_lib.c:691:Expecting: ANY PRIVATE KEY

After searching I get the error, clientKey took a key as a string, not a path
clientKey: '/root/ca/intermediate/private/client.key.pem',
clientKey: fs.readFileSync('/root/ca/intermediate/private/client.key.pem'),

Related

MySQL xdevapi Node Error: SELF_SIGNED_CERT_IN_CHAIN

Windows 10 Pro
MySQL8.0
node.js v14.15.5
openssl 1.1.1c
I'm trying to connect to a MySQL database using node, I'm able to connect without TLS just fine. I used openssl to create a private key and self signed certificate. When I try to use TLS in my node app, I keep getting the following error:
$ NODE_TLS_REJECT_UNAUTHORIZED=0 node index.js
(node:15480) Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification.
(Use `node --trace-warnings ...` to show where the warning was created)
Error: self signed certificate in certificate chain
at TLSSocket.onConnectSecure (_tls_wrap.js:1497:34)
at TLSSocket.emit (events.js:315:20)
at TLSSocket._finishInit (_tls_wrap.js:932:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:706:12) {
code: 'SELF_SIGNED_CERT_IN_CHAIN'
}
TypeError: Cannot read property 'sql' of undefined
at C:\Users\gregb\Desktop\PROGRAMMING\VS Code Workspace\xdevapi2\index.js:40:32
at processTicksAndRejections (internal/process/task_queues.js:93:5)
[]
[]
Index.js
let mysqlx = require('#mysql/xdevapi');
let fs = require('fs');
require('dotenv').config();
let rows = [];
let columns = [];
// Works without TLS
// let config = {
// host: 'localhost',
// port: 33060,
// user: 'root',
// database: 'user',
// password: process.env.password
// };
const config = {
host: 'localhost',
port: 33060,
user: 'root',
database: 'user',
password: process.env.password,
ssl: true,
tls: {
rejectUnauthorized: false,
key: fs.readFileSync('./privatekey2.pem'),
cert: fs.readFileSync('./example.crt'),
ca: './cacert.pem'
}
};
(async function () {
let session;
try {
session = await mysqlx.getSession(config);
} catch(err) {
console.log(err);
}
try {
let result = await session.sql('SELECT "firstName" AS c1, "lastName" AS c2')
.execute(row => rows.push(row), column => columns = columns.concat(column));
session.close();
} catch(err) {
console.log(err);
}
console.log(rows); // [['foo', 'bar']]
console.log(columns.map(column => column.getColumnLabel())); // ['c1', 'c2']
})();
I also tried:
NODE_TLS_REJECT_UNAUTHORIZED='0' node index.js
How I used openssl:
Create a public/private key file pair:
openssl genrsa -out privkey2.pem 4096
Split into public/private:
openssl ssh-keygen -t rsa -b 4096 -f privatekey2.pem
Create a cert
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout privatekey2.pem -out example.crt
The problem does not seem to be related to the certificate you are using. It should be related to the fact that you provide a path for the certificate authority file (ca). You do this when you want the client to verify that the server certificate was signed using a certificate in the CA chain, which only works if rejectUnauthorized is true, which is automatically set once you provide that valid CA file path, thus, your custom rejectUnauthorized: false is ignored.
Which begs the question, Is the server certificate signed by the CA you are providing? I suspect it is not, in which case, the error is legitimate.
If so, then it is a bug, and you should report it using the public MySQL issue tracker. However, I ran a few tests and I'm convinced there is no issue, but if you are able to produce a server certificate that was, indeed, signed by that particular CA, which allows to reproduce the same exact scenario, maybe we can dig some dirt.
Disclaimer: I'm the lead developer of MySQL X DevAPI Connector for Node.js

How to use getAttributeValue() in ClientIdentity for fabric shim?

I am using nodejs sdk for hyperledger fabric, inside my chaincode i need to get name of the identity (sam) who is execting the transaction.
{"name":"sam","mspid":"Org1MSP","roles":null,"affiliation":"","enrollmentSecret":"","enrollment":{"signingIdentity":"5aad871581d63447218743ee79289c0c6f531a032d3cf1f0be32083e8c0cbaea","identity":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICizCCAjGgAwIBAgIUQq0tPLPFsLujCsRclZc9POmAh6EwCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTkxMTE5MDU0ODAwWhcNMjAxMTE4MDU1\nMzAwWjBAMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UECxMLZGVw\nYXJ0bWVudDExDDAKBgNVBAMTA3NhbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBGbtyGsC9QNBlO0Z5sumDzEaYR4m8GJpXW2f8Qlvjt79IzCWDjGwFePAIOfnUojz\naDbr0VHgpnWOtUIKUqTVPOujgdUwgdIwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB\n/wQCMAAwHQYDVR0OBBYEFCR78iTBbBSCYjxajhOMyYrWDO8iMCsGA1UdIwQkMCKA\nIHWD+xHmJ7l80nLYW67w4+Bftya5oeDfD9d4KXfnqn3NMGYGCCoDBAUGBwgBBFp7\nImF0dHJzIjp7ImhmLkFmZmlsaWF0aW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhm\nLkVucm9sbG1lbnRJRCI6InNhbSIsImhmLlR5cGUiOiJjbGllbnQifX0wCgYIKoZI\nzj0EAwIDSAAwRQIhAJcIBDcygI6Z67ueo46b3WnJCZr+D1HzhaWNp6Lj/+7oAiA6\nRRc9JjnWFvaFaqIJTyNaE7/HFXTXKr+HIkig/UEZpQ==\n-----END CERTIFICATE-----\n"}}}
I have used the below code
async approve(ctx) {
try {
const owId = new clientIdentity(ctx.stub).getAttributeValue('name')
return owId.toString();
} catch(error) {
console.log(error);
throw new Error(`Low on amount`);
}
}
but the above code is not returning the name or any other attributes.
Help will be appreciated!!!
The attributes you retrieve with getAttributeValue() in the Smart Contract are created as follows with the command line:
fabric-ca-client register --id.name clare --id.secret hursley1 --id.maxenrollments -1 --id.attrs 'department=Finance:ecert,location=Berkshire:ecert'
So I'm creating 2 attributes for department and location. Note the :ecert on the end which means that I want the attributres written to the certificate, not just stored in the CA database. Note also that the attributes aren't added to existing certificates, but only "appear" when you have enrolled or renrolled.
Using the node SDK this is a snippet of code that would add the department attribute when registering an Identity:
//create user attr array
let registerAttrs = [];
let registerAttribute = {
name: "department",
value: "Finance",
ecert: true
};
registerAttrs.push(registerAttribute);
// at this point we should have the admin user
// first need to register the user with the CA server
return fabric_ca_client.register(
{
enrollmentID: username,
affiliation: "org1",
role: "client",
attrs: registerAttrs
},
admin_user
);
In your smart contract you can then access the attribute:
ctx.clientIdentity.getAttributeValue('department');
Note that with the fabric-contract-api the clientIdentity object is already populated so you don't need a new clientIdentity object.
You have no attribute named "name". If you analyze your X.509 certificate...
openssl x509 -text -noout -in yourcert.pem
...you get...
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
42:ad:2d:3c:b3:c5:b0:bb:a3:0a:c4:5c:95:97:3d:3c:e9:80:87:a1
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = US, ST = California, L = San Francisco, O = org1.example.com, CN = ca.org1.example.com
Validity
Not Before: Nov 19 05:48:00 2019 GMT
Not After : Nov 18 05:53:00 2020 GMT
Subject: OU = client + OU = org1 + OU = department1, CN = sam
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:66:ed:c8:6b:02:f5:03:41:94:ed:19:e6:cb:a6:
0f:31:1a:61:1e:26:f0:62:69:5d:6d:9f:f1:09:6f:
8e:de:fd:23:30:96:0e:31:b0:15:e3:c0:20:e7:e7:
52:88:f3:68:36:eb:d1:51:e0:a6:75:8e:b5:42:0a:
52:a4:d5:3c:eb
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
24:7B:F2:24:C1:6C:14:82:62:3C:5A:8E:13:8C:C9:8A:D6:0C:EF:22
X509v3 Authority Key Identifier:
keyid:75:83:FB:11:E6:27:B9:7C:D2:72:D8:5B:AE:F0:E3:E0:5F:B7:26:B9:A1:E0:DF:0F:D7:78:29:77:E7:AA:7D:CD
1.2.3.4.5.6.7.8.1:
{"attrs":{"hf.Affiliation":"org1.department1","hf.EnrollmentID":"sam","hf.Type":"client"}}
Signature Algorithm: ecdsa-with-SHA256
30:45:02:21:00:97:08:04:37:32:80:8e:99:eb:bb:9e:a3:8e:
9b:dd:69:c9:09:9a:fe:0f:51:f3:85:a5:8d:a7:a2:e3:ff:ee:
e8:02:20:3a:45:17:3d:26:39:d6:16:f6:85:6a:a2:09:4f:23:
5a:13:bf:c7:15:74:d7:2a:bf:87:22:48:a0:fd:41:19:a5
Your attribute keys are:
hf.Affiliation
hf.EnrollmentID
hf.Type
There is no "name" attribute. You are probably looking for "hf.EnrollmentID".
EDIT: You yourself indicated your certificate in your question, in enrollment.identity.certificate field. I have only saved...
-----BEGIN CERTIFICATE-----
MIICizCCAjGgAwIBAgIUQq0tPLPFsLujCsRclZc9POmAh6EwCgYIKoZIzj0EAwIw
czELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh
biBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT
E2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTkxMTE5MDU0ODAwWhcNMjAxMTE4MDU1
MzAwWjBAMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UECxMLZGVw
YXJ0bWVudDExDDAKBgNVBAMTA3NhbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BGbtyGsC9QNBlO0Z5sumDzEaYR4m8GJpXW2f8Qlvjt79IzCWDjGwFePAIOfnUojz
aDbr0VHgpnWOtUIKUqTVPOujgdUwgdIwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB
/wQCMAAwHQYDVR0OBBYEFCR78iTBbBSCYjxajhOMyYrWDO8iMCsGA1UdIwQkMCKA
IHWD+xHmJ7l80nLYW67w4+Bftya5oeDfD9d4KXfnqn3NMGYGCCoDBAUGBwgBBFp7
ImF0dHJzIjp7ImhmLkFmZmlsaWF0aW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhm
LkVucm9sbG1lbnRJRCI6InNhbSIsImhmLlR5cGUiOiJjbGllbnQifX0wCgYIKoZI
zj0EAwIDSAAwRQIhAJcIBDcygI6Z67ueo46b3WnJCZr+D1HzhaWNp6Lj/+7oAiA6
RRc9JjnWFvaFaqIJTyNaE7/HFXTXKr+HIkig/UEZpQ==
-----END CERTIFICATE-----
...as yourcert.pem to check it via openssl.

Node TLS socket : DEPTH_ZERO_SELF_SIGNED_CERT error

I am trying to setup a server and some clients using TLS in node. I am using self-signed certificates on the clients and the server. The server runs ok, but when I try to connect a client I end up with the following error on the client side:
Error: DEPTH_ZERO_SELF_SIGNED_CERT
Cert Generation
CA cert:
# Create key to sign our own certs. Act like as our own a CA.
echo "SecuresPassphrase" > ./tls/passphrase.txt
openssl ecparam -name secp521r1 -genkey -noout -out ./tls/certs/ca/ca.plain.key # Generate private key
openssl pkcs8 -topk8 -passout file:./tls/passphrase.txt -in ./tls/certs/ca/ca.plain.key -out ./tls/certs/ca/ca.key # Generate encrypted private key
rm ./tls/certs/ca/ca.plain.key; # Remove unencrypted private key
# Generate CA cert
openssl req -config ./openssl/oid_file -passin file:./tls/passphrase.txt -new -x509 -days 365 -key ./tls/certs/ca/ca.key -out ./tls/certs/ca/ca.crt
Server Cert:
openssl ecparam -name secp521r1 -genkey -noout -out ./tls/certs/servers/server.key # Generate server private key
openssl req -config ./openssl/oid_file -new -key ./tls/certs/servers/server.key -out ./tls/certs/servers/server.csr # Generate signing request
openssl x509 -passin file:./tls/passphrase.txt -req -days 365 -in ./tls/certs/servers/server.csr -CA ./tls/certs/ca/ca.crt -CAkey ./tls/certs/ca/ca.key -CAcreateserial -out ./tls/server.crt
mv ./tls/server.crt ./tls/certs/servers/
Client cert:
Client's certs are created inside a bash loop, the variable ${name} contains the name of the client and changes each iteration.
openssl ecparam -name secp521r1 -genkey -noout -out ./tls/certs/clients/${name}/client.key
openssl req -config ./openssl/oid_file -new -key ./tls/certs/clients/${name}/client.key -out ./tls/certs/clients/${name}/client.csr
openssl x509 -passin file:./tls/passphrase.txt -req -days 365 -in ./tls/certs/clients/${name}/client.csr -CA ./tls/certs/ca/ca.crt -CAkey ./tls/certs/ca/ca.key -CAcreateserial -out ./tls/client.crt
mv ./tls/client.crt ./tls/certs/clients/${name}/
I am also trying to use Perfect Forward Secrecy by using ephemereal Diffie-Hellman interchange. The parameters, for clients and server, are created as openssl dhparam -outform PEM -out ./tls/params/servers/server/dhparams.pem 2048
Server's code:
return new Promise(resolve => {
// Define parameters of TLS socket
const options = {
rejectUnauthorized: false,
requestCert: true,
// Secure Context Parameters
ca: [fs.readFileSync("tls/certs/ca/ca.crt")],
cert: fs.readFileSync("tls/certs/servers/server.crt"),
key: fs.readFileSync("tls/certs/servers/server.key"),
ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:!RC4:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!SRP:!CAMELLIA",
dhparam: fs.readFileSync("tls/params/servers/server/dhparams.pem"),
ecdhCurve: tls.DEFAULT_ECDH_CURVE,
minVersion: "TLSv1.2"
};
// Iniciar servidor TLS
this.SERVIDOR = tls.createServer(options, function (socket) {
console.log("Server created.");
});
this.SERVIDOR.listen(this.puerto, this.direccion, function () {
console.log("Listening");
});
this.SERVIDOR.on("secureConnection", (socket) => this.handleRequest(socket));
this.SERVIDOR.on("tlsClientError", (error) => console.log("Error client TLs. %s", error));
});
Client's code:
return new Promise(resolve => {
// Define parameters of TLS socket
const options = {
host: this.NODE,
port: this.NODE_PORT,
rejectUnauthorized: false,
secureContext: tls.createSecureContext({
ca: [fs.readFileSync("tls/certs/ca/ca.crt")],
cert: fs.readFileSync("tls/certs/clients/" + this.NAME + "/client.crt"),
key: fs.readFileSync("tls/certs/clients/" + this.NAME + "/client.key"),
ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:!RC4:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!SRP:!CAMELLIA",
dhparam: fs.readFileSync("tls/params/clients/" + this.NAME + "/dhparams.pem"),
ecdhCurve: tls.DEFAULT_ECDH_CURVE,
minVersion: "TLSv1.2"
})
};
// Initialize TLS socket
this.WEB_SOCKET = tls.connect(options, function () {
// Check if TLS auth worked
if (this.authorized) {
console.log("Connection authorized by a Cert. Authority ");
} else {
console.log("Authorization not granted. Error: " + this.authorizationError);
}
});
What I have tried:
Set rejectUnauthorized to false.
Tried to run the code with NODE_TLS_REJECT_UNAUTHORIZED = "0";. It didn't work and I think is not a good option for production.
Checked similar questions on SO, this one it looks pretty similar to my problem. But the most upvoted answer is from 2014 and I couldn't find too much information about Distinguished name on the docs.
I checked the certs using openssl x509 -in *.cert -text and they looked good.
¿Am I wrongly generating the certs? Any help is appreciated.
Thanks!
EDIT. 16/10/2019
There was a problem in the code, I didn't use resolve(); when the sockets were up. The same problem remains... BUT despite of getting an authorization error on the client, the server fires up the "secureConnection" event and messages are interchanged. ¿Does this makes sense? *Yes, it makes sense since the server accepts unauthorized connections. If I set the server to reject not certified connections the clients hung up *
The problem was I was using the same configuration file (./openssl/oid_file) for all the certificates. Using different configuration files and different Alternative names solved this issue.
I ended with an "UNABLE_TO_VERIFY_LEAF_SIGNATURE" error. The certificates were properly generated but it didn't work. I couldn't find a working example of self-signed certificates in nodejs. Most of them simply deprecated the use of certificates by disabling SSL or accepting unathorized transactions, which is the opposite of what TLS is supposed to do.
Finally, I used this tool to generate the certificates: https://github.com/FiloSottile/mkcert . The best and simplest way to generate self-signed certificates in a testing environment. You only need to set the node variable NODE_EXTRA_CA_CERTS to point the root certificate:
process.env.NODE_EXTRA_CA_CERTS = [os.homedir() + "/.local/share/mkcert/rootCA.pem"];
-

SSL in socket.io with express: Missing PFX or certificate + private key.

I want to socket with socket.io through SSL. I have read the other answers but nothing worked
Here is my code:
var ssl_options = {
key : fs.readFileSync(my_key_path),
cert : fs.readFileSync(my_cert_path)
};
var protocol = "https";
preparedApp = require(protocol).createServer(ssl_options,app);
var io = require('socket.io')(preparedApp);
preparedApp.listen(8080, function(){});
io.on('connection', function(socket){});
And here is the log of my ssl_options...
{ key: <Buffer 41 ...>,
cert: <Buffer 4a ...> }
This errors with the error in the title throw new Error('Missing PFX or certificate + private key.');. Does anyone know what might be happening? None of the other solutions to this answer solved my case.
Use PEM (RSA) format for your private key. Check if the private key is a base64 encoded, enclosed between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----"
From the docs:
key: A string or Buffer containing the private key of the server in PEM format
cert : A string holding the PEM encoded certificate
passphrase: A string of passphrase for the private key or pfx [optional default: null]
or
pfx : A string or buffer holding the PFX or PKCS12 encoded private key, certificate and CA certificates
To convert a private key to RSA PEM: openssl rsa -in <PATH TO KEY> -out key.pem -outform PEM
To create a PKCS #12 bundle use openssl pkcs12 -export -in cert.pem -inkey key.pem -certfile ca.pem -out host.pfx
-- ADDITION --
To ensure the cert is PEM encoded run openssl x509 -in <PATH TO CERT> -out cert.pem -outform PEM

How do I use a self signed certificate for a HTTPS Node.js server?

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:
The server key?
The server cert?
The 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();
Update (Nov 2018): Do you need self-signed certs?
Or would real certificates get the job done better? Have you considered any of these?
Let's Encrypt via Greenlock.js
Let's Encrypt via https://greenlock.domains
Localhost relay service such as https://telebit.cloud
(Note: Let's Encrypt can also issue certificates to private networks)
ScreenCast
https://coolaj86.com/articles/how-to-create-a-csr-for-https-tls-ssl-rsa-pems/
Full, Working example
creates certificates
runs node.js server
no warnings or errors in node.js client
no warnings or errors in cURL
https://github.com/coolaj86/nodejs-self-signed-certificate-example
Using localhost.greenlock.domains as an example (it points to 127.0.0.1):
server.js
'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);
});
client.js
'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:
make-certs.sh
#!/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
Install private cert on iOS Mobile Safari
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
Related Examples
https://github.com/coolaj86/nodejs-ssl-example
https://github.com/coolaj86/nodejs-ssl-trusted-peer-example
https://github.com/coolaj86/node-ssl-root-cas
https://github.com/coolaj86/nodejs-https-sni-vhost-example
(Multiple vhosts with SSL on the same server)
https://telebit.cloud
(get REAL SSL certs you can use TODAY for testing on localhost)
Try adding this to your request options
var options = {
host: 'localhost',
port: 8000,
path: '/api/v1/test',
// These next three lines
rejectUnauthorized: false,
requestCert: true,
agent: false
};
Your key generation looks okay. You shouldn't need a ca because you aren't rejecting unsigned requests.
Add .toString() to the end of your readFileSync methods so that you are actually passing a string, not a file object.
This procedure allows you to create both a certificate authority & a certificate :
grab this ca.cnf file to use as a configuration shortcut :
wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/ca.cnf
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
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
grab this server.cnf file to use as a configuration shortcut :
wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/server.cnf
generate the certificate signing request using this configuration :
openssl req -new -config server.cnf -key key.pem -out csr.pem
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.
Try adding
agent: false,
rejectUnauthorized: false
When you have the self-signed cert[s], you tell Node.js to use it with the Environment variable: NODE_EXTRA_CA_CERTS
Copy [cat] all the generated *.cert.pem files to a single file.
I put it the directory with all the keys & certs:
> (cd $keys; cat *.cert.pem > node_extra_ca_certs)
Tell node where to find them:
> export NODE_EXTRA_CA_CERTS=$keys/node_extra_ca_certs
Now, when you run node, it will accept your private certs as valid.

Resources