diff --git a/lib/pem.js b/lib/pem.js index 20a75722..f6038a38 100644 --- a/lib/pem.js +++ b/lib/pem.js @@ -18,6 +18,7 @@ module.exports.readCertificateInfo = readCertificateInfo; module.exports.getPublicKey = getPublicKey; module.exports.getFingerprint = getFingerprint; module.exports.getModulus = getModulus; +module.exports.getModulusFromProtected = getModulusFromProtected; module.exports.config = config; // PUBLIC API @@ -56,9 +57,9 @@ function createPrivateKey(keyBitsize, options, callback) { params.push( '-passout' ); params.push( 'file:' + clientKeyPassword ); } - + params.push(keyBitsize); - + execOpenSSL(params, 'RSA PRIVATE KEY', function(error, key) { if(clientKeyPassword) { fs.unlink(clientKeyPassword); @@ -400,7 +401,7 @@ function getModulus(certificate, callback) { var type = ''; if (certificate.match(/BEGIN(\sNEW)? CERTIFICATE REQUEST/)) { type = 'req'; - } else if (certificate.match(/BEGIN RSA PRIVATE KEY/)) { + } else if (certificate.match(/BEGIN RSA PRIVATE KEY/) || certificate.match(/BEGIN PRIVATE KEY/)) { type = 'rsa'; } else { type = 'x509'; @@ -426,6 +427,44 @@ function getModulus(certificate, callback) { }); } +function getModulusFromProtected(key, password, callback){ + key = Buffer.isBuffer(key) && key.toString() || key; + + var type = ''; + if (key.match(/BEGIN(\sNEW)? CERTIFICATE REQUEST/)) { + type = 'req'; + } else if (key.match(/BEGIN RSA PRIVATE KEY/) || key.match(/BEGIN PRIVATE KEY/)) { + type = 'rsa'; + } else { + type = 'x509'; + } + var params = [type, + '-noout', + '-modulus', + '-in', + '--TMPFILE--' + ]; + + if (password) { + params.push( '-passin'); + params.push( 'pass:' + password); + } + + spawnWrapper(params, key, function(err, code, stdout) { + if (err) { + return callback(err); + } + var match = stdout.match(/Modulus=([0-9a-fA-F]+)$/m); + if (match) { + return callback(null, { + modulus: match[1] + }); + } else { + return callback(new Error('No modulus')); + } + }); +} + /** * config the pem module * @param {Object} options @@ -788,4 +827,4 @@ function testOpenSSLPath(pathBin, callback) { callback(); }); -} \ No newline at end of file +} diff --git a/test/fixtures/test.crt b/test/fixtures/test.crt new file mode 100644 index 00000000..3c146c56 --- /dev/null +++ b/test/fixtures/test.crt @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIChTCCAe4CCQDbGP0P9s69azANBgkqhkiG9w0BAQsFADCBhjELMAkGA1UEBhMC +WlcxGzAZBgNVBAgMEk1hdGViZWxlbGFuZCBOb3J0aDERMA8GA1UEBwwIQnVsYXdh +eW8xDDAKBgNVBAoMA0J5bzELMAkGA1UECwwCSVQxDzANBgNVBAMMBmJ5by56dzEb +MBkGCSqGSIb3DQEJARYMYWRtaW5AYnlvLnp3MB4XDTE1MDQxMDA5NTM1OVoXDTE2 +MDQwOTA5NTM1OVowgYYxCzAJBgNVBAYTAlpXMRswGQYDVQQIDBJNYXRlYmVsZWxh +bmQgTm9ydGgxETAPBgNVBAcMCEJ1bGF3YXlvMQwwCgYDVQQKDANCeW8xCzAJBgNV +BAsMAklUMQ8wDQYDVQQDDAZieW8uencxGzAZBgkqhkiG9w0BCQEWDGFkbWluQGJ5 +by56dzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0q4cDxLRslRKvG2pw5Gx +7fsq7YyiTokoBaDavNold5Vvayi02Mc7dqIanr/ckc0AqgiDd5Kw2bBAYmQpWiDn +pZxp79JIV+gGh7pkiB4wDzvRBXMcew72B9uuYEeUQ8eonE/Yro0ZnD0ZGmBiuk/6 +5xyWNikBhfPLnb2V+Cr/EKsCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAwigr+o+Y+ +5BiL6MuHLTaC+lcv9r2GTHb7wNea674Db3Bi3u6FgmyMsZ8npPSlR0t/YZcFWtRM +y4uXmw5zUutGZTbO/JFxts6kPV+a76mnNm71fF4QINkemmojvJyPZq9N+hV16dba +v1m+dTK7hDZvpd/sM5bMtqWEq4aHkGhujw== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/test/fixtures/test.csr b/test/fixtures/test.csr new file mode 100644 index 00000000..7851a725 --- /dev/null +++ b/test/fixtures/test.csr @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIB3jCCAUcCAQAwgYYxCzAJBgNVBAYTAlpXMRswGQYDVQQIDBJNYXRlYmVsZWxh +bmQgTm9ydGgxETAPBgNVBAcMCEJ1bGF3YXlvMQwwCgYDVQQKDANCeW8xCzAJBgNV +BAsMAklUMQ8wDQYDVQQDDAZieW8uencxGzAZBgkqhkiG9w0BCQEWDGFkbWluQGJ5 +by56dzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0q4cDxLRslRKvG2pw5Gx +7fsq7YyiTokoBaDavNold5Vvayi02Mc7dqIanr/ckc0AqgiDd5Kw2bBAYmQpWiDn +pZxp79JIV+gGh7pkiB4wDzvRBXMcew72B9uuYEeUQ8eonE/Yro0ZnD0ZGmBiuk/6 +5xyWNikBhfPLnb2V+Cr/EKsCAwEAAaAXMBUGCSqGSIb3DQEJAjEIDAZCeW8gQ28w +DQYJKoZIhvcNAQELBQADgYEAxP+4Z2POlTlCBYpGhhKpTBbRDeAQakXqGBlB7ZC2 +0K4fSxuAGVArLV5rbPDHlzNCtmF8mvt55F7zVny4YQ8BHE7ujV3SWtiAr0Otq9VV +WG5LmBLAbyrrUZloHJEpX0wPgQDmMdLhkDkbcjcKOT6WKNW5q36MW+Q9nViStGD5 +lJg= +-----END CERTIFICATE REQUEST----- \ No newline at end of file diff --git a/test/fixtures/test.key b/test/fixtures/test.key new file mode 100644 index 00000000..ec1c5ece --- /dev/null +++ b/test/fixtures/test.key @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,8D7649F2550A3AD6 + +iD68IbbRZDJuiYBqiEMLSfQQqcbXr4CeHFVkAYxCKN785tg+icShBeYXP2H2Oa7m +dmFBNrtuPclUjk1VFeDcRhd1WwabuSbKJkV26bqIwYKSa1blDcgviSvIc8OgN06G +K7kX+3jQzUMeSj+B1phyysCSoSU059oJvcNknBOEe67ersYZhXWFDOxVOeCnpsVA +xDPRGVWa5g5jj0WqcXey/oC/hUccX8w8RZJLSBurIxfWBGy1QtsnopNRaxs5gqXj +FCucQtYTMwRzA0c65/6yDrYrnv3v0mmCKBKXoTvhcmxkE/Ejrk0+ydxlgWXoMjOD +CzuDy8xQ2KN2/62fb0Eb6LwnI3EHceXAO9GbgpCTXDZt0yoKMBDZFYA1+TuYBXJj +RRcKDcF+gt1VdloSkAWIaDwypnPi0xngsJbzNIHKoSKYPuxWdUXB5rThbSdPki5x +r8La88LBK6/WarJevce8Ggg/KCAx5ng/w9XzQDlMSNVT6Ht+gGe6+69XjBA5IyIo +bymu9PlwRMMYEeEcH53tGXcCgSkzlDs2Cc+1+JUypZpX4oggNV5YhsmLZS5BtPFs +9i3lA7RsxXoV0u1BTgHIqrH58IKaXN9xs0ceie3cLR5tcSiSsU9sh3wpjZ2AZ/Q5 +zjoHuyzQVxY14qlE3uWzI9vJtc/kCkQ4D8wdBRVM8uRzf+YGYKRbI6vvsSICeLuW +n82E2zin77HnIOGVHPJ5aNaTQD91Ubxxv7lVeuxZf2tgejs2DbJraKOtOmHLd9GA +Zb5G9TdFMxVcXq18xUMm/Rbkj8ugALxRy8CGNSrTFTPHaEwYxqhnAQ== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/test/pem.js b/test/pem.js index b9643fc7..09c08f88 100644 --- a/test/pem.js +++ b/test/pem.js @@ -3,6 +3,7 @@ var pem = require('..'); var fs = require('fs'); + process.env.PEMJS_TMPDIR = './tmp'; try { @@ -404,6 +405,28 @@ exports['General Tests'] = { }); }); }, + 'Get modulus from a protected key': function(test) { + var certificate = fs.readFileSync('./test/fixtures/test.crt').toString(); + var key = fs.readFileSync('./test/fixtures/test.key').toString(); + + pem.getModulus(certificate, function(error, data) { + var certmodulus = (data && data.modulus || '').toString(); + test.ifError(error); + test.ok(certmodulus); + test.ok(certmodulus.match(/^[0-9A-F]*$/)); + test.ok(fs.readdirSync('./tmp').length === 0); + pem.getModulusFromProtected(key, 'password' ,function(error, data) { + var keymodulus = (data && data.modulus || '').toString(); + test.ifError(error); + test.ok(keymodulus); + test.ok(keymodulus.match(/^[0-9A-F]*$/)); + test.ok(keymodulus === certmodulus); + test.ok(fs.readdirSync('./tmp').length === 0); + test.done(); + }); + }); + + }, 'Create and verify wildcard certificate': function(test) { var certInfo = { commonName: '*.node.ee'