Skip to content

Commit 03b9293

Browse files
Merge pull request #75 from Mastercard/fix/S5026407-cleanup-decryption-config
cleanup decryption key handling
2 parents 90f5811 + ec7d74a commit 03b9293

10 files changed

+118
-83
lines changed

lib/mcapi/crypto/field-level-crypto.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ function validateFingerprint(config, contains) {
258258
config[propertiesFingerprint[0]] !== "publicKey"
259259
) {
260260
throw Error(
261-
"Config not valid: propertiesFingerprint should be: 'certificate' or 'publicKey'"
261+
`Config not valid: ${propertiesFingerprint[0]} should be: 'certificate' or 'publicKey'`
262262
);
263263
}
264264
}

lib/mcapi/utils/utils.js

+30-50
Original file line numberDiff line numberDiff line change
@@ -195,25 +195,40 @@ function deleteRoot(obj, paths, properties) {
195195

196196
module.exports.getPrivateKey = function (config) {
197197
if (config.privateKey) {
198-
return loadPrivateKey(config.privateKey);
199-
} else if (config.keyStore) {
200-
if (config.keyStore.includes(".p12")) {
198+
return getUnencryptedPrivateKey(config.privateKey);
199+
}
200+
201+
if (config.keyStore) {
202+
if (config.keyStore.includes(".p12") || (config.keyStoreAlias && config.keyStorePassword)) {
201203
return getPrivateKey12(
202204
config.keyStore,
203205
config.keyStoreAlias,
204206
config.keyStorePassword
205207
);
206208
}
207-
if (config.keyStore.includes(".pem")) {
208-
return getPrivateKeyPem(config.keyStore);
209-
}
210-
if (config.keyStore.includes(".der")) {
211-
return getPrivateKeyDer(config.keyStore);
212-
}
209+
210+
return getUnencryptedPrivateKey(config.keyStore);
213211
}
212+
214213
return null;
215214
};
216215

216+
function getUnencryptedPrivateKey(filePath) {
217+
const fileContent = fs.readFileSync(filePath);
218+
219+
if (!fileContent || fileContent.length < 1) {
220+
throw new Error("private key file content is empty");
221+
}
222+
223+
// key is PEM
224+
if(fileContent.toString('utf-8').startsWith("-----BEGIN")) {
225+
return forge.pki.privateKeyFromPem(fileContent.toString('utf-8'));
226+
}
227+
228+
// attempt to read DER
229+
return forge.pki.privateKeyFromAsn1(forge.asn1.fromDer(fileContent.toString('binary')));
230+
}
231+
217232
function getPrivateKey12(p12Path, alias, password) {
218233
const p12Content = fs.readFileSync(p12Path, "binary");
219234

@@ -248,40 +263,6 @@ function getPrivateKey12(p12Path, alias, password) {
248263
return keyObj.key;
249264
}
250265

251-
function getPrivateKeyPem(pemPath) {
252-
let pemContent = fs.readFileSync(pemPath, "binary");
253-
254-
if (!pemContent || pemContent.length <= 1) {
255-
throw new Error("pem keystore content is empty");
256-
}
257-
258-
pemContent = pemContent.replace("\n", "");
259-
pemContent = pemContent.replace("\r\n", "");
260-
261-
return forge.pki.privateKeyFromPem(pemContent);
262-
}
263-
264-
function getPrivateKeyDer(derPath) {
265-
const derContent = fs.readFileSync(derPath, "binary");
266-
267-
if (!derContent || derContent.length <= 1) {
268-
throw new Error("der keystore content is empty");
269-
}
270-
271-
const pkeyAsn1 = forge.asn1.fromDer(derContent);
272-
return forge.pki.privateKeyFromAsn1(pkeyAsn1);
273-
}
274-
275-
function loadPrivateKey(privateKeyPath) {
276-
const privateKeyContent = fs.readFileSync(privateKeyPath, "binary");
277-
278-
if (!privateKeyContent || privateKeyContent.length <= 1) {
279-
throw new Error("Private key content not valid");
280-
}
281-
282-
return forge.pki.privateKeyFromAsn1(forge.asn1.fromDer(privateKeyContent));
283-
}
284-
285266
module.exports.readPublicCertificate = function (publicCertificatePath) {
286267
const certificateContent = fs.readFileSync(publicCertificatePath);
287268
if (!certificateContent || certificateContent.length <= 1) {
@@ -351,13 +332,12 @@ module.exports.checkConfigFieldsArePopulated = function(config, propertiesBasic,
351332
return config[elem] !== null && typeof config[elem] !== "undefined";
352333
});
353334
};
354-
if (typeof config !== "object" || config === null) {
335+
336+
// eslint-disable-next-line eqeqeq
337+
if (typeof config !== "object" || config == null) {
355338
throw Error("Config not valid: config should be an object.");
356339
}
357-
if (
358-
config["paths"] === null ||
359-
typeof config["paths"] === "undefined" ||
360-
!(config["paths"] instanceof Array)
340+
if (!Array.isArray(config.paths)
361341
) {
362342
throw Error("Config not valid: paths should be an array of path element.");
363343
}
@@ -466,11 +446,11 @@ module.exports.readPublicCertificateContent = function (config) {
466446
throw new Error("Public certificate content is not valid");
467447
}
468448
return forge.pki.certificateFromPem(config.encryptionCertificate);
469-
}
449+
};
470450

471451
module.exports.getPrivateKeyFromContent = function(config) {
472452
if (config.privateKey) {
473453
return forge.pki.privateKeyFromPem(config.privateKey);
474454
}
475455
return null;
476-
}
456+
};

package-lock.json

+12-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mastercard-client-encryption",
3-
"version": "1.10.3",
3+
"version": "1.10.4",
44
"description": "Library for Mastercard API compliant payload encryption/decryption.",
55
"main": "index.js",
66
"engines": {

test/field-level-crypto.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ describe("Field Level Crypto", () => {
131131
delete config["publicKeyFingerprintType"];
132132
assert.throws(
133133
() => new Crypto(config),
134-
/Config not valid: propertiesFingerprint should be: 'certificate' or 'publicKey'/
134+
/Config not valid: publicKeyFingerprintType should be: 'certificate' or 'publicKey'/
135135
);
136136
});
137137

@@ -147,7 +147,7 @@ describe("Field Level Crypto", () => {
147147
config.publicKeyFingerprintType = "foobar";
148148
assert.throws(
149149
() => new Crypto(config),
150-
/Config not valid: propertiesFingerprint should be: 'certificate' or 'publicKey'/
150+
/Config not valid: publicKeyFingerprintType should be: 'certificate' or 'publicKey'/
151151
);
152152
});
153153

test/res/empty.p12

Whitespace-only changes.

test/res/keys/pkcs1/test_key.der

635 Bytes
Binary file not shown.

test/res/keys/pkcs12/empty_key_container.unknown_extension

Whitespace-only changes.
Binary file not shown.

test/utils.test.js

+72-22
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,25 @@ describe("Utils", () => {
453453
});
454454
});
455455

456-
describe("#getPrivateKey12", () => {
456+
describe("#getPrivateKey", () => {
457+
it("empty p12 file", () => {
458+
assert.throws(() => {
459+
utils.getPrivateKey({
460+
keyStore: "./test/res/empty.p12",
461+
keyStoreAlias: "mykeyalias",
462+
keyStorePassword: "Password1", });
463+
}, /p12 keystore content is empty/);
464+
});
465+
466+
it("empty p12 file unknown extension", () => {
467+
assert.throws(() => {
468+
utils.getPrivateKey({
469+
keyStore: "./test/res/keys/pkcs12/empty_key_container.unknown_extension",
470+
keyStoreAlias: "mykeyalias",
471+
keyStorePassword: "Password1", });
472+
}, /p12 keystore content is empty/);
473+
});
474+
457475
it("empty alias", () => {
458476
assert.throws(() => {
459477
utils.getPrivateKey({
@@ -489,50 +507,82 @@ describe("Utils", () => {
489507
});
490508
}, /No key found for alias \[mykeyalias1\]/);
491509
});
492-
});
493510

494-
describe("#getPrivateKeyPem", () => {
495-
it("valid pkcs8 pem", () => {
511+
it("valid p12, unknown extension", () => {
512+
const pk = utils.getPrivateKey({
513+
keyStore: "./test/res/keys/pkcs12/test_key_container.unknown_extension",
514+
keyStoreAlias: "mykeyalias",
515+
keyStorePassword: "Password1",
516+
});
517+
assert.ok(pk);
518+
});
519+
520+
it("empty unencrypted file keyStore", () => {
521+
assert.throws(() => {
522+
utils.getPrivateKey({ keyStore: "./test/res/empty.pem" });
523+
}, /private key file content is empty/);
524+
});
525+
526+
it("valid pkcs8 pem in keyStore", () => {
496527
const pk = utils.getPrivateKey({
497528
keyStore: "./test/res/keys/pkcs8/test_key.pem",
498529
});
499530
assert.ok(pk);
500531
});
501532

502-
it("valid pkcs1 pem", () => {
533+
it("valid pkcs1 pem in keyStore", () => {
503534
const pk = utils.getPrivateKey({
504535
keyStore: "./test/res/keys/pkcs1/test_key.pem",
505536
});
506537
assert.ok(pk);
507538
});
508539

509-
it("not valid key", () => {
510-
assert.throws(() => {
511-
utils.getPrivateKey({ keyStore: "./test/res/empty.pem" });
512-
}, /pem keystore content is empty/);
540+
it("valid pkcs8 der in keyStore", () => {
541+
const pk = utils.getPrivateKey({
542+
keyStore: "./test/res/keys/pkcs8/test_key.der",
543+
});
544+
assert.ok(pk);
513545
});
514-
});
515546

516-
describe("#getPrivateKeyDer", () => {
517-
it("valid pkcs8 der", () => {
547+
it("valid pkcs1 der in keyStore", () => {
518548
const pk = utils.getPrivateKey({
519-
keyStore: "./test/res/keys/pkcs8/test_key.der",
549+
keyStore: "./test/res/keys/pkcs1/test_key.der",
520550
});
521551
assert.ok(pk);
522552
});
523553

524-
it("not valid key", () => {
554+
it("empty unencrypted file in privateKey", () => {
525555
assert.throws(() => {
526-
utils.getPrivateKey({ keyStore: "./test/res/empty.der" });
527-
}, /der keystore content is empty/);
556+
utils.getPrivateKey({ privateKey: "./test/res/empty.pem" });
557+
}, /private key file content is empty/);
528558
});
529-
});
530559

531-
describe("#loadPrivateKey", () => {
532-
it("not valid key", () => {
533-
assert.throws(() => {
534-
utils.getPrivateKey({ privateKey: "./test/res/empty.key" });
535-
}, /Private key content not valid/);
560+
it("valid pkcs8 pem in privateKey", () => {
561+
const pk = utils.getPrivateKey({
562+
privateKey: "./test/res/keys/pkcs8/test_key.pem",
563+
});
564+
assert.ok(pk);
565+
});
566+
567+
it("valid pkcs1 pem in privateKey", () => {
568+
const pk = utils.getPrivateKey({
569+
privateKey: "./test/res/keys/pkcs1/test_key.pem",
570+
});
571+
assert.ok(pk);
572+
});
573+
574+
it("valid pkcs8 der in privateKey", () => {
575+
const pk = utils.getPrivateKey({
576+
privateKey: "./test/res/keys/pkcs8/test_key.der",
577+
});
578+
assert.ok(pk);
579+
});
580+
581+
it("valid pkcs1 der in privateKey", () => {
582+
const pk = utils.getPrivateKey({
583+
privateKey: "./test/res/keys/pkcs1/test_key.der",
584+
});
585+
assert.ok(pk);
536586
});
537587
});
538588

0 commit comments

Comments
 (0)