diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..7413e0d
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,17 @@
+on: [push, pull_request]
+name: Test
+jobs:
+  test:
+    name: Test Go ${{ matrix.go }}
+    runs-on: ubuntu-20.04
+    strategy:
+      matrix:
+        go: ['1.17', '1.16']
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: ${{ matrix.go }}
+      - name: Test
+        run: go test ./...
diff --git a/README.md b/README.md
index 9464e61..a775887 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # goxmldsig
 
-[![Build Status](https://travis-ci.org/russellhaering/goxmldsig.svg?branch=master)](https://travis-ci.org/russellhaering/goxmldsig)
+![Build Status](https://github.com/russellhaering/goxmldsig/actions/workflows/test.yml/badge.svg?branch=main)
 [![GoDoc](https://godoc.org/github.com/russellhaering/goxmldsig?status.svg)](https://godoc.org/github.com/russellhaering/goxmldsig)
 
 XML Digital Signatures implemented in pure Go.
diff --git a/canonicalize.go b/canonicalize.go
index 05655eb..75392d1 100644
--- a/canonicalize.go
+++ b/canonicalize.go
@@ -26,11 +26,12 @@ func (c *NullCanonicalizer) Algorithm() AlgorithmID {
 
 func (c *NullCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
 	scope := make(map[string]struct{})
-	return canonicalSerialize(canonicalPrep(el, scope, false))
+	return canonicalSerialize(canonicalPrep(el, scope, false, true))
 }
 
 type c14N10ExclusiveCanonicalizer struct {
 	prefixList string
+	comments   bool
 }
 
 // MakeC14N10ExclusiveCanonicalizerWithPrefixList constructs an exclusive Canonicalizer
@@ -38,12 +39,22 @@ type c14N10ExclusiveCanonicalizer struct {
 func MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList string) Canonicalizer {
 	return &c14N10ExclusiveCanonicalizer{
 		prefixList: prefixList,
+		comments:   false,
+	}
+}
+
+// MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList constructs an exclusive Canonicalizer
+// from a PrefixList in NMTOKENS format (a white space separated list).
+func MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList(prefixList string) Canonicalizer {
+	return &c14N10ExclusiveCanonicalizer{
+		prefixList: prefixList,
+		comments:   true,
 	}
 }
 
 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
 func (c *c14N10ExclusiveCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
-	err := etreeutils.TransformExcC14n(el, c.prefixList)
+	err := etreeutils.TransformExcC14n(el, c.prefixList, c.comments)
 	if err != nil {
 		return nil, err
 	}
@@ -52,58 +63,73 @@ func (c *c14N10ExclusiveCanonicalizer) Canonicalize(el *etree.Element) ([]byte,
 }
 
 func (c *c14N10ExclusiveCanonicalizer) Algorithm() AlgorithmID {
+	if c.comments {
+		return CanonicalXML10ExclusiveWithCommentsAlgorithmId
+	}
 	return CanonicalXML10ExclusiveAlgorithmId
 }
 
-type c14N11Canonicalizer struct{}
+type c14N11Canonicalizer struct {
+	comments bool
+}
 
 // MakeC14N11Canonicalizer constructs an inclusive canonicalizer.
 func MakeC14N11Canonicalizer() Canonicalizer {
-	return &c14N11Canonicalizer{}
+	return &c14N11Canonicalizer{
+		comments: false,
+	}
+}
+
+// MakeC14N11WithCommentsCanonicalizer constructs an inclusive canonicalizer.
+func MakeC14N11WithCommentsCanonicalizer() Canonicalizer {
+	return &c14N11Canonicalizer{
+		comments: true,
+	}
 }
 
 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
 func (c *c14N11Canonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
 	scope := make(map[string]struct{})
-	return canonicalSerialize(canonicalPrep(el, scope, true))
+	return canonicalSerialize(canonicalPrep(el, scope, true, c.comments))
 }
 
 func (c *c14N11Canonicalizer) Algorithm() AlgorithmID {
+	if c.comments {
+		return CanonicalXML11WithCommentsAlgorithmId
+	}
 	return CanonicalXML11AlgorithmId
 }
 
-type c14N10RecCanonicalizer struct{}
+type c14N10RecCanonicalizer struct {
+	comments bool
+}
 
 // MakeC14N10RecCanonicalizer constructs an inclusive canonicalizer.
 func MakeC14N10RecCanonicalizer() Canonicalizer {
-	return &c14N10RecCanonicalizer{}
+	return &c14N10RecCanonicalizer{
+		comments: false,
+	}
+}
+
+// MakeC14N10WithCommentsCanonicalizer constructs an inclusive canonicalizer.
+func MakeC14N10WithCommentsCanonicalizer() Canonicalizer {
+	return &c14N10RecCanonicalizer{
+		comments: true,
+	}
 }
 
 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
 func (c *c14N10RecCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
 	scope := make(map[string]struct{})
-	return canonicalSerialize(canonicalPrep(el, scope, true))
+	return canonicalSerialize(canonicalPrep(el, scope, true, c.comments))
 }
 
 func (c *c14N10RecCanonicalizer) Algorithm() AlgorithmID {
+	if c.comments {
+		return CanonicalXML10WithCommentsAlgorithmId
+	}
 	return CanonicalXML10RecAlgorithmId
-}
-
-type c14N10CommentCanonicalizer struct{}
-
-// MakeC14N10CommentCanonicalizer constructs an inclusive canonicalizer.
-func MakeC14N10CommentCanonicalizer() Canonicalizer {
-	return &c14N10CommentCanonicalizer{}
-}
-
-// Canonicalize transforms the input Element into a serialized XML document in canonical form.
-func (c *c14N10CommentCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
-	scope := make(map[string]struct{})
-	return canonicalSerialize(canonicalPrep(el, scope, true))
-}
 
-func (c *c14N10CommentCanonicalizer) Algorithm() AlgorithmID {
-	return CanonicalXML10CommentAlgorithmId
 }
 
 func composeAttr(space, key string) string {
@@ -132,7 +158,7 @@ const nsSpace = "xmlns"
 //
 // TODO(russell_h): This is very similar to excCanonicalPrep - perhaps they should
 // be unified into one parameterized function?
-func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}, strip bool) *etree.Element {
+func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}, strip bool, comments bool) *etree.Element {
 	_seenSoFar := make(map[string]struct{})
 	for k, v := range seenSoFar {
 		_seenSoFar[k] = v
@@ -140,16 +166,29 @@ func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}, strip bool)
 
 	ne := el.Copy()
 	sort.Sort(etreeutils.SortedAttrs(ne.Attr))
-	if len(ne.Attr) != 0 {
-		for _, attr := range ne.Attr {
-			if attr.Space != nsSpace {
-				continue
-			}
-			key := attr.Space + ":" + attr.Key
-			if _, seen := _seenSoFar[key]; seen {
-				ne.RemoveAttr(attr.Space + ":" + attr.Key)
+	n := 0
+	for _, attr := range ne.Attr {
+		if attr.Space != nsSpace {
+			ne.Attr[n] = attr
+			n++
+			continue
+		}
+		key := attr.Space + ":" + attr.Key
+		if _, seen := _seenSoFar[key]; !seen {
+			ne.Attr[n] = attr
+			n++
+			_seenSoFar[key] = struct{}{}
+		}
+	}
+	ne.Attr = ne.Attr[:n]
+
+	if !comments {
+		c := 0
+		for c < len(ne.Child) {
+			if _, ok := ne.Child[c].(*etree.Comment); ok {
+				ne.RemoveChildAt(c)
 			} else {
-				_seenSoFar[key] = struct{}{}
+				c++
 			}
 		}
 	}
@@ -157,7 +196,7 @@ func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}, strip bool)
 	for i, token := range ne.Child {
 		childElement, ok := token.(*etree.Element)
 		if ok {
-			ne.Child[i] = canonicalPrep(childElement, _seenSoFar, strip)
+			ne.Child[i] = canonicalPrep(childElement, _seenSoFar, strip, comments)
 		}
 	}
 
diff --git a/canonicalize_test.go b/canonicalize_test.go
index da7b771..d53ca50 100644
--- a/canonicalize_test.go
+++ b/canonicalize_test.go
@@ -8,9 +8,11 @@ import (
 )
 
 const (
-	assertion       = `<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" Version="2.0" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AssertionConsumerServiceIndex="0" AttributeConsumingServiceIndex="0" IssueInstant="2016-04-28T15:37:17" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO"><saml:Issuer>https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""/><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
-	c14n11          = `<samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AttributeConsumingServiceIndex="0" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" IssueInstant="2016-04-28T15:37:17" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer>https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""></samlp:NameIDPolicy><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
-	assertionC14ned = `<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AttributeConsumingServiceIndex="0" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" IssueInstant="2016-04-28T15:37:17" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""></samlp:NameIDPolicy><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
+	assertion              = `<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" Version="2.0" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AssertionConsumerServiceIndex="0" AttributeConsumingServiceIndex="0" IssueInstant="2016-04-28T15:37:17" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO"><!-- Some Comment --><saml:Issuer>https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""/><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
+	c14n11                 = `<samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AttributeConsumingServiceIndex="0" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" IssueInstant="2016-04-28T15:37:17" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer>https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""></samlp:NameIDPolicy><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
+	assertionC14ned        = `<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AttributeConsumingServiceIndex="0" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" IssueInstant="2016-04-28T15:37:17" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""></samlp:NameIDPolicy><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
+	c14n11Comment          = `<samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AttributeConsumingServiceIndex="0" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" IssueInstant="2016-04-28T15:37:17" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><!-- Some Comment --><saml:Issuer>https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""></samlp:NameIDPolicy><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
+	assertionC14nedComment = `<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://saml2.test.astuart.co/sso/saml2" AttributeConsumingServiceIndex="0" Destination="http://idp.astuart.co/idp/profile/SAML2/Redirect/SSO" ID="_88a93ebe-abdf-48cd-9ed0-b0dd1b252909" IssueInstant="2016-04-28T15:37:17" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><!-- Some Comment --><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://saml2.test.astuart.co/sso/saml2</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format=""></samlp:NameIDPolicy><samlp:RequestedAuthnContext Comparison="exact"><saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>`
 )
 
 const (
@@ -33,10 +35,18 @@ func TestExcC14N10(t *testing.T) {
 	runCanonicalizationTest(t, MakeC14N10ExclusiveCanonicalizerWithPrefixList(""), assertion, assertionC14ned)
 }
 
+func TestExcC14N10WithComments(t *testing.T) {
+	runCanonicalizationTest(t, MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList(""), assertion, assertionC14nedComment)
+}
+
 func TestC14N11(t *testing.T) {
 	runCanonicalizationTest(t, MakeC14N11Canonicalizer(), assertion, c14n11)
 }
 
+func TestC14N11WithComments(t *testing.T) {
+	runCanonicalizationTest(t, MakeC14N11WithCommentsCanonicalizer(), assertion, c14n11Comment)
+}
+
 func TestXmldocC14N10Exclusive(t *testing.T) {
 	runCanonicalizationTest(t, MakeC14N10ExclusiveCanonicalizerWithPrefixList(""), xmldoc, xmldocC14N10ExclusiveCanonicalized)
 }
@@ -45,6 +55,12 @@ func TestXmldocC14N11(t *testing.T) {
 	runCanonicalizationTest(t, MakeC14N11Canonicalizer(), xmldoc, xmldocC14N11Canonicalized)
 }
 
+func TestNestedExcC14N11(t *testing.T) {
+	input := `<X xmlns:x="x" xmlns:y="y"><Y xmlns:x="x" xmlns:y="y" xmlns:z="z"/></X>`
+	expected := `<X xmlns:x="x" xmlns:y="y"><Y xmlns:z="z"></Y></X>`
+	runCanonicalizationTest(t, MakeC14N11Canonicalizer(), input, expected)
+}
+
 func TestExcC14nDefaultNamespace(t *testing.T) {
 	input := `<foo:Foo xmlns="urn:baz" xmlns:foo="urn:foo"><foo:Bar></foo:Bar></foo:Foo>`
 	expected := `<foo:Foo xmlns:foo="urn:foo"><foo:Bar></foo:Bar></foo:Foo>`
diff --git a/debian/changelog b/debian/changelog
index 5e1c1f3..a83353f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-russellhaering-goxmldsig (1.2.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sun, 17 Apr 2022 00:29:00 -0000
+
 golang-github-russellhaering-goxmldsig (1.1.1-1) unstable; urgency=medium
 
   * New upstream release.
diff --git a/etreeutils/canonicalize.go b/etreeutils/canonicalize.go
index e9f8deb..8437fe4 100644
--- a/etreeutils/canonicalize.go
+++ b/etreeutils/canonicalize.go
@@ -8,7 +8,7 @@ import (
 )
 
 // TransformExcC14n transforms the passed element into xml-exc-c14n form.
-func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) error {
+func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string, comments bool) error {
 	prefixes := strings.Fields(inclusiveNamespacesPrefixList)
 	prefixSet := make(map[string]struct{}, len(prefixes))
 
@@ -16,7 +16,7 @@ func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) e
 		prefixSet[prefix] = struct{}{}
 	}
 
-	err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet)
+	err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet, comments)
 	if err != nil {
 		return err
 	}
@@ -24,7 +24,7 @@ func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) e
 	return nil
 }
 
-func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNamespaces map[string]struct{}) error {
+func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNamespaces map[string]struct{}, comments bool) error {
 	scope, err := ctx.SubContext(el)
 	if err != nil {
 		return err
@@ -86,9 +86,20 @@ func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNames
 
 	sort.Sort(SortedAttrs(el.Attr))
 
+	if !comments {
+		c := 0
+		for c < len(el.Child) {
+			if _, ok := el.Child[c].(*etree.Comment); ok {
+				el.RemoveChildAt(c)
+			} else {
+				c++
+			}
+		}
+	}
+
 	// Transform child elements
 	for _, child := range el.ChildElements() {
-		err := transformExcC14n(scope, declared, child, inclusiveNamespaces)
+		err := transformExcC14n(scope, declared, child, inclusiveNamespaces, comments)
 		if err != nil {
 			return err
 		}
diff --git a/validate.go b/validate.go
index 8404585..2c65ca1 100644
--- a/validate.go
+++ b/validate.go
@@ -21,7 +21,7 @@ var (
 	// ErrMissingSignature indicates that no enveloped signature was found referencing
 	// the top level element passed for signature verification.
 	ErrMissingSignature = errors.New("Missing signature referencing the top-level element")
-	ErrInvalidSignature = errors.New( "Invalid Signature")
+	ErrInvalidSignature = errors.New("Invalid Signature")
 )
 
 type ValidationContext struct {
@@ -70,7 +70,7 @@ func mapPathToElement(tree, el *etree.Element) []int {
 	for i, child := range tree.Child {
 		if childElement, ok := child.(*etree.Element); ok {
 			childPath := mapPathToElement(childElement, el)
-			if childElement != nil {
+			if childPath != nil {
 				return append([]int{i}, childPath...)
 			}
 		}
@@ -138,14 +138,25 @@ func (ctx *ValidationContext) transform(
 
 			canonicalizer = MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList)
 
+		case CanonicalXML10ExclusiveWithCommentsAlgorithmId:
+			var prefixList string
+			if transform.InclusiveNamespaces != nil {
+				prefixList = transform.InclusiveNamespaces.PrefixList
+			}
+
+			canonicalizer = MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList(prefixList)
+
 		case CanonicalXML11AlgorithmId:
 			canonicalizer = MakeC14N11Canonicalizer()
 
+		case CanonicalXML11WithCommentsAlgorithmId:
+			canonicalizer = MakeC14N11WithCommentsCanonicalizer()
+
 		case CanonicalXML10RecAlgorithmId:
 			canonicalizer = MakeC14N10RecCanonicalizer()
 
-		case CanonicalXML10CommentAlgorithmId:
-			canonicalizer = MakeC14N10CommentCanonicalizer()
+		case CanonicalXML10WithCommentsAlgorithmId:
+			canonicalizer = MakeC14N10WithCommentsCanonicalizer()
 
 		default:
 			return nil, nil, errors.New("Unknown Transform Algorithm: " + algo)
@@ -353,9 +364,9 @@ func (ctx *ValidationContext) findSignature(root *etree.Element) (*types.Signatu
 
 				var canonicalSignedInfo *etree.Element
 
-				switch AlgorithmID(c14NAlgorithm) {
-				case CanonicalXML10ExclusiveAlgorithmId:
-					err := etreeutils.TransformExcC14n(detachedSignedInfo, "")
+				switch alg := AlgorithmID(c14NAlgorithm); alg {
+				case CanonicalXML10ExclusiveAlgorithmId, CanonicalXML10ExclusiveWithCommentsAlgorithmId:
+					err := etreeutils.TransformExcC14n(detachedSignedInfo, "", alg == CanonicalXML10ExclusiveWithCommentsAlgorithmId)
 					if err != nil {
 						return err
 					}
@@ -366,14 +377,11 @@ func (ctx *ValidationContext) findSignature(root *etree.Element) (*types.Signatu
 					// removing of elements below.
 					canonicalSignedInfo = detachedSignedInfo
 
-				case CanonicalXML11AlgorithmId:
-					canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true)
-
-				case CanonicalXML10RecAlgorithmId:
-					canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true)
+				case CanonicalXML11AlgorithmId, CanonicalXML10RecAlgorithmId:
+					canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true, false)
 
-				case CanonicalXML10CommentAlgorithmId:
-					canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true)
+				case CanonicalXML11WithCommentsAlgorithmId, CanonicalXML10WithCommentsAlgorithmId:
+					canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true, true)
 
 				default:
 					return fmt.Errorf("invalid CanonicalizationMethod on Signature: %s", c14NAlgorithm)
diff --git a/validate_test.go b/validate_test.go
index 4406f9f..7516376 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/beevik/etree"
+	"github.com/russellhaering/goxmldsig/etreeutils"
 	"github.com/stretchr/testify/require"
 )
 
@@ -249,7 +250,6 @@ func TestValidateWithValid(t *testing.T) {
 	require.NotEmpty(t, el)
 }
 
-
 func TestValidateWithModified(t *testing.T) {
 	doc := etree.NewDocument()
 	err := doc.ReadFromBytes([]byte(modifiedToBeTodd))
@@ -268,7 +268,6 @@ func TestValidateWithModified(t *testing.T) {
 	require.Error(t, err)
 }
 
-
 func TestValidateWithModifiedAndSignatureEdited(t *testing.T) {
 	doc := etree.NewDocument()
 	err := doc.ReadFromBytes([]byte(spoofedAsTodd))
@@ -287,6 +286,24 @@ func TestValidateWithModifiedAndSignatureEdited(t *testing.T) {
 	require.Error(t, err)
 }
 
+func TestMapPathAndRemove(t *testing.T) {
+	doc := etree.NewDocument()
+	err := doc.ReadFromString(`<X><Y/><Y><RemoveMe xmlns="x"/></Y></X>`)
+	require.NoError(t, err)
+
+	el, err := etreeutils.NSFindOne(doc.Root(), "x", "RemoveMe")
+	require.NoError(t, err)
+	require.NotNil(t, el)
+
+	path := mapPathToElement(doc.Root(), el)
+	removed := removeElementAtPath(doc.Root(), path)
+	require.True(t, removed)
+
+	el, err = etreeutils.NSFindOne(doc.Root(), "x", "RemoveMe")
+	require.NoError(t, err)
+	require.Nil(t, el)
+}
+
 const (
 	validExample = `<?xml version="1.0" encoding="UTF-8"?><saml2p:Response Destination="https://dev.sudo.wtf:8443/v1/_saml_callback" ID="id149481635007085371203272055" InResponseTo="_ffea96b1-44a2-4a86-9683-45807984ab5b" IssueInstant="2020-09-01T17:51:12.176Z" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exkrfkzzb7NyB3UeP0h7</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#id149481635007085371203272055"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces PrefixList="xs" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>LwRDkrPmsTcUa++BIS5VJIANUlZN7zzdtjLfxfLAWds=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>UyjNRj9ZFbhApPhWEuVG26yACVqd25uyRKalSpp6XCdjrqKjI8Fmx7Q/IFkk5M755cxyFCQGttxThR6IPBk4Kp5OG2qGKXNHt7OQ8mumSLqWZpBJbmzNIKyG3nWlFoLVCoWPtBTd2gZM0aHOQp1JKa1birFBp2NofkEXbLeghZQ2YfCc4m8qgpZW5k/Itc0P/TVIkvPInjdSMyjm/ql4FUDO8cMkExJNR/i+GElW8cfnniWGcDPSiOqfIjLEDvZouXC7F1v5Wa0SmIxg7NJUTB+g6yrDN15VDq3KbHHTMlZXOZTXON2mBZOj5cwyyd4uX3aGSmYQiy/CGqBdqxrW2A==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDnjCCAoagAwIBAgIGAXHxS90vMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYDVQQGEwJVUzETMBEG
 A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
diff --git a/xml_constants.go b/xml_constants.go
index c4b815b..d2b98e2 100644
--- a/xml_constants.go
+++ b/xml_constants.go
@@ -47,11 +47,14 @@ const (
 //Well-known signature algorithms
 const (
 	// Supported canonicalization algorithms
-	CanonicalXML10ExclusiveAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#"
-	CanonicalXML11AlgorithmId          AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11"
+	CanonicalXML10ExclusiveAlgorithmId             AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#"
+	CanonicalXML10ExclusiveWithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
 
-	CanonicalXML10RecAlgorithmId     AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
-	CanonicalXML10CommentAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
+	CanonicalXML11AlgorithmId             AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11"
+	CanonicalXML11WithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11#WithComments"
+
+	CanonicalXML10RecAlgorithmId          AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
+	CanonicalXML10WithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
 
 	EnvelopedSignatureAltorithmId AlgorithmID = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
 )