Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

pem

Package Overview
Dependencies
Maintainers
1
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pem - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

289

lib/pem.js

@@ -1,2 +0,7 @@

var spawn = require("child_process").spawn;
var spawn = require("child_process").spawn,
os = require("os"),
pathlib = require("path"),
fs = require("fs"),
crypto = require("crypto"),
tempDir = (os.tmpdir || os.tmpDir) && (os.tmpdir || os.tmpDir)() || "/tmp";

@@ -8,2 +13,3 @@ module.exports.createPrivateKey = createPrivateKey;

module.exports.getPublicKey = getPublicKey;
module.exports.getFingerprint = getFingerprint;

@@ -14,3 +20,3 @@ // PUBLIC API

* Creates a private key
*
*
* @param {Number} [keyBitsize=1024] Size of the key, defaults to 1024bit

@@ -24,3 +30,3 @@ * @param {Function} callback Callback function with an error object and {key}

}
keyBitsize = Number(keyBitsize) || 1024;

@@ -33,3 +39,3 @@

];
execOpenSSL(params, "RSA PRIVATE KEY", function(error, key){

@@ -45,6 +51,6 @@ if(error){

* Creates a Certificate Signing Request
*
*
* If client key is undefined, a new key is created automatically. The used key is included
* in the callback return as clientKey
*
*
* @param {Object} [options] Optional options object

@@ -68,5 +74,5 @@ * @param {String} [options.clientKey] Optional client key to use

}
options = options || {};
if(!options.clientKey){

@@ -82,3 +88,3 @@ createPrivateKey(options.keyBitsize || 1024, function(error, keyData){

}
var params = ["req",

@@ -90,5 +96,5 @@ "-new",

"-key",
"/dev/stdin"
"--TMPFILE--"
];
execOpenSSL(params, "CERTIFICATE REQUEST", options.clientKey, function(error, data){

@@ -103,3 +109,3 @@ if(error){

return callback(null, response);
});

@@ -112,3 +118,3 @@ }

* can be used as with createCSR.
*
*
* @param {Object} [options] Optional options object

@@ -126,5 +132,5 @@ * @param {String} [options.serviceKey] Private key for signing the certificate, if not defined a new one is generated

}
options = options || {};
if(!options.csr){

@@ -141,5 +147,5 @@ createCSR(options, function(error, keyData){

}
if(!options.serviceKey){
if(options.selfSigned){

@@ -158,3 +164,3 @@ options.serviceKey = options.clientKey;

}
var params = ["x509",

@@ -165,8 +171,24 @@ "-req",

"-in",
"/dev/stdin",
"-signkey",
"/dev/stdin"
"--TMPFILE--"
];
var tmpfiles = [options.csr];
if (options.serviceCertificate) {
if (!options.serial) {
return callback(new Error("serial option required for CA signing"));
}
params.push("-CA");
params.push("--TMPFILE--");
params.push("-CAkey");
params.push("--TMPFILE--");
params.push("-set_serial");
params.push("0x" + ("00000000" + options.serial.toString(16)).slice(-8));
tmpfiles.push(options.serviceCertificate)
tmpfiles.push(options.serviceKey)
} else {
params.push("-signkey");
params.push("--TMPFILE--");
tmpfiles.push(options.serviceKey)
}
execOpenSSL(params, "CERTIFICATE", [options.csr, options.serviceKey], function(error, data){
execOpenSSL(params, "CERTIFICATE", tmpfiles, function(error, data){
if(error){

@@ -187,3 +209,3 @@ return callback(error);

* Exports a public key from a private key, CSR or certificate
*
*
* @param {String} certificate PEM encoded private key, CSR or certificate

@@ -197,11 +219,11 @@ * @param {Function} callback Callback function with an error object and {publicKey}

}
certificate = (certificate || "").toString();
var params;
if(certificate.match(/BEGIN CERTIFICATE REQUEST/)){
params = ["req",
"-in",
"/dev/stdin",
"--TMPFILE--",
"-pubkey",

@@ -212,3 +234,3 @@ "-noout"];

"-in",
"/dev/stdin",
"--TMPFILE--",
"-pubout"];

@@ -218,3 +240,3 @@ }else{

"-in",
"/dev/stdin",
"--TMPFILE--",
"-pubkey",

@@ -234,3 +256,3 @@ "-noout"];

* Reads subject data from a certificate or a CSR
*
*
* @param {String} certificate PEM encoded CSR or certificate

@@ -244,5 +266,5 @@ * @param {Function} callback Callback function with an error object and {country, state, locality, organization, organizationUnit, commonName, emailAddress}

}
certificate = (certificate || "").toString();
var type = certificate.match(/BEGIN CERTIFICATE REQUEST/)?"req":"x509",

@@ -253,28 +275,35 @@ params = [type,

"-in",
"/dev/stdin"
],
openssl = spawn("openssl", params),
stdout = "",
stderr = "";
openssl.stdin.write(certificate);
openssl.stdin.end();
openssl.stdout.on('data', function (data) {
stdout += (data || "").toString("binary");
"--TMPFILE--"
];
spawnWrapper(params, certificate, function(err, code, stdout, stderr){
if (err) {
return callback(err);
}
return fetchCertificateData(stdout, callback);
});
}
openssl.stderr.on('data', function (data) {
stderr += (data || "").toString("binary");
});
/**
* Gets the fingerprint for a certificate
*
* @param {String} PEM encoded certificate
* @param {Function} callback Callback function with an error object and {fingerprint}
*/
function getFingerprint(certificate, callback){
var params = ["x509",
"-in",
"--TMPFILE--",
"-fingerprint",
"-noout"];
openssl.on('exit', function (code) {
if(code){
return callback(new Error("Invalid openssl exit code "+code));
spawnWrapper(params, certificate, function(err, code, stdout, stderr){
if (err) {
return callback(err);
}
stdout = new Buffer(stdout, "binary").toString("utf-8");
stderr = new Buffer(stderr, "binary").toString("utf-8");
return fetchCertificateData(stdout, callback);
var match = stdout.match(/Fingerprint=([0-9a-fA-F:]+)$/m);
if (match){
return callback(null, {fingerprint: match[1]});
} else {
return callback(new Error("No fingerprint"));
}
});

@@ -287,5 +316,5 @@ }

certData = (certData || "").toString();
var subject, extra, tmp, certValues = {};
if((subject = certData.match(/Subject:([^\n]*)\n/)) && subject.length>1){

@@ -325,3 +354,3 @@ subject = subject[1];

options = options || {};
var csrData = {

@@ -337,3 +366,3 @@ C: options.country || options.C || "",

csrBuilder = [];
Object.keys(csrData).forEach(function(key){

@@ -344,3 +373,3 @@ if(csrData[key]){

});
return csrBuilder.join("");

@@ -350,33 +379,13 @@ }

/**
* Spawn an openssl command
* Generically spawn openSSL, without processing the result
*
* @param {Array} params The parameters to pass to openssl
* @param {String|Array} tmpfiles Stuff to pass to tmpfiles
* @param {Function} callback Called with (error, exitCode, stdout, stderr)
*/
function execOpenSSL(params, searchStr, stdin, callback){
function spawnOpenSSL(params, callback) {
var openssl = spawn("openssl", params),
stdout = "",
stderr = "",
pushToStdin = function(){
var data = stdin.shift();
if(data){
openssl.stdin.write(data + "\n");
if(!stdin.length){
openssl.stdin.end();
}
}
};
if(!callback && typeof stdin == "function"){
callback = stdin;
stdin = false;
}
if(stdin){
if(Array.isArray(stdin)){
pushToStdin();
}else{
openssl.stdin.write(stdin);
openssl.stdin.end();
}
}
stderr = "";
openssl.stdout.on('data', function (data) {

@@ -388,17 +397,96 @@ stdout += (data || "").toString("binary");

stderr += (data || "").toString("binary");
if(Array.isArray(stdin)){
pushToStdin();
});
// We need both the return code and access to all of stdout. Stdout isn't
// *really* available until the close event fires; the timing nuance was
// making this fail periodically.
var needed = 2; // wait for both exit and close.
var code = -1;
var bothDone = function() {
if (code) {
callback(new Error("Invalid openssl exit code: " + code + "\n% openssl " + params.join(" ") + "\n" + stderr), code);
} else {
callback(null, code, stdout, stderr);
}
};
openssl.on('exit', function (ret) {
code = ret;
if (--needed < 1) {
bothDone();
}
});
openssl.on('exit', function (code) {
var start, end;
openssl.on('close', function () {
stdout = new Buffer(stdout, "binary").toString("utf-8");
stderr = new Buffer(stderr, "binary").toString("utf-8");
if(code){
return callback(new Error("Invalid openssl exit code "+code+"\nSTDOUT:\n"+stdout+"\nSTDERR:\n"+stderr));
if (--needed < 1) {
bothDone();
}
});
}
function spawnWrapper(params, tmpfiles, callback){
var files = [];
if(tmpfiles){
tmpfiles = [].concat(tmpfiles || []);
params.forEach(function(value, i){
var fname;
if(value == "--TMPFILE--"){
fpath = pathlib.join(tempDir, crypto.randomBytes(20).toString("hex"));
files.push({
path: fpath,
contents: tmpfiles.shift()
});
params[i] = fpath;
}
})
}
var processFiles = function(){
var file = files.shift();
if(!file){
return spawnSSL();
}
fs.writeFile(file.path, file.contents, function(err, bytes){
processFiles();
});
}
var spawnSSL = function(){
spawnOpenSSL(params, function(err, code, stdout, stderr) {
var start, end;
files.forEach(function(file){
fs.unlink(file.path);
})
callback(err, code, stdout, stderr);
});
}
processFiles();
}
/**
* Spawn an openssl command
*/
function execOpenSSL(params, searchStr, tmpfiles, callback){
if(!callback && typeof tmpfiles == "function"){
callback = tmpfiles;
tmpfiles = false;
}
spawnWrapper(params, tmpfiles, function(err, code, stdout, stderr) {
var start, end;
if (err) {
return callback(err);
}
if((start = stdout.match(new RegExp("\\-+BEGIN "+searchStr+"\\-+$", "m")))){

@@ -409,3 +497,3 @@ start = start.index;

}
if((end = stdout.match(new RegExp("^\\-+END "+searchStr+"\\-+", "m")))){

@@ -416,10 +504,9 @@ end = end.index + (end[0] || "").length;

}
if(start >= 0 && end >=0){
return callback(null, stdout.substring(start, end));
}else{
return callback(new Error(searchStr + " not found from openssl output"));
return callback(new Error(searchStr + " not found from openssl output:\n---stdout---\n" + stdout + "\n---stderr---\n" + stderr + "\ncode: " + code + "\nsignal: " + signal));
}
});
}
}

@@ -5,3 +5,3 @@ {

"description": "Create private keys and certificates with node.js",
"version": "0.1.0",
"version": "0.2.0",
"repository": {

@@ -8,0 +8,0 @@ "type": "git",

@@ -8,4 +8,2 @@ pem

**NB!** This module does not yet support node v0.7+/0.8 or Windows. Sorry.
## Installation

@@ -97,4 +95,15 @@

### Get fingerprint
Use `getFingerprint` to get the SHA1 fingerprint for a certificate
pem.getFingerprint(certificate, callback)
Where
* **certificate** is a PEM encoded certificate
* **callback** is a callback function with an error object and `{fingerprint}`
## License
**MIT**
**MIT**

@@ -17,3 +17,3 @@ var pem = require(".."),

},
"Create 2048bit Private key": function(test){

@@ -30,3 +30,3 @@ pem.createPrivateKey(2048, function(error, data){

},
"Create default CSR": function(test){

@@ -39,13 +39,13 @@ pem.createCSR(function(error, data){

test.ok(csr.match(/\n\-\-\-\-\-END CERTIFICATE REQUEST\-\-\-\-\-\n*$/));
test.ok(data && data.clientKey);
test.done();
});
},
"Create CSR with own key": function(test){
pem.createPrivateKey(function(error, data){
var key = (data && data.key || "").toString();
pem.createCSR({clientKey: key}, function(error, data){

@@ -57,13 +57,13 @@ var csr = (data && data.csr || "").toString();

test.ok(csr.match(/\n\-\-\-\-\-END CERTIFICATE REQUEST\-\-\-\-\-\n*$/));
test.equal(data && data.clientKey, key);
test.ok(data && data.clientKey);
test.done();
});
});
},
"Create default certificate": function(test){

@@ -76,13 +76,13 @@ pem.createCertificate(function(error, data){

test.ok(certificate.match(/\n\-\-\-\-\-END CERTIFICATE\-\-\-\-\-\n*$/));
test.ok((data && data.clientKey) != (data && data.serviceKey));
test.ok(data && data.clientKey);
test.ok(data && data.serviceKey);
test.ok(data && data.csr);
test.done();
});
},
"Create self signed certificate": function(test){

@@ -95,13 +95,13 @@ pem.createCertificate({selfSigned: true}, function(error, data){

test.ok(certificate.match(/\n\-\-\-\-\-END CERTIFICATE\-\-\-\-\-\n*$/));
test.ok((data && data.clientKey) == (data && data.serviceKey));
test.ok(data && data.clientKey);
test.ok(data && data.serviceKey);
test.ok(data && data.csr);
test.done();
});
},
"Read default cert data from CSR": function(test){

@@ -111,3 +111,3 @@ pem.createCSR(function(error, data){

test.ifError(error);
pem.readCertificateInfo(csr, function(error, data){

@@ -127,10 +127,10 @@ test.ifError(error);

},
"Read edited cert data from CSR": function(test){
var certInfo = {country:"EE",
state:"Harjumaa",
locality:"Tallinn",
organization:"Node.ee",
organizationUnit:"test",
commonName:"www.node.ee",
var certInfo = {country:"EE",
state:"Harjumaa",
locality:"Tallinn",
organization:"Node.ee",
organizationUnit:"test",
commonName:"www.node.ee",
emailAddress:"andris@node.ee"};

@@ -140,3 +140,3 @@ pem.createCSR(Object.create(certInfo), function(error, data){

test.ifError(error);
pem.readCertificateInfo(csr, function(error, data){

@@ -149,3 +149,3 @@ test.ifError(error);

},
"Read default cert data from certificate": function(test){

@@ -155,3 +155,3 @@ pem.createCertificate(function(error, data){

test.ifError(error);
pem.readCertificateInfo(certificate, function(error, data){

@@ -171,10 +171,10 @@ test.ifError(error);

},
"Read edited cert data from certificate": function(test){
var certInfo = {country:"EE",
state:"Harjumaa",
locality:"Tallinn",
organization:"Node.ee",
organizationUnit:"test",
commonName:"www.node.ee",
var certInfo = {country:"EE",
state:"Harjumaa",
locality:"Tallinn",
organization:"Node.ee",
organizationUnit:"test",
commonName:"www.node.ee",
emailAddress:"andris@node.ee"};

@@ -184,3 +184,3 @@ pem.createCertificate(Object.create(certInfo), function(error, data){

test.ifError(error);
pem.readCertificateInfo(certificate, function(error, data){

@@ -193,3 +193,3 @@ test.ifError(error);

},
"Get public key from private key": function(test){

@@ -200,3 +200,3 @@ pem.createPrivateKey(function(error, data){

test.ok(key);
pem.getPublicKey(key, function(error, data){

@@ -206,12 +206,12 @@ var pubkey = (data && data.publicKey || "").toString();

test.ok(pubkey);
test.ok(pubkey.match(/^\n*\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-\n/));
test.ok(pubkey.match(/\n\-\-\-\-\-END PUBLIC KEY\-\-\-\-\-\n*$/));
test.done();
});
});
},
"Get public key from CSR": function(test){

@@ -222,3 +222,3 @@ pem.createCSR(function(error, data){

test.ok(key);
pem.getPublicKey(key, function(error, data){

@@ -228,12 +228,12 @@ var pubkey = (data && data.publicKey || "").toString();

test.ok(pubkey);
test.ok(pubkey.match(/^\n*\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-\n/));
test.ok(pubkey.match(/\n\-\-\-\-\-END PUBLIC KEY\-\-\-\-\-\n*$/));
test.done();
});
});
},
"Get public key from certificate": function(test){

@@ -244,3 +244,3 @@ pem.createCertificate(function(error, data){

test.ok(key);
pem.getPublicKey(key, function(error, data){

@@ -250,11 +250,29 @@ var pubkey = (data && data.publicKey || "").toString();

test.ok(pubkey);
test.ok(pubkey.match(/^\n*\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-\n/));
test.ok(pubkey.match(/\n\-\-\-\-\-END PUBLIC KEY\-\-\-\-\-\n*$/));
test.done();
});
});
},
"Get fingerprint from certificate": function(test){
pem.createCertificate(function(error, data){
var certificate = (data && data.certificate || "").toString();
test.ifError(error);
test.ok(certificate);
pem.getFingerprint(certificate, function(error, data){
var fingerprint = (data && data.fingerprint || "").toString();
test.ifError(error);
test.ok(fingerprint);
test.ok(fingerprint.match(/^[0-9A-F]{2}(:[0-9A-F]{2}){19}$/));
test.done();
});
});
}
};
};

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc