Skip to content

Commit 4b8fd0c

Browse files
committed
cleanup decryption key handling
1 parent 90f5811 commit 4b8fd0c

File tree

8 files changed

+102
-73
lines changed

8 files changed

+102
-73
lines changed

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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const forge = require("node-forge");
22
const fs = require("fs");
3+
const path = require("path")
34
const c = require("../utils/constants");
45

56
/**
@@ -195,25 +196,40 @@ function deleteRoot(obj, paths, properties) {
195196

196197
module.exports.getPrivateKey = function (config) {
197198
if (config.privateKey) {
198-
return loadPrivateKey(config.privateKey);
199-
} else if (config.keyStore) {
200-
if (config.keyStore.includes(".p12")) {
199+
return getUnencryptedPrivateKey(config.privateKey);
200+
}
201+
202+
if (config.keyStore) {
203+
if (config.keyStore.includes(".p12") || (config.keyStoreAlias && config.keyStorePassword)) {
201204
return getPrivateKey12(
202205
config.keyStore,
203206
config.keyStoreAlias,
204207
config.keyStorePassword
205208
);
206209
}
207-
if (config.keyStore.includes(".pem")) {
208-
return getPrivateKeyPem(config.keyStore);
209-
}
210-
if (config.keyStore.includes(".der")) {
211-
return getPrivateKeyDer(config.keyStore);
212-
}
210+
211+
return getUnencryptedPrivateKey(config.keyStore)
213212
}
213+
214214
return null;
215215
};
216216

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

@@ -248,40 +264,6 @@ function getPrivateKey12(p12Path, alias, password) {
248264
return keyObj.key;
249265
}
250266

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-
285267
module.exports.readPublicCertificate = function (publicCertificatePath) {
286268
const certificateContent = fs.readFileSync(publicCertificatePath);
287269
if (!certificateContent || certificateContent.length <= 1) {
@@ -351,13 +333,10 @@ module.exports.checkConfigFieldsArePopulated = function(config, propertiesBasic,
351333
return config[elem] !== null && typeof config[elem] !== "undefined";
352334
});
353335
};
354-
if (typeof config !== "object" || config === null) {
336+
if (typeof config !== "object" || config == null) {
355337
throw Error("Config not valid: config should be an object.");
356338
}
357-
if (
358-
config["paths"] === null ||
359-
typeof config["paths"] === "undefined" ||
360-
!(config["paths"] instanceof Array)
339+
if (!Array.isArray(config.paths)
361340
) {
362341
throw Error("Config not valid: paths should be an array of path element.");
363342
}

test/field-level-crypto.test.js

Lines changed: 2 additions & 2 deletions
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.
2.43 KB
Binary file not shown.

test/utils.test.js

Lines changed: 72 additions & 22 deletions
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)