From c7ea1a44b8dfc6c3978ef3d973c4116b41a4f8f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 08:59:14 +0000 Subject: [PATCH] Bump github.com/russellhaering/goxmldsig from 1.1.1 to 1.4.0 Bumps [github.com/russellhaering/goxmldsig](https://github.com/russellhaering/goxmldsig) from 1.1.1 to 1.4.0. - [Release notes](https://github.com/russellhaering/goxmldsig/releases) - [Commits](https://github.com/russellhaering/goxmldsig/compare/v1.1.1...v1.4.0) --- updated-dependencies: - dependency-name: github.com/russellhaering/goxmldsig dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../russellhaering/goxmldsig/README.md | 15 +- .../russellhaering/goxmldsig/canonicalize.go | 171 ++++++++++++++---- .../goxmldsig/etreeutils/canonicalize.go | 22 ++- .../goxmldsig/etreeutils/namespace.go | 49 +++-- .../goxmldsig/etreeutils/sort.go | 25 ++- .../russellhaering/goxmldsig/sign.go | 123 ++++++++++--- .../russellhaering/goxmldsig/validate.go | 57 +++--- .../russellhaering/goxmldsig/xml_constants.go | 74 ++++++-- vendor/modules.txt | 2 +- 11 files changed, 406 insertions(+), 138 deletions(-) diff --git a/go.mod b/go.mod index 8c46b8ab..9c003970 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.5 github.com/kr/pretty v0.3.0 github.com/mattermost/xml-roundtrip-validator v0.1.0 - github.com/russellhaering/goxmldsig v1.1.1 + github.com/russellhaering/goxmldsig v1.4.0 github.com/zenazn/goji v1.0.1 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 gotest.tools v2.2.0+incompatible diff --git a/go.sum b/go.sum index 600aad56..5ef66946 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/russellhaering/goxmldsig v1.1.1 h1:vI0r2osGF1A9PLvsGdPUAGwEIrKa4Pj5sesSBsebIxM= -github.com/russellhaering/goxmldsig v1.1.1/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= +github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= +github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= diff --git a/vendor/github.com/russellhaering/goxmldsig/README.md b/vendor/github.com/russellhaering/goxmldsig/README.md index 9464e61e..c572e8c7 100644 --- a/vendor/github.com/russellhaering/goxmldsig/README.md +++ b/vendor/github.com/russellhaering/goxmldsig/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. @@ -15,6 +15,19 @@ $ go get github.com/russellhaering/goxmldsig ## Usage +Include the [`types.Signature`](https://pkg.go.dev/github.com/russellhaering/goxmldsig/types#Signature) struct from this package in your application messages. + +```go +import ( + sigtypes "github.com/russellhaering/goxmldsig/types" +) + +type AppHdr struct { + ... + Signature *sigtypes.Signature +} +``` + ### Signing ```go diff --git a/vendor/github.com/russellhaering/goxmldsig/canonicalize.go b/vendor/github.com/russellhaering/goxmldsig/canonicalize.go index 05655ebc..4d51f4a0 100644 --- a/vendor/github.com/russellhaering/goxmldsig/canonicalize.go +++ b/vendor/github.com/russellhaering/goxmldsig/canonicalize.go @@ -25,12 +25,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, false, true)) } type c14N10ExclusiveCanonicalizer struct { prefixList string + comments bool } // MakeC14N10ExclusiveCanonicalizerWithPrefixList constructs an exclusive Canonicalizer @@ -38,12 +38,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 +62,74 @@ 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, 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)) +func (c *c14N10RecCanonicalizer) Canonicalize(inputXML *etree.Element) ([]byte, error) { + parentNamespaceAttributes, parentXmlAttributes := getParentNamespaceAndXmlAttributes(inputXML) + inputXMLCopy := inputXML.Copy() + enhanceNamespaceAttributes(inputXMLCopy, parentNamespaceAttributes, parentXmlAttributes) + return canonicalSerialize(canonicalPrep(inputXMLCopy, 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,24 +158,50 @@ 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 { - _seenSoFar := make(map[string]struct{}) +func canonicalPrep(el *etree.Element, strip bool, comments bool) *etree.Element { + return canonicalPrepInner(el, make(map[string]string), strip, comments) +} + +func canonicalPrepInner(el *etree.Element, seenSoFar map[string]string, strip bool, comments bool) *etree.Element { + _seenSoFar := make(map[string]string) for k, v := range seenSoFar { _seenSoFar[k] = v } ne := el.Copy() sort.Sort(etreeutils.SortedAttrs(ne.Attr)) - if len(ne.Attr) != 0 { - for _, attr := range ne.Attr { - if attr.Space != nsSpace { - continue - } + n := 0 + for _, attr := range ne.Attr { + if attr.Space != nsSpace && !(attr.Space == "" && attr.Key == nsSpace) { + ne.Attr[n] = attr + n++ + continue + } + + if attr.Space == nsSpace { key := attr.Space + ":" + attr.Key - if _, seen := _seenSoFar[key]; seen { - ne.RemoveAttr(attr.Space + ":" + attr.Key) + if uri, seen := _seenSoFar[key]; !seen || attr.Value != uri { + ne.Attr[n] = attr + n++ + _seenSoFar[key] = attr.Value + } + } else { + if uri, seen := _seenSoFar[nsSpace]; (!seen && attr.Value != "") || attr.Value != uri { + ne.Attr[n] = attr + n++ + _seenSoFar[nsSpace] = attr.Value + } + } + } + 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 +209,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] = canonicalPrepInner(childElement, _seenSoFar, strip, comments) } } @@ -176,3 +228,44 @@ func canonicalSerialize(el *etree.Element) ([]byte, error) { return doc.WriteToBytes() } + +func getParentNamespaceAndXmlAttributes(el *etree.Element) (map[string]string, map[string]string) { + namespaceMap := make(map[string]string, 23) + xmlMap := make(map[string]string, 5) + parents := make([]*etree.Element, 0, 23) + n1 := el.Parent() + if n1 == nil { + return namespaceMap, xmlMap + } + parent := n1 + for parent != nil { + parents = append(parents, parent) + parent = parent.Parent() + } + for i := len(parents) - 1; i > -1; i-- { + elementPos := parents[i] + for _, attr := range elementPos.Attr { + if attr.Space == "xmlns" && (attr.Key != "xml" || attr.Value != "http://www.w3.org/XML/1998/namespace") { + namespaceMap[attr.Key] = attr.Value + } else if attr.Space == "" && attr.Key == "xmlns" { + namespaceMap[attr.Key] = attr.Value + } else if attr.Space == "xml" { + xmlMap[attr.Key] = attr.Value + } + } + } + return namespaceMap, xmlMap +} + +func enhanceNamespaceAttributes(el *etree.Element, parentNamespaces map[string]string, parentXmlAttributes map[string]string) { + for prefix, uri := range parentNamespaces { + if prefix == "xmlns" { + el.CreateAttr("xmlns", uri) + } else { + el.CreateAttr("xmlns:"+prefix, uri) + } + } + for attr, value := range parentXmlAttributes { + el.CreateAttr("xml:"+attr, value) + } +} diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go index e9f8deb1..82ceb0a2 100644 --- a/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go +++ b/vendor/github.com/russellhaering/goxmldsig/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,8 @@ func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) e prefixSet[prefix] = struct{}{} } - err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet) + ctx := NewDefaultNSContext() + err := transformExcC14n(ctx, ctx, el, prefixSet, comments) if err != nil { return err } @@ -24,14 +25,14 @@ 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 } visiblyUtilizedPrefixes := map[string]struct{}{ - el.Space: struct{}{}, + el.Space: {}, } filteredAttrs := []etree.Attr{} @@ -86,9 +87,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/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go index baf1124f..6a5be036 100644 --- a/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go +++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go @@ -2,9 +2,7 @@ package etreeutils import ( "errors" - "fmt" - "sort" "github.com/beevik/etree" @@ -19,20 +17,25 @@ const ( XMLNSNamespace = "http://www.w3.org/2000/xmlns/" ) -var ( - DefaultNSContext = NSContext{ +func NewDefaultNSContext() NSContext { + defaultLimit := 1000 + return NSContext{ prefixes: map[string]string{ defaultPrefix: XMLNamespace, xmlPrefix: XMLNamespace, xmlnsPrefix: XMLNSNamespace, }, + limit: &defaultLimit, } +} +var ( EmptyNSContext = NSContext{} ErrReservedNamespace = errors.New("disallowed declaration of reserved namespace") ErrInvalidDefaultNamespace = errors.New("invalid default namespace declaration") ErrTraversalHalted = errors.New("traversal halted") + ErrTraversalLimit = errors.New("traversal limit reached") ) type ErrUndeclaredNSPrefix struct { @@ -45,6 +48,17 @@ func (e ErrUndeclaredNSPrefix) Error() string { type NSContext struct { prefixes map[string]string + limit *int +} + +// CheckLimit checks the traversal limit before calling the handler function +func (ctx NSContext) CheckLimit() error { + if *ctx.limit <= 0 { + return ErrTraversalLimit + } + *ctx.limit-- + + return nil } func (ctx NSContext) Copy() NSContext { @@ -53,7 +67,7 @@ func (ctx NSContext) Copy() NSContext { prefixes[k] = v } - return NSContext{prefixes: prefixes} + return NSContext{prefixes: prefixes, limit: ctx.limit} } func (ctx NSContext) declare(prefix, namespace string) etree.Attr { @@ -140,7 +154,12 @@ type NSIterHandler func(NSContext, *etree.Element) error // NSTraverse traverses an element tree, invoking the passed handler for each element // in the tree. func NSTraverse(ctx NSContext, el *etree.Element, handle NSIterHandler) error { - ctx, err := ctx.SubContext(el) + err := ctx.CheckLimit() + if err != nil { + return err + } + + ctx, err = ctx.SubContext(el) if err != nil { return err } @@ -223,7 +242,7 @@ func NSDetatch(ctx NSContext, el *etree.Element) (*etree.Element, error) { // NSSelectOne behaves identically to NSSelectOneCtx, but uses DefaultNSContext as the // surrounding context. func NSSelectOne(el *etree.Element, namespace, tag string) (*etree.Element, error) { - return NSSelectOneCtx(DefaultNSContext, el, namespace, tag) + return NSSelectOneCtx(NewDefaultNSContext(), el, namespace, tag) } // NSSelectOneCtx conducts a depth-first search for an element with the specified namespace @@ -243,7 +262,6 @@ func NSSelectOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*e return ErrTraversalHalted }) - if err != nil { return nil, err } @@ -254,7 +272,7 @@ func NSSelectOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*e // NSFindIterate behaves identically to NSFindIterateCtx, but uses DefaultNSContext // as the surrounding context. func NSFindIterate(el *etree.Element, namespace, tag string, handle NSIterHandler) error { - return NSFindIterateCtx(DefaultNSContext, el, namespace, tag, handle) + return NSFindIterateCtx(NewDefaultNSContext(), el, namespace, tag, handle) } // NSFindIterateCtx conducts a depth-first traversal searching for elements with the @@ -294,7 +312,7 @@ func NSFindIterateCtx(ctx NSContext, el *etree.Element, namespace, tag string, h // NSFindOne behaves identically to NSFindOneCtx, but uses DefaultNSContext for // context. func NSFindOne(el *etree.Element, namespace, tag string) (*etree.Element, error) { - return NSFindOneCtx(DefaultNSContext, el, namespace, tag) + return NSFindOneCtx(NewDefaultNSContext(), el, namespace, tag) } // NSFindOneCtx conducts a depth-first search for the specified element. If such an element @@ -306,7 +324,6 @@ func NSFindOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etr found = el return ErrTraversalHalted }) - if err != nil { return nil, err } @@ -325,6 +342,11 @@ func NSIterateChildren(ctx NSContext, el *etree.Element, handle NSIterHandler) e // Iterate the child elements. for _, child := range el.ChildElements() { + err := ctx.CheckLimit() + if err != nil { + return err + } + err = handle(ctx, child) if err != nil { return err @@ -368,7 +390,7 @@ func NSFindChildrenIterateCtx(ctx NSContext, el *etree.Element, namespace, tag s // NSFindOneChild behaves identically to NSFindOneChildCtx, but uses // DefaultNSContext for context. func NSFindOneChild(el *etree.Element, namespace, tag string) (*etree.Element, error) { - return NSFindOneChildCtx(DefaultNSContext, el, namespace, tag) + return NSFindOneChildCtx(NewDefaultNSContext(), el, namespace, tag) } // NSFindOneCtx conducts a depth-first search for the specified element. If such an @@ -394,11 +416,10 @@ func NSFindOneChildCtx(ctx NSContext, el *etree.Element, namespace, tag string) func NSBuildParentContext(el *etree.Element) (NSContext, error) { parent := el.Parent() if parent == nil { - return DefaultNSContext, nil + return NewDefaultNSContext(), nil } ctx, err := NSBuildParentContext(parent) - if err != nil { return ctx, err } diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go index 5871a391..1dc62829 100644 --- a/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go +++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go @@ -55,12 +55,29 @@ func (a SortedAttrs) Less(i, j int) bool { return false } - // Wow. We're still going. Finally, attributes in the same namespace should be - // sorted by key. Attributes in different namespaces should be sorted by the - // actual namespace (_not_ the prefix). For now just use the prefix. + // Attributes with the same prefix should be sorted by their keys. if a[i].Space == a[j].Space { return a[i].Key < a[j].Key } - return a[i].Space < a[j].Space + // Attributes in the same namespace are sorted by their Namespace URI, not the prefix. + // NOTE: This implementation is not complete because it does not consider namespace + // prefixes declared in ancestor elements. A complete solution would ideally use the + // Attribute.NamespaceURI() method obtain a namespace URI for sorting, but the + // beevik/etree library needs to be fixed to provide the correct value first. + if a[i].Key == a[j].Key { + var leftNS, rightNS etree.Attr + for n := range a { + if a[i].Space == a[n].Key { + leftNS = a[n] + } + if a[j].Space == a[n].Key { + rightNS = a[n] + } + } + // Sort based on the NS URIs + return leftNS.Value < rightNS.Value + } + + return a[i].Key < a[j].Key } diff --git a/vendor/github.com/russellhaering/goxmldsig/sign.go b/vendor/github.com/russellhaering/goxmldsig/sign.go index 2be34b7f..cc77f790 100644 --- a/vendor/github.com/russellhaering/goxmldsig/sign.go +++ b/vendor/github.com/russellhaering/goxmldsig/sign.go @@ -2,10 +2,12 @@ package dsig import ( "crypto" + "crypto/ecdsa" "crypto/rand" "crypto/rsa" _ "crypto/sha1" _ "crypto/sha256" + "crypto/x509" "encoding/base64" "errors" "fmt" @@ -15,11 +17,18 @@ import ( ) type SigningContext struct { - Hash crypto.Hash + Hash crypto.Hash + + // This field will be nil and unused if the SigningContext is created with + // NewSigningContext KeyStore X509KeyStore IdAttribute string Prefix string Canonicalizer Canonicalizer + + // KeyStore is mutually exclusive with signer and certs + signer crypto.Signer + certs [][]byte } func NewDefaultSigningContext(ks X509KeyStore) *SigningContext { @@ -32,13 +41,54 @@ func NewDefaultSigningContext(ks X509KeyStore) *SigningContext { } } +// NewSigningContext creates a new signing context with the given signer and certificate chain. +// Note that e.g. rsa.PrivateKey implements the crypto.Signer interface. +// The certificate chain is a slice of ASN.1 DER-encoded X.509 certificates. +// A SigningContext created with this function should not use the KeyStore field. +// It will return error if passed a nil crypto.Signer +func NewSigningContext(signer crypto.Signer, certs [][]byte) (*SigningContext, error) { + if signer == nil { + return nil, errors.New("signer cannot be nil for NewSigningContext") + } + ctx := &SigningContext{ + Hash: crypto.SHA256, + IdAttribute: DefaultIdAttr, + Prefix: DefaultPrefix, + Canonicalizer: MakeC14N11Canonicalizer(), + + signer: signer, + certs: certs, + } + return ctx, nil +} + +func (ctx *SigningContext) getPublicKeyAlgorithm() x509.PublicKeyAlgorithm { + if ctx.KeyStore != nil { + return x509.RSA + } else { + switch ctx.signer.Public().(type) { + case *ecdsa.PublicKey: + return x509.ECDSA + case *rsa.PublicKey: + return x509.RSA + } + } + + return x509.UnknownPublicKeyAlgorithm +} + func (ctx *SigningContext) SetSignatureMethod(algorithmID string) error { - hash, ok := signatureMethodsByIdentifier[algorithmID] + info, ok := signatureMethodsByIdentifier[algorithmID] if !ok { - return fmt.Errorf("Unknown SignatureMethod: %s", algorithmID) + return fmt.Errorf("unknown SignatureMethod: %s", algorithmID) } - ctx.Hash = hash + algo := ctx.getPublicKeyAlgorithm() + if info.PublicKeyAlgorithm != algo { + return fmt.Errorf("SignatureMethod %s is incompatible with %s key", algorithmID, algo) + } + + ctx.Hash = info.Hash return nil } @@ -58,6 +108,46 @@ func (ctx *SigningContext) digest(el *etree.Element) ([]byte, error) { return hash.Sum(nil), nil } +func (ctx *SigningContext) signDigest(digest []byte) ([]byte, error) { + if ctx.KeyStore != nil { + key, _, err := ctx.KeyStore.GetKeyPair() + if err != nil { + return nil, err + } + + rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest) + if err != nil { + return nil, err + } + + return rawSignature, nil + } else { + rawSignature, err := ctx.signer.Sign(rand.Reader, digest, ctx.Hash) + if err != nil { + return nil, err + } + + return rawSignature, nil + } +} + +func (ctx *SigningContext) getCerts() ([][]byte, error) { + if ctx.KeyStore != nil { + if cs, ok := ctx.KeyStore.(X509ChainStore); ok { + return cs.GetChain() + } + + _, cert, err := ctx.KeyStore.GetKeyPair() + if err != nil { + return nil, err + } + + return [][]byte{cert}, nil + } else { + return ctx.certs, nil + } +} + func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool) (*etree.Element, error) { digestAlgorithmIdentifier := ctx.GetDigestAlgorithmIdentifier() if digestAlgorithmIdentifier == "" { @@ -97,7 +187,6 @@ func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool reference.CreateAttr(URIAttr, "#"+dataId) } - // /SignedInfo/Reference/Transforms transforms := ctx.createNamespacedElement(reference, TransformsTag) if enveloped { @@ -172,20 +261,12 @@ func (ctx *SigningContext) ConstructSignature(el *etree.Element, enveloped bool) return nil, err } - key, cert, err := ctx.KeyStore.GetKeyPair() + rawSignature, err := ctx.signDigest(digest) if err != nil { return nil, err } - certs := [][]byte{cert} - if cs, ok := ctx.KeyStore.(X509ChainStore); ok { - certs, err = cs.GetChain() - if err != nil { - return nil, err - } - } - - rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest) + certs, err := ctx.getCerts() if err != nil { return nil, err } @@ -222,7 +303,9 @@ func (ctx *SigningContext) SignEnveloped(el *etree.Element) (*etree.Element, err } func (ctx *SigningContext) GetSignatureMethodIdentifier() string { - if ident, ok := signatureMethodIdentifiers[ctx.Hash]; ok { + algo := ctx.getPublicKeyAlgorithm() + + if ident, ok := signatureMethodIdentifiers[algo][ctx.Hash]; ok { return ident } return "" @@ -247,11 +330,5 @@ func (ctx *SigningContext) SignString(content string) ([]byte, error) { } digest := hash.Sum(nil) - var signature []byte - if key, _, err := ctx.KeyStore.GetKeyPair(); err != nil { - return nil, fmt.Errorf("unable to fetch key for signing: %v", err) - } else if signature, err = rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest); err != nil { - return nil, fmt.Errorf("error signing: %v", err) - } - return signature, nil + return ctx.signDigest(digest) } diff --git a/vendor/github.com/russellhaering/goxmldsig/validate.go b/vendor/github.com/russellhaering/goxmldsig/validate.go index 84045858..3d0fc973 100644 --- a/vendor/github.com/russellhaering/goxmldsig/validate.go +++ b/vendor/github.com/russellhaering/goxmldsig/validate.go @@ -2,7 +2,6 @@ package dsig import ( "bytes" - "crypto/rsa" "crypto/x509" "encoding/base64" "errors" @@ -21,7 +20,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 +69,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 +137,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) @@ -202,26 +212,12 @@ func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicaliz return err } - signatureAlgorithm, ok := signatureMethodsByIdentifier[signatureMethodId] + algo, ok := x509SignatureAlgorithmByIdentifier[signatureMethodId] if !ok { return errors.New("Unknown signature method: " + signatureMethodId) } - hash := signatureAlgorithm.New() - _, err = hash.Write(canonical) - if err != nil { - return err - } - - hashed := hash.Sum(nil) - - pubKey, ok := cert.PublicKey.(*rsa.PublicKey) - if !ok { - return errors.New("Invalid public key") - } - - // Verify that the private key matching the public key from the cert was what was used to sign the 'SignedInfo' and produce the 'SignatureValue' - err = rsa.VerifyPKCS1v15(pubKey, signatureAlgorithm, hashed[:], decodedSignature) + err = cert.CheckSignature(algo, canonical, decodedSignature) if err != nil { return err } @@ -353,9 +349,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,21 +362,18 @@ 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, true, false) - case CanonicalXML10CommentAlgorithmId: - canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true) + case CanonicalXML11WithCommentsAlgorithmId, CanonicalXML10WithCommentsAlgorithmId: + canonicalSignedInfo = canonicalPrep(detachedSignedInfo, true, true) default: return fmt.Errorf("invalid CanonicalizationMethod on Signature: %s", c14NAlgorithm) } + signatureEl.InsertChildAt(signedInfo.Index(), canonicalSignedInfo) signatureEl.RemoveChild(signedInfo) - signatureEl.AddChild(canonicalSignedInfo) found = true diff --git a/vendor/github.com/russellhaering/goxmldsig/xml_constants.go b/vendor/github.com/russellhaering/goxmldsig/xml_constants.go index c4b815b2..0526062e 100644 --- a/vendor/github.com/russellhaering/goxmldsig/xml_constants.go +++ b/vendor/github.com/russellhaering/goxmldsig/xml_constants.go @@ -1,6 +1,9 @@ package dsig -import "crypto" +import ( + "crypto" + "crypto/x509" +) const ( DefaultPrefix = "ds" @@ -39,19 +42,27 @@ func (id AlgorithmID) String() string { } const ( - RSASHA1SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1" - RSASHA256SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" - RSASHA512SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" + RSASHA1SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1" + RSASHA256SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" + RSASHA384SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384" + RSASHA512SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" + ECDSASHA1SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1" + ECDSASHA256SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256" + ECDSASHA384SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384" + ECDSASHA512SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512" ) -//Well-known signature algorithms +// 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" + + 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" - CanonicalXML10CommentAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#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" ) @@ -59,23 +70,54 @@ const ( var digestAlgorithmIdentifiers = map[crypto.Hash]string{ crypto.SHA1: "http://www.w3.org/2000/09/xmldsig#sha1", crypto.SHA256: "http://www.w3.org/2001/04/xmlenc#sha256", + crypto.SHA384: "http://www.w3.org/2001/04/xmldsig-more#sha384", crypto.SHA512: "http://www.w3.org/2001/04/xmlenc#sha512", } +type signatureMethodInfo struct { + PublicKeyAlgorithm x509.PublicKeyAlgorithm + Hash crypto.Hash +} + var digestAlgorithmsByIdentifier = map[string]crypto.Hash{} -var signatureMethodsByIdentifier = map[string]crypto.Hash{} +var signatureMethodsByIdentifier = map[string]signatureMethodInfo{} func init() { for hash, id := range digestAlgorithmIdentifiers { digestAlgorithmsByIdentifier[id] = hash } - for hash, id := range signatureMethodIdentifiers { - signatureMethodsByIdentifier[id] = hash + for algo, hashToMethod := range signatureMethodIdentifiers { + for hash, method := range hashToMethod { + signatureMethodsByIdentifier[method] = signatureMethodInfo{ + PublicKeyAlgorithm: algo, + Hash: hash, + } + } } } -var signatureMethodIdentifiers = map[crypto.Hash]string{ - crypto.SHA1: RSASHA1SignatureMethod, - crypto.SHA256: RSASHA256SignatureMethod, - crypto.SHA512: RSASHA512SignatureMethod, +var signatureMethodIdentifiers = map[x509.PublicKeyAlgorithm]map[crypto.Hash]string{ + x509.RSA: { + crypto.SHA1: RSASHA1SignatureMethod, + crypto.SHA256: RSASHA256SignatureMethod, + crypto.SHA384: RSASHA384SignatureMethod, + crypto.SHA512: RSASHA512SignatureMethod, + }, + x509.ECDSA: { + crypto.SHA1: ECDSASHA1SignatureMethod, + crypto.SHA256: ECDSASHA256SignatureMethod, + crypto.SHA384: ECDSASHA384SignatureMethod, + crypto.SHA512: ECDSASHA512SignatureMethod, + }, +} + +var x509SignatureAlgorithmByIdentifier = map[string]x509.SignatureAlgorithm{ + RSASHA1SignatureMethod: x509.SHA1WithRSA, + RSASHA256SignatureMethod: x509.SHA256WithRSA, + RSASHA384SignatureMethod: x509.SHA384WithRSA, + RSASHA512SignatureMethod: x509.SHA512WithRSA, + ECDSASHA1SignatureMethod: x509.ECDSAWithSHA1, + ECDSASHA256SignatureMethod: x509.ECDSAWithSHA256, + ECDSASHA384SignatureMethod: x509.ECDSAWithSHA384, + ECDSASHA512SignatureMethod: x509.ECDSAWithSHA512, } diff --git a/vendor/modules.txt b/vendor/modules.txt index 3147a2da..08efaf1c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -37,7 +37,7 @@ github.com/pkg/errors # github.com/rogpeppe/go-internal v1.8.0 ## explicit; go 1.11 github.com/rogpeppe/go-internal/fmtsort -# github.com/russellhaering/goxmldsig v1.1.1 +# github.com/russellhaering/goxmldsig v1.4.0 ## explicit; go 1.15 github.com/russellhaering/goxmldsig github.com/russellhaering/goxmldsig/etreeutils