Skip to content

Commit

Permalink
Merge pull request #39 from rfeelin/feature/improving-public-key-fing…
Browse files Browse the repository at this point in the history
…erprint

Allowing encoding type to be set for publickey fingerprint
  • Loading branch information
rfeelin authored Jul 19, 2022
2 parents 0f874cb + 1afa9ea commit b342c2b
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 41 deletions.
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,6 @@ const config = {
],
mode: "JWE",
encryptedValueFieldName: "encryptedData",
publicKeyFingerprintType: "certificate",
encryptionCertificate: "./path/to/public.cert",
privateKey: "./path/to/your/private.key",
};
Expand Down Expand Up @@ -394,7 +393,6 @@ const config = {
],
mode: "JWE",
encryptedValueFieldName: "encryptedData",
publicKeyFingerprintType: "certificate",
encryptionCertificate: "./path/to/public.cert",
privateKey: "./path/to/your/private.key",
};
Expand Down Expand Up @@ -443,7 +441,6 @@ const config = {
],
mode: "JWE",
encryptedValueFieldName: "encryptedData",
publicKeyFingerprintType: "certificate",
encryptionCertificate: "./path/to/public.cert",
privateKey: "./path/to/your/private.key",
};
Expand Down
31 changes: 24 additions & 7 deletions lib/mcapi/crypto/jwe-crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,17 @@ function getPrivateKey(config) {
*/
function computePublicFingerprint(config, encryptionCertificate) {
if (config && encryptionCertificate) {
return utils.computePublicFingerprint(
config,
forge.pki.certificateFromPem(encryptionCertificate),
c.BASE64
);
if(config.publicKeyFingerprintType) {
return utils.computePublicFingerprint(
config,
forge.pki.certificateFromPem(encryptionCertificate),
config.dataEncoding
);
} else {
return utils.publicKeyFingerprint(
forge.pki.certificateFromPem(encryptionCertificate)
);
}
} else {
return null;
}
Expand All @@ -232,14 +238,25 @@ function isValidConfig(config) {
*/
function validateFingerprint(config, contains) {
const propertiesFingerprint = ["publicKeyFingerprintType"];
const propertiesOptionalDataEncoding = ["dataEncoding"];
const propertiesOptionalFingerprint = ["publicKeyFingerprint"];
if (
!contains(propertiesOptionalFingerprint) &&
contains(propertiesFingerprint) &&
config[propertiesFingerprint[0]] !== "certificate" &&
config[propertiesFingerprint[0]] !== "publicKey"
) {
throw Error(
"Config not valid: propertiesFingerprint should be: 'certificate' or 'publicKey'"
"Config not valid: publicKeyFingerprintType should be: 'certificate' or 'publicKey'"
);
}
if (
!contains(propertiesOptionalFingerprint) &&
config[propertiesFingerprint[0]] === "certificate" &&
!(config[propertiesOptionalDataEncoding[0]] === c.BASE64 ||
config[propertiesOptionalDataEncoding[0]] === c.HEX)
) {
throw Error(
"Config not valid: if publicKeyFingerprintType is 'certificate' dataEncoding must be either 'base64' or 'hex'"
);
}
}
Expand Down
9 changes: 1 addition & 8 deletions lib/mcapi/encryption/field-level-encryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,7 @@ function encryptBody(path, body) {
const elem = utils.elemFromPath(path.element, body);
if (elem && elem.node) {
const encryptedData = this.crypto.encryptData({ data: elem.node });
body = utils.mutateObjectProperty(path.obj, encryptedData, body);
// delete encrypted field if not overridden
if (
!utils.isJsonRoot(path.obj) &&
path.element !== path.obj + "." + this.config.encryptedValueFieldName
) {
utils.deleteNode(path.element, body);
}
body = utils.addEncryptedDataToBody(encryptedData, path, this.config.encryptedValueFieldName, body);
}
return body;
}
Expand Down
9 changes: 1 addition & 8 deletions lib/mcapi/encryption/jwe-encryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,7 @@ function encryptBody(path, body) {
const elem = utils.elemFromPath(path.element, body);
if (elem && elem.node) {
const encryptedData = this.crypto.encryptData({ data: elem.node });
body = utils.mutateObjectProperty(path.obj, encryptedData, body);
// delete encrypted field if not overridden
if (
!utils.isJsonRoot(path.obj) &&
path.element !== path.obj + "." + this.config.encryptedValueFieldName
) {
utils.deleteNode(path.element, body);
}
body = utils.addEncryptedDataToBody(encryptedData, path, this.config.encryptedValueFieldName, body);
}
return body;
}
Expand Down
19 changes: 15 additions & 4 deletions lib/mcapi/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ module.exports.computePublicFingerprint = function (
);
break;
case "publicKey":
fingerprint = publicKeyFingerprint(encryptionCertificate);
fingerprint = this.publicKeyFingerprint(encryptionCertificate);
break;
}
}
Expand All @@ -289,13 +289,13 @@ function publicCertificateFingerprint(publicCertificate, encoding) {
return bytesToString(md.digest().getBytes(), encoding);
}

function publicKeyFingerprint(publicCertificate) {
module.exports.publicKeyFingerprint = function(publicCertificate) {
return forge.pki.getPublicKeyFingerprint(publicCertificate.publicKey, {
type: "SubjectPublicKeyInfo",
md: createMessageDigest("SHA-256"),
encoding: c.HEX,
});
}
};

function createMessageDigest(digest) {
switch (digest.toUpperCase()) {
Expand Down Expand Up @@ -415,6 +415,17 @@ function hasEncryptionParam(encParams, bodyMap) {
return encParams && encParams.length === 1 && bodyMap && bodyMap[0];
}

module.exports.addEncryptedDataToBody = function(encryptedData, path, encryptedValueFieldName, body) {
body = this.mutateObjectProperty(path.obj, encryptedData, body);
if (
!isJsonRoot(path.obj) &&
path.element !== path.obj + "." + encryptedValueFieldName
) {
this.deleteNode(path.element, body);
}
return body;
};

module.exports.readPublicCertificateContent = function (config) {
if (!config.encryptionCertificate || config.encryptionCertificate.length <= 1) {
throw new Error("Public certificate content is not valid");
Expand All @@ -427,4 +438,4 @@ module.exports.getPrivateKeyFromContent = function(config) {
return forge.pki.privateKeyFromPem(config.privateKey);
}
return null;
}
}
44 changes: 33 additions & 11 deletions test/jwe-crypto.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,6 @@ describe("JWE Crypto", () => {
});
});

it("without publicKeyFingerprintType", () => {
const config = JSON.parse(JSON.stringify(testConfig));
delete config["publicKeyFingerprintType"];
assert.throws(
() => new Crypto(config),
/Config not valid: propertiesFingerprint should be: 'certificate' or 'publicKey'/
);
});

it("without publicKeyFingerprintType, but providing the publicKeyFingerprint", () => {
const config = JSON.parse(JSON.stringify(testConfig));
delete config["publicKeyFingerprintType"];
Expand All @@ -108,16 +99,34 @@ describe("JWE Crypto", () => {
config.publicKeyFingerprintType = "foobar";
assert.throws(
() => new Crypto(config),
/Config not valid: propertiesFingerprint should be: 'certificate' or 'publicKey'/
/Config not valid: publicKeyFingerprintType should be: 'certificate' or 'publicKey'/
);
});

it("with right publicKeyFingerprintType: certificate", () => {
it("with right publicKeyFingerprintType: certificate and dataEncoding: base64", () => {
const config = JSON.parse(JSON.stringify(testConfig));
config.publicKeyFingerprintType = "certificate";
config.dataEncoding = "base64";
assert.doesNotThrow(() => new Crypto(config));
});

it("with right publicKeyFingerprintType: certificate and dataEncoding: hex", () => {
const config = JSON.parse(JSON.stringify(testConfig));
config.publicKeyFingerprintType = "certificate";
config.dataEncoding = "hex";
assert.doesNotThrow(() => new Crypto(config));
});

it("with right publicKeyFingerprintType: certificate and dataEncoding: null", () => {
const config = JSON.parse(JSON.stringify(testConfig));
config.publicKeyFingerprintType = "certificate";
delete config["dataEncoding"];
assert.throws(
() => new Crypto(config),
/Config not valid: if publicKeyFingerprintType is 'certificate' dataEncoding must be either 'base64' or 'hex'/
);
});

it("with right publicKeyFingerprintType: publicKey", () => {
const config = JSON.parse(JSON.stringify(testConfig));
config.publicKeyFingerprintType = "publicKey";
Expand Down Expand Up @@ -249,5 +258,18 @@ describe("JWE Crypto", () => {
})
);
});

it("compute public fingerprint: defaults to publicKey with publicKeyFingerprintType set", () => {
const strippedConfig = JSON.parse(JSON.stringify(testConfig));
delete strippedConfig["publicKeyFingerprintType"];
delete strippedConfig["dataEncoding"];

assert.ok(
"80810fc13a8319fcf0e2ec322c82a4c304b782cc3ce671176343cfe8160c2279",
computePublicFingerprint.call(crypto, {
strippedConfig
})
);
});
});
});
1 change: 1 addition & 0 deletions test/mock/jwe-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ module.exports = {
mode: "JWE",
encryptedValueFieldName: "encryptedData",
publicKeyFingerprintType: "certificate",
dataEncoding: "base64",
encryptionCertificate: "./test/res/test_certificate.cert",
privateKey: "./test/res/test_key.der",
};

0 comments on commit b342c2b

Please sign in to comment.