diff --git a/src/formats/pkcs1.js b/src/formats/pkcs1.js index d481810..c34a748 100644 --- a/src/formats/pkcs1.js +++ b/src/formats/pkcs1.js @@ -2,6 +2,30 @@ var ber = require('asn1').Ber; var _ = require('../utils')._; var utils = require('../utils'); +const PRIVATE_OPENING_BOUNDARY = '-----BEGIN RSA PRIVATE KEY-----'; +const PRIVATE_CLOSING_BOUNDARY = '-----END RSA PRIVATE KEY-----'; + +const PUBLIC_OPENING_BOUNDARY = '-----BEGIN RSA PUBLIC KEY-----'; +const PUBLIC_CLOSING_BOUNDARY = '-----END RSA PUBLIC KEY-----'; + +/** + * Strips everything around the opening and closing lines, including the lines + * themselves. + */ +function trimSurroundingText(data, opening, closing) { + let openingBoundaryIndex = data.indexOf(opening); + if (openingBoundaryIndex < 0) { + throw Error('Unsupported key format - Missing BEGIN line'); + } + + let closingBoundaryIndex = data.indexOf(closing, openingBoundaryIndex); + if (closingBoundaryIndex < 0) { + throw Error('Unsupported key format - Missing END line'); + } + + return data.substring(openingBoundaryIndex + opening.length, closingBoundaryIndex); +} + module.exports = { privateExport: function (key, options) { options = options || {}; @@ -46,8 +70,7 @@ module.exports = { } if (_.isString(data)) { - var pem = data.replace('-----BEGIN RSA PRIVATE KEY-----', '') - .replace('-----END RSA PRIVATE KEY-----', '') + let pem = trimSurroundingText(data, PRIVATE_OPENING_BOUNDARY, PRIVATE_CLOSING_BOUNDARY) .replace(/\s+|\n\r|\n|\r$/gm, ''); buffer = Buffer.from(pem, 'base64'); } else { @@ -103,8 +126,7 @@ module.exports = { } if (_.isString(data)) { - var pem = data.replace('-----BEGIN RSA PUBLIC KEY-----', '') - .replace('-----END RSA PUBLIC KEY-----', '') + var pem = trimSurroundingText(data, PUBLIC_OPENING_BOUNDARY, PUBLIC_CLOSING_BOUNDARY) .replace(/\s+|\n\r|\n|\r$/gm, ''); buffer = Buffer.from(pem, 'base64'); } @@ -128,12 +150,13 @@ module.exports = { * @param data */ autoImport: function (key, data) { - if (/^\s*-----BEGIN RSA PRIVATE KEY-----\s*(?=(([A-Za-z0-9+/=]+\s*)+))\1-----END RSA PRIVATE KEY-----\s*$/g.test(data)) { + // [\S\s]* matches zero or more of any character + if (/^[\S\s]*-----BEGIN RSA PRIVATE KEY-----\s*(?=(([A-Za-z0-9+/=]+\s*)+))\1-----END RSA PRIVATE KEY-----[\S\s]*$/g.test(data)) { module.exports.privateImport(key, data); return true; } - if (/^\s*-----BEGIN RSA PUBLIC KEY-----\s*(?=(([A-Za-z0-9+/=]+\s*)+))\1-----END RSA PUBLIC KEY-----\s*$/g.test(data)) { + if (/^[\S\s]*-----BEGIN RSA PUBLIC KEY-----\s*(?=(([A-Za-z0-9+/=]+\s*)+))\1-----END RSA PUBLIC KEY-----[\S\s]*$/g.test(data)) { module.exports.publicImport(key, data); return true; } diff --git a/test/tests.js b/test/tests.js index 298adcb..b54d535 100644 --- a/test/tests.js +++ b/test/tests.js @@ -336,6 +336,21 @@ describe('NodeRSA', function () { assert.equal(key.exportKey(), fileKeyPKCS1); }); + it('should gracefully handle data outside of encapsulation boundaries for private keys', function () { + let privateFileWithNoise = 'Lorem ipsum' + fs.readFileSync(keysFolder + 'private_pkcs1.pem') + 'dulce et decorum'; + let key = new NodeRSA(privateFileWithNoise); + assert.equal(key.exportKey(), fileKeyPKCS1); + }); + + it('should gracefully handle data outside of encapsulation boundaries for public keys', function () { + let publicFileWithNoise = 'Lorem ipsum' + fs.readFileSync(keysFolder + 'public_pkcs1.pem') + 'dulce et decorum'; + let publicNodeRSA = new NodeRSA(publicFileWithNoise); + assert.instanceOf(privateNodeRSA.keyPair, Object); + assert(publicNodeRSA.isPublic()); + assert(publicNodeRSA.isPublic(true)); + assert(!publicNodeRSA.isPrivate()); + }); + it('.importKey() from private components', function () { var key = new NodeRSA(); key.importKey({