Skip to content

Commit 97b0b94

Browse files
committed
Improve test coverage and make tests match descriptions
This exposes a runtime gap that the type system was preventing.
1 parent b64e74e commit 97b0b94

1 file changed

Lines changed: 96 additions & 20 deletions

File tree

test/xmldsig-verifier.spec.ts

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ const expiredCert = fs.readFileSync("./test/static/expired_certificate.crt.pem",
2828
const futureKey = fs.readFileSync("./test/static/future_certificate.key.pem", "utf-8");
2929
const futureCert = fs.readFileSync("./test/static/future_certificate.crt.pem", "utf-8");
3030

31+
// Shared-secret keys for HMAC verification testing
32+
const hmacKey = fs.readFileSync("./test/static/hmac.key");
33+
const wrongHmacKey = fs.readFileSync("./test/static/hmac-foobar.key");
34+
3135
// Helper function to create a signed XML document
3236
function createSignedXml(
3337
xml: string,
@@ -104,6 +108,23 @@ function createFutureSignedXml(xml: string): string {
104108
return sig.getSignedXml();
105109
}
106110

111+
function createHmacSignedXml(xml: string): string {
112+
const sig = new SignedXml();
113+
sig.enableHMAC();
114+
sig.privateKey = hmacKey;
115+
sig.canonicalizationAlgorithm = CANONICALIZATION_ALGORITHMS.EXCLUSIVE_C14N;
116+
sig.signatureAlgorithm = SIGNATURE_ALGORITHMS.HMAC_SHA1;
117+
118+
sig.addReference({
119+
xpath: "//*[local-name(.)='test']",
120+
digestAlgorithm: HASH_ALGORITHMS.SHA1,
121+
transforms: [CANONICALIZATION_ALGORITHMS.EXCLUSIVE_C14N],
122+
});
123+
124+
sig.computeSignature(xml);
125+
return sig.getSignedXml();
126+
}
127+
107128
function expectValidResult(result: XmlDsigVerificationResult, references: number = 1) {
108129
expect(result.success).to.be.true;
109130
expect(result.error).to.be.undefined;
@@ -269,6 +290,41 @@ describe("XmlDSigVerifier", function () {
269290
});
270291
});
271292

293+
describe("sharedSecretKey selector", function () {
294+
it("verifies a valid HMAC signature using the sharedSecretKey selector", function () {
295+
const signedXml = createHmacSignedXml(xml);
296+
297+
const verifier = new XmlDSigVerifier({
298+
keySelector: { sharedSecretKey: hmacKey },
299+
});
300+
301+
expectValidResult(verifier.verifySignature(signedXml));
302+
});
303+
304+
it("returns an invalid result when sharedSecretKey does not match the signing key", function () {
305+
const signedXml = createHmacSignedXml(xml);
306+
307+
const verifier = new XmlDSigVerifier({
308+
keySelector: { sharedSecretKey: wrongHmacKey },
309+
throwOnError: false,
310+
});
311+
312+
expectInvalidResult(verifier.verifySignature(signedXml), "invalid signature");
313+
});
314+
315+
it("returns an invalid result when HMAC signature algorithm is not allowed", function () {
316+
const signedXml = createHmacSignedXml(xml);
317+
318+
const verifier = new XmlDSigVerifier({
319+
keySelector: { sharedSecretKey: hmacKey },
320+
throwOnError: false,
321+
security: { signatureAlgorithms: [] },
322+
});
323+
324+
expectInvalidResult(verifier.verifySignature(signedXml), "signature algorithm");
325+
});
326+
});
327+
272328
describe("idAttributes option", function () {
273329
const xmlWithCustomId = '<root><test customId="test1">content</test></root>';
274330
const xmlWithPrefixedId = `<root xmlns:foo="uri:foo"><test foo:customId="test1">content</test></root>`;
@@ -359,7 +415,7 @@ describe("XmlDSigVerifier", function () {
359415
idAttributes: [{ localName: "customId", namespaceUri: "uri:bar" }],
360416
throwOnError: false,
361417
});
362-
expectInvalidResult(verifier.verifySignature(signedXml), "fail");
418+
expectInvalidResult(verifier.verifySignature(signedXml), "verification failed");
363419
});
364420

365421
it("should fail validation when Id attribute is not namespaced but namespaceUri is provided", function () {
@@ -382,7 +438,7 @@ describe("XmlDSigVerifier", function () {
382438
idAttributes: [{ localName: "customId", namespaceUri: "uri:foo" }],
383439
throwOnError: false,
384440
});
385-
expectInvalidResult(verifier.verifySignature(signedXml), "fail");
441+
expectInvalidResult(verifier.verifySignature(signedXml), "verification failed");
386442
});
387443

388444
describe("idAttributes property handling", function () {
@@ -618,24 +674,24 @@ describe("XmlDSigVerifier", function () {
618674
});
619675

620676
describe("checkCertExpiration", function () {
621-
it("should validate when certificate is not expired and checkCertExpiration is true", function () {
622-
const signedXml = createSignedXml(xml);
623-
// @ts-expect-error -- ignore for test purposes
624-
const verifier = new XmlDSigVerifier({
625-
keySelector: { publicCert },
626-
security: { checkCertExpiration: true },
627-
});
628-
expectValidResult(verifier.verifySignature(signedXml));
629-
});
630-
631-
it("should validate when certificate is expired and checkCertExpiration is false", function () {
632-
const signedXml = createExpiredSignedXml(xml);
633-
// @ts-expect-error -- ignore for test purposes
634-
const verifier = new XmlDSigVerifier({
635-
keySelector: { publicCert: expiredCert },
636-
security: { checkCertExpiration: false },
637-
});
638-
expectValidResult(verifier.verifySignature(signedXml));
677+
it("should reject checkCertExpiration when used with publicCert selector (true)", function () {
678+
expect(() => {
679+
// @ts-expect-error -- checkCertExpiration is currently only typed for keyinfo selector
680+
new XmlDSigVerifier({
681+
keySelector: { publicCert },
682+
security: { checkCertExpiration: true },
683+
});
684+
}).to.throw("checkCertExpiration is only supported with getCertFromKeyInfo");
685+
});
686+
687+
it("should reject checkCertExpiration when used with publicCert selector (false)", function () {
688+
expect(() => {
689+
// @ts-expect-error -- checkCertExpiration is currently only typed for keyinfo selector
690+
new XmlDSigVerifier({
691+
keySelector: { publicCert: expiredCert },
692+
security: { checkCertExpiration: false },
693+
});
694+
}).to.throw("checkCertExpiration is only supported with getCertFromKeyInfo");
639695
});
640696

641697
it("should fail validation when certificate is expired and checkCertExpiration is true", function () {
@@ -658,6 +714,26 @@ describe("XmlDSigVerifier", function () {
658714
});
659715

660716
describe("truststore", function () {
717+
it("should reject truststore when used with publicCert selector", function () {
718+
expect(() => {
719+
// @ts-expect-error -- truststore is currently only typed for keyinfo selector
720+
new XmlDSigVerifier({
721+
keySelector: { publicCert },
722+
security: { truststore: [rootCert] },
723+
});
724+
}).to.throw("truststore is only supported with getCertFromKeyInfo");
725+
});
726+
727+
it("should reject truststore when used with sharedSecretKey selector", function () {
728+
expect(() => {
729+
// @ts-expect-error -- truststore is currently only typed for keyinfo selector
730+
new XmlDSigVerifier({
731+
keySelector: { sharedSecretKey: hmacKey },
732+
security: { truststore: [rootCert] },
733+
});
734+
}).to.throw("truststore is only supported with getCertFromKeyInfo");
735+
});
736+
661737
it("should validate when certificate is exactly in truststore", function () {
662738
const signedXml = createSignedXml(xml);
663739
const verifier = new XmlDSigVerifier({

0 commit comments

Comments
 (0)