vendor: revendor

This commit is contained in:
Eric Chiang
2017-03-21 09:27:22 -07:00
parent 5888220965
commit 910d59865b
6 changed files with 372 additions and 96 deletions

View File

@@ -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)
}