vendor: revendor
This commit is contained in:
123
vendor/github.com/russellhaering/goxmldsig/validate.go
generated
vendored
123
vendor/github.com/russellhaering/goxmldsig/validate.go
generated
vendored
@@ -5,16 +5,22 @@ import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/beevik/etree"
|
||||
"github.com/russellhaering/goxmldsig/etreeutils"
|
||||
)
|
||||
|
||||
var uriRegexp = regexp.MustCompile("^#[a-zA-Z_][\\w.-]*$")
|
||||
|
||||
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")
|
||||
)
|
||||
|
||||
type ValidationContext struct {
|
||||
CertificateStore X509CertificateStore
|
||||
IdAttribute string
|
||||
@@ -186,21 +192,7 @@ func (ctx *ValidationContext) verifySignedInfo(signatureElement *etree.Element,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctx *ValidationContext) validateSignature(el *etree.Element, cert *x509.Certificate) (*etree.Element, error) {
|
||||
el = el.Copy()
|
||||
|
||||
// Verify the document minus the signedInfo against the 'DigestValue'
|
||||
// Find the 'Signature' element
|
||||
sig := el.FindElement(SignatureTag)
|
||||
|
||||
if sig == nil {
|
||||
return nil, errors.New("Missing Signature")
|
||||
}
|
||||
|
||||
if !inNamespace(sig, Namespace) {
|
||||
return nil, errors.New("Signature element is in the wrong namespace")
|
||||
}
|
||||
|
||||
func (ctx *ValidationContext) validateSignature(el, sig *etree.Element, cert *x509.Certificate) (*etree.Element, error) {
|
||||
// Get the 'SignedInfo' element
|
||||
signedInfo := sig.FindElement(childPath(sig.Space, SignedInfoTag))
|
||||
if signedInfo == nil {
|
||||
@@ -224,10 +216,6 @@ func (ctx *ValidationContext) validateSignature(el *etree.Element, cert *x509.Ce
|
||||
return nil, errors.New("Reference is missing URI attribute")
|
||||
}
|
||||
|
||||
if !uriRegexp.MatchString(uri.Value) {
|
||||
return nil, errors.New("Invalid URI: " + uri.Value)
|
||||
}
|
||||
|
||||
// Get the element referenced in the 'SignedInfo'
|
||||
referencedElement := el.FindElement(fmt.Sprintf("//[@%s='%s']", ctx.IdAttribute, uri.Value[1:]))
|
||||
if referencedElement == nil {
|
||||
@@ -311,69 +299,85 @@ func contains(roots []*x509.Certificate, cert *x509.Certificate) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ctx *ValidationContext) verifyCertificate(el *etree.Element) (*x509.Certificate, error) {
|
||||
now := ctx.Clock.Now()
|
||||
el = el.Copy()
|
||||
|
||||
// findSignature searches for a Signature element referencing the passed root element.
|
||||
func (ctx *ValidationContext) findSignature(el *etree.Element) (*etree.Element, error) {
|
||||
idAttr := el.SelectAttr(DefaultIdAttr)
|
||||
if idAttr == nil || idAttr.Value == "" {
|
||||
return nil, errors.New("Missing ID attribute")
|
||||
}
|
||||
|
||||
signatureElements := el.FindElements("//" + SignatureTag)
|
||||
var signatureElement *etree.Element
|
||||
|
||||
// Find the Signature element that references the whole Response element
|
||||
for _, e := range signatureElements {
|
||||
e2 := e.Copy()
|
||||
|
||||
signedInfo := e2.FindElement(childPath(e2.Space, SignedInfoTag))
|
||||
err := etreeutils.NSFindIterate(el, Namespace, SignatureTag, func(sig *etree.Element) error {
|
||||
signedInfo := sig.FindElement(childPath(sig.Space, SignedInfoTag))
|
||||
if signedInfo == nil {
|
||||
return nil, errors.New("Missing SignedInfo")
|
||||
return errors.New("Missing SignedInfo")
|
||||
}
|
||||
|
||||
referenceElement := signedInfo.FindElement(childPath(e2.Space, ReferenceTag))
|
||||
referenceElement := signedInfo.FindElement(childPath(sig.Space, ReferenceTag))
|
||||
if referenceElement == nil {
|
||||
return nil, errors.New("Missing Reference Element")
|
||||
return errors.New("Missing Reference Element")
|
||||
}
|
||||
|
||||
uriAttr := referenceElement.SelectAttr(URIAttr)
|
||||
if uriAttr == nil || uriAttr.Value == "" {
|
||||
return nil, errors.New("Missing URI attribute")
|
||||
return errors.New("Missing URI attribute")
|
||||
}
|
||||
|
||||
if !uriRegexp.MatchString(uriAttr.Value) {
|
||||
return errors.New("Invalid URI: " + uriAttr.Value)
|
||||
}
|
||||
|
||||
if uriAttr.Value[1:] == idAttr.Value {
|
||||
signatureElement = e
|
||||
break
|
||||
signatureElement = sig
|
||||
return etreeutils.ErrTraversalHalted
|
||||
}
|
||||
}
|
||||
|
||||
if signatureElement == nil {
|
||||
return nil, errors.New("Missing signature referencing the top-level element")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Get the x509 element from the signature
|
||||
x509Element := signatureElement.FindElement("//" + childPath(signatureElement.Space, X509CertificateTag))
|
||||
if x509Element == nil {
|
||||
return nil, errors.New("Missing x509 Element")
|
||||
}
|
||||
|
||||
x509Text := "-----BEGIN CERTIFICATE-----\n" + x509Element.Text() + "\n-----END CERTIFICATE-----"
|
||||
block, _ := pem.Decode([]byte(x509Text))
|
||||
if block == nil {
|
||||
return nil, errors.New("Failed to parse certificate PEM")
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if signatureElement == nil {
|
||||
return nil, ErrMissingSignature
|
||||
}
|
||||
|
||||
return signatureElement, nil
|
||||
}
|
||||
|
||||
func (ctx *ValidationContext) verifyCertificate(signatureElement *etree.Element) (*x509.Certificate, error) {
|
||||
now := ctx.Clock.Now()
|
||||
|
||||
roots, err := ctx.CertificateStore.Certificates()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cert *x509.Certificate
|
||||
|
||||
// Get the x509 element from the signature
|
||||
x509Element := signatureElement.FindElement("//" + childPath(signatureElement.Space, X509CertificateTag))
|
||||
if x509Element == nil {
|
||||
// Use root certificate if there is only one and it is not contained in signatureElement
|
||||
if len(roots) == 1 {
|
||||
cert = roots[0]
|
||||
} else {
|
||||
return nil, errors.New("Missing x509 Element")
|
||||
}
|
||||
} else {
|
||||
certData, err := base64.StdEncoding.DecodeString(x509Element.Text())
|
||||
if err != nil {
|
||||
return nil, errors.New("Failed to parse certificate")
|
||||
}
|
||||
|
||||
cert, err = x509.ParseCertificate(certData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the certificate is one we trust
|
||||
if !contains(roots, cert) {
|
||||
return nil, errors.New("Could not verify certificate against trusted certs")
|
||||
@@ -386,12 +390,21 @@ func (ctx *ValidationContext) verifyCertificate(el *etree.Element) (*x509.Certif
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// Validate verifies that the passed element contains a valid enveloped signature
|
||||
// matching a currently-valid certificate in the context's CertificateStore.
|
||||
func (ctx *ValidationContext) Validate(el *etree.Element) (*etree.Element, error) {
|
||||
cert, err := ctx.verifyCertificate(el)
|
||||
// Make a copy of the element to avoid mutating the one we were passed.
|
||||
el = el.Copy()
|
||||
|
||||
sig, err := ctx.findSignature(el)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ctx.validateSignature(el, cert)
|
||||
cert, err := ctx.verifyCertificate(sig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ctx.validateSignature(el, sig, cert)
|
||||
}
|
||||
|
Reference in New Issue
Block a user