How can i pass the base64 string as a input certificate for Openssl? - node.js

I have a certificate which i am getting in string . I just want that string to be directly pass as -in in the openssl command.
But i don't see any method in openssl , can you help.
my code
const { exec } = require('child_process');
exec('openssl x509 -noout -issuer -in '+certificateString , (err, stdout, stderr) => {
if (err) {
console.log(err);
}else{
console.log(studout);
}
});
If i directly pass certificate file url it works, like this
openssl x509 -noout -issuer -in certificate.pem
this work
but how can i pass the certificate string directly in openssl ?
Any help?

First, do you have base64 or PEM? Those are not the same thing; although PEM includes base64, it is not only base64. If you have a file that works with openssl x509 -in file then it is PEM, NOT only base64. People seem to look at PEM, see more than 40 base64 characters, and their brains shut down and become unable to see the dashes-BEGIN line, the dashes-END line, and the line breaks, all of which are REQUIRED.
Second, certificate.pem is a filename or pathname, not a URL. A filename or pathname is not a URL, and a URL is not a filename or pathname, although some URL schemes (and particularly the only ones most people notice) include some elements in common with pathnames.
The certificate input to openssl x509 must be either a (named) file, or standard input (commonly abbreviated stdin). If you don't want to supply it as a named file, nodejs can provide data to a child's stdin, but not with the higher-level exec* methods, only the more basic spawn:
const{ spawn } = require('child_process');
const pem = `-----BEGIN CERTIFICATE-----
MIIDUzCCAjugAwIBAgIJANK2Ysp8bp+6MA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTETMBEGA1UEBwwKVGluc2VsdG93bjEPMA0GA1UE
CgwGRGlzbmV5MB4XDTE5MDUwOTA5MTQ0NVoXDTIwMDUwODA5MTQ0NVowQDELMAkG
A1UEBhMCVVMxCzAJBgNVBAgMAkNBMRMwEQYDVQQHDApUaW5zZWx0b3duMQ8wDQYD
VQQKDAZEaXNuZXkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCuKNJI
oBJ6acFSqMlG6e6WS44jC0RP+2y0q+02P4xc9BIuPjKV6/Lkg3bnYenAzktemvc7
EVFOUS/Ema4UIc+aDtSpjAegWnZNrzX+K76Xxzw+RnZalXB1Z++CpTdtsgSmkrmR
wJ7ZZpclAK+Yt6Ggx9ea3/d8WJ85V30ezcG7hPf5BrCSxzjSPsxG3heDPh1/X0zk
H7PD0JB+IW08yOikLmQNZeTZXaIAaSXoIPj5L9Ax7kyDEiDcSBIcQbPGMfIG6CPO
hKOM4yZKWni0mO9jwgfYNU6Bxei35/KTVwBWXHck9N7DdEtoST9THYO7ZFqqvTdk
mLfBpsPXorFT+vAVAgMBAAGjUDBOMB0GA1UdDgQWBBQyXFJDoapFe4JaZBD1xVYE
ImDj7DAfBgNVHSMEGDAWgBQyXFJDoapFe4JaZBD1xVYEImDj7DAMBgNVHRMEBTAD
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAwFXI13uxhGz+fem7N03r0+dnNaXZQQ9CR
owTHVVOjsfrsbFPhKdZIKMKeqpc1AksqynhbV2zY5VjINMab8ADw165gTCgy8/0S
X3QQsy2P5RNx/YuRMvs6hP7ZhZQlabLVbBnCWqAevT2qEZ7Gmi+m9A9sdK2Hsrkj
0lxGCozscme7E3ZfR/3GQVzyfZVppRLsgIth9F2y6SyLXwi+v39C+a9vdZjMS3Uy
HuRD9Sk8xydWywI8wKBlfnX4KGMBjKpSDpMeb6723eXuPC+soUBafuUoP+fWqjg4
LFgYg1TtyzfdrkkWZ9/KxS47OxkF6BAQtFGVF2nNgcpdXxToK7pP
-----END CERTIFICATE-----
`;
const p = spawn("/path/to/openssl", ["x509","-noout","-issuer"]);
// options.stdio defaults to ['pipe','pipe','pipe']
p.stdout.on('data',(data)=> {console.log(data.toString())} );
p.stderr.on('data',(data)=> {console.log("ERROR:"+data.toString())} );
p.on('close',()=> {} );
p.stdin.write(pem); p.stdin.end();
However, you don't need to run an external program to parse a certificate; there are lots of JS libraries to do it. For example, with the second one npmjs finds for me:
const { Certificate } = require('#fidm/x509');
const { ASN1 } = require('#fidm/asn1');
var iss = Certificate.fromPEM(pem).issuer.attributes;
var s = ""; for(var a of iss){ s += "/" + a.shortName + "=" + a.value; }
console.log(s);
If you actually did have base64 and not PEM, replace the third line with
const bin = Buffer.from(b64,'base64');
var iss = new Certificate(ASN1.fromDER(bin)).issuer.attributes;

Related

Reading public and private key from stored files in node js

I wanted to encrypt and decrypt a message in node using public and private keys stored in my system. I was using the following java code to read the file and use the keys.
Java Code:
byte[] keyBytes = Files.readAllBytes(new File(publicKeyFileName).toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
publicKey=kf.generatePublic(spec);
I am able to use the above java method without any issues to read the public key from file. However, I want to achieve similar functionality in node.
I have tried using crypto for achieving the same but it gives me error while passing the key to publicEncrypt method.
Node:
var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) {
var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
var publicKey = fs.read(absolutepath, "utf-8");
console.log(publicKey);
var buffer = Buffer.from(toEncrypt);
var encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
};
Error
internal/crypto/cipher.js:43
return method(toBuf(key), buffer, padding, passphrase);
^
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
Please help. Thanks
Your problem is located in the file format you are actually using with Java. You probably save the
private and the public in encoded ("byte array") to a file and rebuild the keys e.g. with
X509EncodedKeySpec.
This format is not compatible to Node.JS and you have 3 ways to solve it:
a) you write the keys in Java with re neccessary format for usage in Node.JS
b) you write a converter in Node.JS to get the correct format
c) you convert the files with a tool like OPENSSL.
Here I show you the "c-way" as you are handling just one keypair and probably don't need a programatically solution.
Let's say you have two files with the private key ("rsa_privatekey_2048.der") and the public key ("rsa_publickey_2048.der").
In OPENSSL you are using the command line with
openssl rsa -inform der -in rsa_privatekey_2048.der -outform pem -out rsa_privatekey_2048.pem
openssl rsa -inform der -pubin -in rsa_publickey_2048.der -outform pem -RSAPublicKey_out -out rsa_publickey_2048.pem
to convert the files to their PEM-encoded formats.
Below you can find the two sample files I created.
rsa_privatekey_2048.pem:
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAmbeKgSAwVe0nZ84XlbDhMkUDjx1C0duA16MkzHTg1uh9SouO
KK0e3gPtTJ9LssaHlXSYhjpMDMWGO6ujd85XRosI2u9eSMNRYY25AQuBriSTVdi9
BHqWAuWuo6VuvTrkgWTL69vNWvLXTOkTiIyrgnhiavjNvm4UVy2AcO2Y3ER+dKgJ
pQAYlEP1jvuQuf6dfNdSBoN0DZbxZXYbQqoA9R/u0GZHCXY+r8A54RejG34pnnuH
koyROZz5H9LbKGOiaETryornQ1TRvB/p9tgIoCJFI71WsKsqeWQPG3Ymg/FoEWXN
Y0yopZEjpkZa3tU+hrOmAFIRg+/bedKfjYFi/QIDAQABAoIBAD3XZ3N3fbq0BExw
z3A7jv3oYfwrq3w+MOGQEvfmdaZANlfNOU4ICAkNz2QqGgw8bsOj+tDVl070EILl
FIjYjKgmu1NJRcdEPPNgTvOqq2th75xz6+dnYf6cZNwVbC3ZCaE86gVjkoRqek/I
3UDsRvvgbsfWfP+Fzc0c0zWbgQnsK6qivU1uzJX+5xsvgQlZboeZOO2lsdQMgfnu
iGlW1bVVM4Sy7AngqfiKMzihUnYEBIi0Y+mfxAPcBLUW8mrOvIOPPuNNUPxUtkBF
bDEzZ6loXCLLD8UBqXeDbCUPPFdTGcc7INhVgFdl2FL6rHB0+p6eUt8MI/XkZI2d
2AnkBUkCgYEA34cKLs2l5bPjyKybbj6ZG7RhDRsnPypEGU63DMV21twISqt7ZQNv
i3iTP+FYHM3ImECbNRIOZpyLuWLPmh5+5egQH13jRDempoxVSVcghbIserlCz2EU
nD2V6ZKuaDbn395O6Qe/PE/yKHLWbXwJrBBm+o7GGNm/Jd3KJib23PcCgYEAsAxB
esEsxxL8hqg/qf+ij7JJt492svpK/6QXhqeeP/FVOtYSgoNtSrXh9qahGpzMSF0m
FqwIgrOX0RkK3v6ofGVfIKObxOVyhwddS1Ru+SnjBFnTMKS57q0WNrIrBNM6Q0xE
Wd3tiljwmg8xF90U/BXu+m0v5XWKxSn7VLiCBqsCgYEAgl0xtSY/EP6fZJQ2ek+L
4DqNN6WUeCRgXxonbA1mR91AALyOVNVyIreJuYHlb7ccvJ9BZexH9dRrMQ3N4ibS
/6cecAzD1S9XxF6oBwQHdbH6ewC9VFFcQdsxKW5gxWrwRQJUp1fbUoOVyb1gDa5/
vZg7VvoZ0rh74Mu/cAzdgPUCgYEAiNANdwt29AKyUyefykpLGCczGL8aPP88l6z7
R38uAX1Ygg/pdJoUrnHo+FkIbHkcXMRfHFF3j7NoMWynwSLg50OUiPX80SiLN5qm
iytDzskZjsEL2gq6IF1NHRabTfWlmrVDjR9mQhTabq+NtIDwlPOqs9100nrlbFIy
6uU0z18CgYEAkDxQg5UjOzbYIighp/e0LkfKlwUE/cMtISUq1A6Yio9AKZYdBV8p
dd4osUW0gZvDflXlQaBIaNlOwl035lyEZtyuKmFh1oSmoir/TTMbIk0avSgKCLGg
fnhabaQRHl4RdXWcEsioRv3aZUsGkb46Y8xODyAUPRHBPhBsd71gnZ8=
-----END RSA PRIVATE KEY-----
rsa_publickey_2048.pem:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAmbeKgSAwVe0nZ84XlbDhMkUDjx1C0duA16MkzHTg1uh9SouOKK0e
3gPtTJ9LssaHlXSYhjpMDMWGO6ujd85XRosI2u9eSMNRYY25AQuBriSTVdi9BHqW
AuWuo6VuvTrkgWTL69vNWvLXTOkTiIyrgnhiavjNvm4UVy2AcO2Y3ER+dKgJpQAY
lEP1jvuQuf6dfNdSBoN0DZbxZXYbQqoA9R/u0GZHCXY+r8A54RejG34pnnuHkoyR
OZz5H9LbKGOiaETryornQ1TRvB/p9tgIoCJFI71WsKsqeWQPG3Ymg/FoEWXNY0yo
pZEjpkZa3tU+hrOmAFIRg+/bedKfjYFi/QIDAQAB
-----END RSA PUBLIC KEY-----
There's potentially a few issues with your code or the encryption key you're using:
You're using fs.read incorrectly as Node is asynchronous and it needs a callback function to properly read the file.
The encryption key you're using is formatted incorrectly for crypto.publicEncrypt. You must have the proper RSA headers.
I modified your code to use fs.readFile properly instead in the standard Node callback form, and here's an example encryption key in the correct RSA format to use:
var path = require('path');
var crypto = require('crypto');
var fs = require('fs');
var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey, callback) {
var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
fs.readFile(absolutePath, 'utf-8', (err, publicKey) => {
// The value of `publicKey` is in the callback, not the return value
console.log(publicKey);
var buffer = Buffer.from(toEncrypt);
var encrypted = crypto.publicEncrypt(publicKey, buffer);
if (err) {
callback(err);
} else {
callback(null, encrypted.toString("base64"));
}
});
};
encryptStringWithRsaPublicKey('hello world', 'test.pub', (err, encrypted) => {
// If you're using a callback in a function,
// the original function must have a callback as well
console.log(encrypted);
});
Example encryption key at test.pub (must have the RSA headers as shown below):
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA+xGZ/wcz9ugFpP07Nspo6U17l0YhFiFpxxU4pTk3Lifz9R3zsIsu
ERwta7+fWIfxOo208ett/jhskiVodSEt3QBGh4XBipyWopKwZ93HHaDVZAALi/2A
+xTBtWdEo7XGUujKDvC2/aZKukfjpOiUI8AhLAfjmlcD/UZ1QPh0mHsglRNCmpCw
mwSXA9VNmhz+PiB+Dml4WWnKW/VHo2ujTXxq7+efMU4H2fny3Se3KYOsFPFGZ1TN
QSYlFuShWrHPtiLmUdPoP6CV2mML1tk+l7DIIqXrQhLUKDACeM5roMx0kLhUWB8P
+0uj1CNlNN4JRZlC7xFfqiMbFRU9Z4N6YwIDAQAB
-----END RSA PUBLIC KEY-----
As of 2020, there are also other ways of making the code cleaner, such as with using the Promises version of the fs module and async / await, though I wanted to keep this answer as simple as possible for now.

Node.js Crypto AES-128 encrypt stream with padding

I am successfully using NodeJS to encrypt a file in the following manner:
let cipher = crypto.createCipheriv('aes-128-cbc', key, iv),
crypted = cipher.update(file_data, 'binary');
return Buffer.concat([crypted, cipher.final()]);
This generates a file with a hash that exactly matches our target encryption, which is server-side OpenSSL command:
openssl aes-128-cbc -e -in file -out file.enc -nosalt -iv <iv_str> -K <k_str>
The goal is to upgrade our systems to use nodejs streams. Node documentation and other posts suggest the following way to encrypt streams:
cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
let file_stream = fs.createReadStream(local_file, 'binary'),
write_stream = fs.createWriteStream(`${local_file}.enc`, 'binary');
file_stream.pipe(cipher).pipe(write_stream);
however this ignores the cipher.final() appending. Without it the encryption always results in a file with the wrong hash. I've tried:
creating a Transform that would append the remaining padding. That doesn't work because you can't call final on a cipher that hasn't had update called on it
setting the autopadding with setAutoPadding. In all cases that results in the error Error: error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:data not multiple of block length
How can I cipher with streams in the same way I was originally encrypting?

Programmatically create certificate and certificate key in Node

Using node.js, I'd like to write code to programmatically do the equivalent of the following:
openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
openssl rsa -passin pass:x -in server.pass.key -out server.key
rm server.pass.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
When complete, I need the RSA key server.key and the self-signed SSL certificate server.crt.
forge looks the most promising, but so far I haven't figured out how to get it to work. I have the following code:
var pki = forge.pki;
var keys = pki.rsa.generateKeyPair(2048);
var privKey = forge.pki.privateKeyToPem(keys.privateKey);
var pubKey = forge.pki.publicKeyToPem(keys.publicKey);
But when I write the pubKey to a file, I've noticed it starts with ...
-----BEGIN PUBLIC KEY-----
MIIB...
-----END PUBLIC KEY-----
... and isn't recognized, whereas using openssl above it starts with:
-----BEGIN CERTIFICATE-----
MIID...
-----END CERTIFICATE-----
Since the original link went dead, I've made my own code that generates a self-signed certificate using node-forge (which it looks like they already have based on the original question), so I thought I'd put it here for someone who wants it
Simply creating a public and private key pair isn't enough to work as a certificate, you have to put in attributes, node-forge is incredibly useful this way, as its pki submodule is designed for this.
First, you need to create a certificate via pki.createCertificate(), this is where you'll assign all of your certificate attributes.
You need to set the certificate public key, serial number, and the valid from date and valid to date. In this example, the public key is set to the generated public key from before, the serial number is randomly generated, and the valid from and to dates are set to one day ago and one year in the future.
You then need to assign a subject, and extensions to your certificate, this is a very basic example, so the subject is just a name you can define (or let it default to 'Testing CA - DO NOT TRUST'), and the extensions are just a single 'Basic Constraints' extension, with certificate authority set to true.
We then set the issuer to itself, as all certificates need an issuer, and we don't have one.
Then we tell the certificate to sign itself, with the private key (corresponding to its public key we've assigned) that we generated earlier, this part is important when signing certificates (or child certificates), they need to be signed with the private key of its parent (this prevents you from making fake certificates with a trusted certificate parent, as you don't have that trusted parent's private key)
Then we return the new certificate in a PEM-encoded format, you could save this to a file or convert it to a buffer and use it for a https server.
const forge = require('node-forge')
const crypto = require('crypto')
const pki = forge.pki
//using a blank options is perfectly fine here
async function genCACert(options = {}) {
options = {...{
commonName: 'Testing CA - DO NOT TRUST',
bits: 2048
}, ...options}
let keyPair = await new Promise((res, rej) => {
pki.rsa.generateKeyPair({ bits: options.bits }, (error, pair) => {
if (error) rej(error);
else res(pair)
})
})
let cert = pki.createCertificate()
cert.publicKey = keyPair.publicKey
cert.serialNumber = crypto.randomUUID().replace(/-/g, '')
cert.validity.notBefore = new Date()
cert.validity.notBefore.setDate(cert.validity.notBefore.getDate() - 1)
cert.validity.notAfter = new Date()
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1)
cert.setSubject([{name: 'commonName', value: options.commonName}])
cert.setExtensions([{ name: 'basicConstraints', cA: true }])
cert.setIssuer(cert.subject.attributes)
cert.sign(keyPair.privateKey, forge.md.sha256.create())
return {
ca: {
key: pki.privateKeyToPem(keyPair.privateKey),
cert: pki.certificateToPem(cert)
},
fingerprint: forge.util.encode64(
pki.getPublicKeyFingerprint(keyPair.publicKey, {
type: 'SubjectPublicKeyInfo',
md: forge.md.sha256.create(),
encoding: 'binary'
})
)
}
}
//you need to put the output from genCACert() through this if you want to use it for a https server
/* e.g
let cert = await genCACert();
let buffers = caToBuffer(cert.ca);
let options = {};
options.key = buffers.key;
options.cert = buffers.cert;
let server = https.createServer(options, <listener here>);
*/
function caToBuffer(ca) {
return {
key: Buffer.from(ca.key),
cert: Buffer.from(ca.cert)
}
}
Do with this what you will.
Okay, as you probably realized, I wasn't generating a certificate. It required quite a bit more work, which you can find here.
Essentially, after a bunch of setup, I had to create, sign, and convert the certificate to Pem:
cert.sign(keys.privateKey);
var pubKey = pki.certificateToPem(cert);
Hope this helps someone else!

Encrypting a file with Nodejs (Crypto) throw an error: bad base64 decode

Hello and sorry if my question is stupid, I'm just beginning on nodejs and bring a heavy luggage from PHP world.
I'm trying to encrypt a file using a public key generated through linux command line using the GnuPG command.
On my app I use Express, fs and Crypto to create a buffer from the file and get the public key content and then use publicEncrypt to get the encrypted data.
When I do so the application stops and throw an error complaining about the PEM format: bad base64 decode.
Error: error:0906D064:PEM routines:PEM_read_bio:bad base64 decode
Here you have the main parts of this code:
var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) {
var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
var publicKey = fs.readFileSync(absolutePath, "utf8");
if(typeof toEncrypt !=='object') return false;
var buffer = new Buffer(toEncrypt);
console.log(publicKey);
var encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
};
fs.readFile(req.files[0].path, function (err, data){
var encrypted = encryptStringWithRsaPublicKey(data, '/home/app/data/pub_key.txt');
if(!encrypted) {
fs.writeFile("/home/app/data/uploads/enc1/test.pdf", encrypted, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
res.end(req.files[0].filename);
});
}
else {
res.end({error:'encryption failed. all data deleted.'});
}
});
Maybe the Public Key has some end of line bad characters somewhere or maybe Crypto requires a very special format?
This is the content of the pub key:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFiFz2ABCADGk6E2IgbaGYIHO7EVNotxiDjB4k5UZJ4xx41RwY9LeG0c+SLW
rC/ijPFJZ/kN3nrpvTAZEYpnK51olqvw/OOgt5p3k32mW47HALx91vU9WRrykt2Y
DMj+aeMDi5QZnda8qTnWCW3E+OBg4W0ZdpwPs+eOyHWRjp6zuBFxZfrtKQuFlzHs
6KKczdGidemUQCZL7ve34EQmgeh4rDJ1oNC8QzSFOYZHiSVQDXGvZSFirc3OMZus
JiflY1Al3Y0fJj2m8catu/i9bKfAPA+YE+yU86BrgV05Skn82px2K3coiI/+eSjp
j/ROxijvwzLf/F98B3/AiMJjx8pD/9APmnSbABEBAAG0MVBheSBGaWxlIChDdWJl
IEluc3BpcmUpIDxwYXlmaWxlQGN1YmVpbnNwaXJlLmNvbT6JATgEEwECACIFAliF
z2ACGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEBeEp+MzfXEgefgH/0bJ
Oug/m66vlENqR+y6Z+mbC7RzFnhvojJ51EB6JlJe9EJ2VwtcirxorY5zL9DjTyB2
ys/kzdeN0+FmuIIO0To7ksB1ASZ5jsg1UdQEvLuLeSZSJRzbmz9M7jvxEfR+vz0h
RJPqs6EfgAOtRyDs8C/IXyWTrhu1wI+09CChjBH0/tCJ2sO074f4xMY1IYzf8nm7
ohuiGpN1egHOVjIjIajpmb94dGBXnbGNq/tzNwGZu9GUtaeTs3+kuqqy0+eIQDvR
7AU4Gt43etwpFz4dbWVDd77OxKUFshilaChIAwGmngfFn3ksnrl/AZVsGIJrxmy0
ja5t+yZOwl7KdC82SOa5AQ0EWIXPYAEIAOHRdsrEm/WFG3Fps++Mo6xUf/CFTyz3
WQr2nkOoBxAzcHPQd/3muDNKUblRhxZMrwuVZcnOZVOOz9rMqaM5kYSAB84PpVpG
26QcYFUn5WCmR3KSn9MiKqtSFJDn695ysaCdzzEW5Y/eKgxydG4rhFOy07VcKTev
dBC19XcukjxAbzmnZ7qUFhaRrS2u11mA+s0FmRz+EVOd0uxQdJq/Lps1nMvZ3UfL
saHJuBDgX+gCarbt+7uSx3aC/jBDzrq63Ry7nqN5mypSMRBeEAmi7kKToIRDj0Uj
xwqCgU4NVj8zCG2iBlOzrfKPk9oMLgHBvMPQYDW9wLz5rQnoVr4RkrUAEQEAAYkB
HwQYAQIACQUCWIXPYAIbDAAKCRAXhKfjM31xIBDYB/0VTjC/zvFHJwD5t+8DzHjN
UqPg7Mk0kYbu6dyPYb0/S2G5uZa3LoJ99EgOhgFlfUHM9k0GBC0OTxKiUEqKtENH
+W/wBouTltqGGyzDit+KlqzKz9gsyWF/HO3GTg1Df9D8o3MhUHRGjEeuik0BbJyd
Hy4YfDk5a4qUYtFztbmUSxVqdLlFBZ7oMn3n+A25HaDtohv9g1ZC3gTLD+yTTMsG
ruOEs6ZMIOENn6pgsjFdMIUmJVP3tt9n538jVfbVf7EgTrPt+JKjoQF3EfTysTnO
Y0IuotQuA83+5Fa6IY+iFLLvkNABr1WACVOKMUzBJJJG7EnlvgPufZL3eJE4LUZ9
=rpky
-----END PGP PUBLIC KEY BLOCK-----
I've found the solution to my problem.
In fact the method publicEncrypt is a wrapper of OpenSSL and then it expect a public/private key on that format. A key from GPG won't do it.
By generating the private and public keys with the following command the code work as expected:
$ openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
$ openssl rsa -pubout -in private_key.pem -out public_key.pem

Can nodejs generate SSL certificates?

I'm writing a proxy support HTTPS-HTTPS proxy. Before i use Python as the main programming language, but i'm interested in node.js now, so i prepare to migrate.
The largest problem i'm facing is that i don't know how to generate CA and other server certificates in node.js. In Python, there is pyOpenSSL which is awesome. I don't find something similar in node.js until now.
Maybe i should use openssl-fork method? But how to handle the interactive operation in openssl.
Thank you.
Use shell for certificate:
openssl genrsa -out server-key.pem 1024
openssl req -new -key server-key.pem -out server-csr.pem
openssl x509 -req -in server-csr.pem -signkey server-key.pem -out server-cert.pem
Then use them in node.js
var https = require('https');
https.createServer({
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem')
},
function (req,res) {
...
})
EDIT:
You can also give a try to this project in NPM :
https://npmjs.org/package/openssl-wrapper
I found it searching the NPM repo : https://npmjs.org/search?q=openssl
I did not tried or checked it myself, but it looks like a way to generate the certificate using node, which is the original question.
var openssl = require('openssl-wrapper');
var password = 'github';
return openssl.exec('genrsa', {des3: true, passout: 'pass:' + password, '2048': false}, function(err, buffer) {
console.log(buffer.toString());
});
I'd be interested by a feedback. ;)
In case somebody does want to programatically create CSRs from node.js, I have created a nodejs module which uses openssl to create a private key and a CSR.
Edit: Use pem instead. It is much more complete and probably more reliable.
Edit2: Actually, pem is also just a simple wrapper over openssh. For a pure js implementation, look into forge
node-forge allow that. Nothing to say more. DOES NOT use openssl shell command internally.
https://github.com/digitalbazaar/forge#x509
there is a pure javascript library called "Jsrsasign" to generate CSR certificates.
const r = require("jsrsasign");
const kp = r.KEYUTIL.generateKeypair("RSA", 2048);
const csr = r.KJUR.asn1.csr.CSRUtil.newCSRPEM({
subject: {},
sbjpubkey: kp.pubKeyObj,
sigalg: "SHA256withRSA",
sbjprvkey: kp.prvKeyObj,
});
const privateKey = r.KEYUTIL.getPEM(kp.prvKeyObj, "PKCS1PRV");
for more docs visit http://kjur.github.io/jsrsasign/
None of the node libraries seem to support the options I need, so I use the openssl executable.
import { execSync } from 'child_process'
import fs from 'fs'
import tempy from 'tempy'
const extHeader = `authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = #alt_names
[alt_names]
`
const shell = cmd => execSync(cmd, { stdio: 'pipe' })
const writeCert = (extFile, outfile) => {
const cmd = [
`openssl`,
`x509`,
`-req`,
`-in ssl/my.csr`,
`-CA ssl/root-ca.pem`,
`-CAkey ssl/root-ca.key`,
`-CAserial ssl/root-ca.srl`,
`-out ssl/${outfile}`,
`-days 1825`,
`-sha256`,
`-extfile ${extFile}`,
`-passin pass:mypassphrase`
]
shell(cmd.join(' '))
}
const createCert = domains => {
const sans = domains.map((d, i) => `DNS.${i + 1} = ${d}`)
const ext = extHeader + sans.join('\n')
const extFile = tempy.file()
fs.writeFileSync(extFile, ext, 'utf-8')
writeCert(extFile, 'out.crt')
}
Dependencies:
openssl executable
yarn add tempy

Resources