@@ -28,6 +28,10 @@ const expiredCert = fs.readFileSync("./test/static/expired_certificate.crt.pem",
2828const futureKey = fs . readFileSync ( "./test/static/future_certificate.key.pem" , "utf-8" ) ;
2929const 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
3236function 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+
107128function 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