Codebase list golang-github-russellhaering-goxmldsig / 4dae618
Import upstream version 1.2.0 Debian Janitor 1 year, 4 months ago
8 changed file(s) with 176 addition(s) and 65 deletion(s). Raw diff Collapse all Expand all
0 on: [push, pull_request]
1 name: Test
2 jobs:
3 test:
4 name: Test Go ${{ matrix.go }}
5 runs-on: ubuntu-20.04
6 strategy:
7 matrix:
8 go: ['1.17', '1.16']
9 steps:
10 - uses: actions/checkout@v2
11 - name: Setup Go
12 uses: actions/setup-go@v2
13 with:
14 go-version: ${{ matrix.go }}
15 - name: Test
16 run: go test ./...
00 # goxmldsig
11
2 [![Build Status](https://travis-ci.org/russellhaering/goxmldsig.svg?branch=master)](https://travis-ci.org/russellhaering/goxmldsig)
2 ![Build Status](https://github.com/russellhaering/goxmldsig/actions/workflows/test.yml/badge.svg?branch=main)
33 [![GoDoc](https://godoc.org/github.com/russellhaering/goxmldsig?status.svg)](https://godoc.org/github.com/russellhaering/goxmldsig)
44
55 XML Digital Signatures implemented in pure Go.
2525
2626 func (c *NullCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
2727 scope := make(map[string]struct{})
28 return canonicalSerialize(canonicalPrep(el, scope, false))
28 return canonicalSerialize(canonicalPrep(el, scope, false, true))
2929 }
3030
3131 type c14N10ExclusiveCanonicalizer struct {
3232 prefixList string
33 comments bool
3334 }
3435
3536 // MakeC14N10ExclusiveCanonicalizerWithPrefixList constructs an exclusive Canonicalizer
3738 func MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList string) Canonicalizer {
3839 return &c14N10ExclusiveCanonicalizer{
3940 prefixList: prefixList,
41 comments: false,
42 }
43 }
44
45 // MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList constructs an exclusive Canonicalizer
46 // from a PrefixList in NMTOKENS format (a white space separated list).
47 func MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList(prefixList string) Canonicalizer {
48 return &c14N10ExclusiveCanonicalizer{
49 prefixList: prefixList,
50 comments: true,
4051 }
4152 }
4253
4354 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
4455 func (c *c14N10ExclusiveCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
45 err := etreeutils.TransformExcC14n(el, c.prefixList)
56 err := etreeutils.TransformExcC14n(el, c.prefixList, c.comments)
4657 if err != nil {
4758 return nil, err
4859 }
5162 }
5263
5364 func (c *c14N10ExclusiveCanonicalizer) Algorithm() AlgorithmID {
65 if c.comments {
66 return CanonicalXML10ExclusiveWithCommentsAlgorithmId
67 }
5468 return CanonicalXML10ExclusiveAlgorithmId
5569 }
5670
57 type c14N11Canonicalizer struct{}
71 type c14N11Canonicalizer struct {
72 comments bool
73 }
5874
5975 // MakeC14N11Canonicalizer constructs an inclusive canonicalizer.
6076 func MakeC14N11Canonicalizer() Canonicalizer {
61 return &c14N11Canonicalizer{}
77 return &c14N11Canonicalizer{
78 comments: false,
79 }
80 }
81
82 // MakeC14N11WithCommentsCanonicalizer constructs an inclusive canonicalizer.
83 func MakeC14N11WithCommentsCanonicalizer() Canonicalizer {
84 return &c14N11Canonicalizer{
85 comments: true,
86 }
6287 }
6388
6489 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
6590 func (c *c14N11Canonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
6691 scope := make(map[string]struct{})
67 return canonicalSerialize(canonicalPrep(el, scope, true))
92 return canonicalSerialize(canonicalPrep(el, scope, true, c.comments))
6893 }
6994
7095 func (c *c14N11Canonicalizer) Algorithm() AlgorithmID {
96 if c.comments {
97 return CanonicalXML11WithCommentsAlgorithmId
98 }
7199 return CanonicalXML11AlgorithmId
72100 }
73101
74 type c14N10RecCanonicalizer struct{}
102 type c14N10RecCanonicalizer struct {
103 comments bool
104 }
75105
76106 // MakeC14N10RecCanonicalizer constructs an inclusive canonicalizer.
77107 func MakeC14N10RecCanonicalizer() Canonicalizer {
78 return &c14N10RecCanonicalizer{}
108 return &c14N10RecCanonicalizer{
109 comments: false,
110 }
111 }
112
113 // MakeC14N10WithCommentsCanonicalizer constructs an inclusive canonicalizer.
114 func MakeC14N10WithCommentsCanonicalizer() Canonicalizer {
115 return &c14N10RecCanonicalizer{
116 comments: true,
117 }
79118 }
80119
81120 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
82121 func (c *c14N10RecCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
83122 scope := make(map[string]struct{})
84 return canonicalSerialize(canonicalPrep(el, scope, true))
123 return canonicalSerialize(canonicalPrep(el, scope, true, c.comments))
85124 }
86125
87126 func (c *c14N10RecCanonicalizer) Algorithm() AlgorithmID {
127 if c.comments {
128 return CanonicalXML10WithCommentsAlgorithmId
129 }
88130 return CanonicalXML10RecAlgorithmId
89 }
90
91 type c14N10CommentCanonicalizer struct{}
92
93 // MakeC14N10CommentCanonicalizer constructs an inclusive canonicalizer.
94 func MakeC14N10CommentCanonicalizer() Canonicalizer {
95 return &c14N10CommentCanonicalizer{}
96 }
97
98 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
99 func (c *c14N10CommentCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
100 scope := make(map[string]struct{})
101 return canonicalSerialize(canonicalPrep(el, scope, true))
102 }
103
104 func (c *c14N10CommentCanonicalizer) Algorithm() AlgorithmID {
105 return CanonicalXML10CommentAlgorithmId
131
106132 }
107133
108134 func composeAttr(space, key string) string {
131157 //
132158 // TODO(russell_h): This is very similar to excCanonicalPrep - perhaps they should
133159 // be unified into one parameterized function?
134 func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}, strip bool) *etree.Element {
160 func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}, strip bool, comments bool) *etree.Element {
135161 _seenSoFar := make(map[string]struct{})
136162 for k, v := range seenSoFar {
137163 _seenSoFar[k] = v
139165
140166 ne := el.Copy()
141167 sort.Sort(etreeutils.SortedAttrs(ne.Attr))
142 if len(ne.Attr) != 0 {
143 for _, attr := range ne.Attr {
144 if attr.Space != nsSpace {
145 continue
146 }
147 key := attr.Space + ":" + attr.Key
148 if _, seen := _seenSoFar[key]; seen {
149 ne.RemoveAttr(attr.Space + ":" + attr.Key)
168 n := 0
169 for _, attr := range ne.Attr {
170 if attr.Space != nsSpace {
171 ne.Attr[n] = attr
172 n++
173 continue
174 }
175 key := attr.Space + ":" + attr.Key
176 if _, seen := _seenSoFar[key]; !seen {
177 ne.Attr[n] = attr
178 n++
179 _seenSoFar[key] = struct{}{}
180 }
181 }
182 ne.Attr = ne.Attr[:n]
183
184 if !comments {
185 c := 0
186 for c < len(ne.Child) {
187 if _, ok := ne.Child[c].(*etree.Comment); ok {
188 ne.RemoveChildAt(c)
150189 } else {
151 _seenSoFar[key] = struct{}{}
190 c++
152191 }
153192 }
154193 }
156195 for i, token := range ne.Child {
157196 childElement, ok := token.(*etree.Element)
158197 if ok {
159 ne.Child[i] = canonicalPrep(childElement, _seenSoFar, strip)
198 ne.Child[i] = canonicalPrep(childElement, _seenSoFar, strip, comments)
160199 }
161200 }
162201
77 )
88
99 const (
10 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>`
11 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>`
12 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>`
10 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>`
11 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>`
12 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>`
13 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>`
14 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>`
1315 )
1416
1517 const (
3234 runCanonicalizationTest(t, MakeC14N10ExclusiveCanonicalizerWithPrefixList(""), assertion, assertionC14ned)
3335 }
3436
37 func TestExcC14N10WithComments(t *testing.T) {
38 runCanonicalizationTest(t, MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList(""), assertion, assertionC14nedComment)
39 }
40
3541 func TestC14N11(t *testing.T) {
3642 runCanonicalizationTest(t, MakeC14N11Canonicalizer(), assertion, c14n11)
43 }
44
45 func TestC14N11WithComments(t *testing.T) {
46 runCanonicalizationTest(t, MakeC14N11WithCommentsCanonicalizer(), assertion, c14n11Comment)
3747 }
3848
3949 func TestXmldocC14N10Exclusive(t *testing.T) {
4252
4353 func TestXmldocC14N11(t *testing.T) {
4454 runCanonicalizationTest(t, MakeC14N11Canonicalizer(), xmldoc, xmldocC14N11Canonicalized)
55 }
56
57 func TestNestedExcC14N11(t *testing.T) {
58 input := `<X xmlns:x="x" xmlns:y="y"><Y xmlns:x="x" xmlns:y="y" xmlns:z="z"/></X>`
59 expected := `<X xmlns:x="x" xmlns:y="y"><Y xmlns:z="z"></Y></X>`
60 runCanonicalizationTest(t, MakeC14N11Canonicalizer(), input, expected)
4561 }
4662
4763 func TestExcC14nDefaultNamespace(t *testing.T) {
77 )
88
99 // TransformExcC14n transforms the passed element into xml-exc-c14n form.
10 func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) error {
10 func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string, comments bool) error {
1111 prefixes := strings.Fields(inclusiveNamespacesPrefixList)
1212 prefixSet := make(map[string]struct{}, len(prefixes))
1313
1515 prefixSet[prefix] = struct{}{}
1616 }
1717
18 err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet)
18 err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet, comments)
1919 if err != nil {
2020 return err
2121 }
2323 return nil
2424 }
2525
26 func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNamespaces map[string]struct{}) error {
26 func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNamespaces map[string]struct{}, comments bool) error {
2727 scope, err := ctx.SubContext(el)
2828 if err != nil {
2929 return err
8585
8686 sort.Sort(SortedAttrs(el.Attr))
8787
88 if !comments {
89 c := 0
90 for c < len(el.Child) {
91 if _, ok := el.Child[c].(*etree.Comment); ok {
92 el.RemoveChildAt(c)
93 } else {
94 c++
95 }
96 }
97 }
98
8899 // Transform child elements
89100 for _, child := range el.ChildElements() {
90 err := transformExcC14n(scope, declared, child, inclusiveNamespaces)
101 err := transformExcC14n(scope, declared, child, inclusiveNamespaces, comments)
91102 if err != nil {
92103 return err
93104 }
2020 // ErrMissingSignature indicates that no enveloped signature was found referencing
2121 // the top level element passed for signature verification.
2222 ErrMissingSignature = errors.New("Missing signature referencing the top-level element")
23 ErrInvalidSignature = errors.New( "Invalid Signature")
23 ErrInvalidSignature = errors.New("Invalid Signature")
2424 )
2525
2626 type ValidationContext struct {
6969 for i, child := range tree.Child {
7070 if childElement, ok := child.(*etree.Element); ok {
7171 childPath := mapPathToElement(childElement, el)
72 if childElement != nil {
72 if childPath != nil {
7373 return append([]int{i}, childPath...)
7474 }
7575 }
137137
138138 canonicalizer = MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList)
139139
140 case CanonicalXML10ExclusiveWithCommentsAlgorithmId:
141 var prefixList string
142 if transform.InclusiveNamespaces != nil {
143 prefixList = transform.InclusiveNamespaces.PrefixList
144 }
145
146 canonicalizer = MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList(prefixList)
147
140148 case CanonicalXML11AlgorithmId:
141149 canonicalizer = MakeC14N11Canonicalizer()
142150
151 case CanonicalXML11WithCommentsAlgorithmId:
152 canonicalizer = MakeC14N11WithCommentsCanonicalizer()
153
143154 case CanonicalXML10RecAlgorithmId:
144155 canonicalizer = MakeC14N10RecCanonicalizer()
145156
146 case CanonicalXML10CommentAlgorithmId:
147 canonicalizer = MakeC14N10CommentCanonicalizer()
157 case CanonicalXML10WithCommentsAlgorithmId:
158 canonicalizer = MakeC14N10WithCommentsCanonicalizer()
148159
149160 default:
150161 return nil, nil, errors.New("Unknown Transform Algorithm: " + algo)
352363
353364 var canonicalSignedInfo *etree.Element
354365
355 switch AlgorithmID(c14NAlgorithm) {
356 case CanonicalXML10ExclusiveAlgorithmId:
357 err := etreeutils.TransformExcC14n(detachedSignedInfo, "")
366 switch alg := AlgorithmID(c14NAlgorithm); alg {
367 case CanonicalXML10ExclusiveAlgorithmId, CanonicalXML10ExclusiveWithCommentsAlgorithmId:
368 err := etreeutils.TransformExcC14n(detachedSignedInfo, "", alg == CanonicalXML10ExclusiveWithCommentsAlgorithmId)
358369 if err != nil {
359370 return err
360371 }
365376 // removing of elements below.
366377 canonicalSignedInfo = detachedSignedInfo
367378
368 case CanonicalXML11AlgorithmId:
369 canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true)
370
371 case CanonicalXML10RecAlgorithmId:
372 canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true)
373
374 case CanonicalXML10CommentAlgorithmId:
375 canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true)
379 case CanonicalXML11AlgorithmId, CanonicalXML10RecAlgorithmId:
380 canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true, false)
381
382 case CanonicalXML11WithCommentsAlgorithmId, CanonicalXML10WithCommentsAlgorithmId:
383 canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true, true)
376384
377385 default:
378386 return fmt.Errorf("invalid CanonicalizationMethod on Signature: %s", c14NAlgorithm)
66 "testing"
77
88 "github.com/beevik/etree"
9 "github.com/russellhaering/goxmldsig/etreeutils"
910 "github.com/stretchr/testify/require"
1011 )
1112
248249 require.NotEmpty(t, el)
249250 }
250251
251
252252 func TestValidateWithModified(t *testing.T) {
253253 doc := etree.NewDocument()
254254 err := doc.ReadFromBytes([]byte(modifiedToBeTodd))
267267 require.Error(t, err)
268268 }
269269
270
271270 func TestValidateWithModifiedAndSignatureEdited(t *testing.T) {
272271 doc := etree.NewDocument()
273272 err := doc.ReadFromBytes([]byte(spoofedAsTodd))
286285 require.Error(t, err)
287286 }
288287
288 func TestMapPathAndRemove(t *testing.T) {
289 doc := etree.NewDocument()
290 err := doc.ReadFromString(`<X><Y/><Y><RemoveMe xmlns="x"/></Y></X>`)
291 require.NoError(t, err)
292
293 el, err := etreeutils.NSFindOne(doc.Root(), "x", "RemoveMe")
294 require.NoError(t, err)
295 require.NotNil(t, el)
296
297 path := mapPathToElement(doc.Root(), el)
298 removed := removeElementAtPath(doc.Root(), path)
299 require.True(t, removed)
300
301 el, err = etreeutils.NSFindOne(doc.Root(), "x", "RemoveMe")
302 require.NoError(t, err)
303 require.Nil(t, el)
304 }
305
289306 const (
290307 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
291308 A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
4646 //Well-known signature algorithms
4747 const (
4848 // Supported canonicalization algorithms
49 CanonicalXML10ExclusiveAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#"
50 CanonicalXML11AlgorithmId AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11"
49 CanonicalXML10ExclusiveAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#"
50 CanonicalXML10ExclusiveWithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
5151
52 CanonicalXML10RecAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
53 CanonicalXML10CommentAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
52 CanonicalXML11AlgorithmId AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11"
53 CanonicalXML11WithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11#WithComments"
54
55 CanonicalXML10RecAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
56 CanonicalXML10WithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
5457
5558 EnvelopedSignatureAltorithmId AlgorithmID = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
5659 )