diff --git a/connector/saml/saml.go b/connector/saml/saml.go
index 7fad1cc38ad7270de5399431068d4c7b368cd674..8b55252a812837979550fc4a2414804564e96348 100644
--- a/connector/saml/saml.go
+++ b/connector/saml/saml.go
@@ -17,6 +17,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/beevik/etree"
 	dsig "github.com/russellhaering/goxmldsig"
+	"github.com/russellhaering/goxmldsig/etreeutils"
 
 	"github.com/coreos/dex/connector"
 )
@@ -500,8 +501,9 @@ func verify(validator *dsig.ValidationContext, data []byte) (signed []byte, err
 		verified = true
 		doc.SetRoot(transformedResponse)
 	}
-	assertion := response.SelectElement("Assertion")
-	if assertion == nil {
+	// Ensures xmlns are copied down to the assertion element when they are defined in the root
+	assertion, err := etreeutils.NSSelectOne(response, "urn:oasis:names:tc:SAML:2.0:assertion", "Assertion")
+	if err != nil {
 		return nil, fmt.Errorf("response does not contain an Assertion element")
 	}
 	transformedAssertion, err := validator.Validate(assertion)
diff --git a/connector/saml/saml_test.go b/connector/saml/saml_test.go
index a2bc49b2f7bbeeedd671800fee6c6d9d72a3160e..cba0fe12862e8d4e56fc5c4362cda00f047cf4be 100644
--- a/connector/saml/saml_test.go
+++ b/connector/saml/saml_test.go
@@ -86,6 +86,10 @@ func TestVerify(t *testing.T) {
 	runVerify(t, "testdata/okta-ca.pem", "testdata/okta-resp.xml", true)
 }
 
+func TestVerifyUnsignedMessageAndSignedAssertionWithRootXmlNs(t *testing.T) {
+	runVerify(t, "testdata/oam-ca.pem", "testdata/oam-resp.xml", true)
+}
+
 func TestVerifySignedMessageAndUnsignedAssertion(t *testing.T) {
 	runVerify(t, "testdata/idp-cert.pem", "testdata/idp-resp-signed-message.xml", true)
 }
diff --git a/connector/saml/testdata/oam-ca.pem b/connector/saml/testdata/oam-ca.pem
new file mode 100644
index 0000000000000000000000000000000000000000..41645dda75a5d24a40182548055782f50c80f48a
--- /dev/null
+++ b/connector/saml/testdata/oam-ca.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAWegAwIBAgIBCjANBgkqhkiG9w0BAQQFADAkMSIwIAYDVQQDExlkZWFv
+YW0tZGV2MDIuanBsLm5hc2EuZ292MB4XDTE2MDYzMDA0NTQxNloXDTI2MDYyODA0
+NTQxNlowJDEiMCAGA1UEAxMZZGVhb2FtLWRldjAyLmpwbC5uYXNhLmdvdjCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAht1N4lGdwUbl7YRyHwSCrnep6/e2I3+V
+eue0pSA/DGn8OuR/udM8UCja5utqlqJdq200ox4b4Mpz0Jg9kMckALtKe+1DgeES
+EIx9FpeuBdHlitYQNSbEr30HIG2nmeTOy4Vi5unBO54um3tNazcUTMA0/LJ6KQL8
+LeZSlB/IxwUCAwEAAaNAMD4wDAYDVR0TAQH/BAIwADAPBgNVHQ8BAf8EBQMDB9gA
+MB0GA1UdDgQWBBRYo1YjfrNonauLzj6/AsueWFGSszANBgkqhkiG9w0BAQQFAAOB
+gQACq7GHK/Zsg0+qC0WWa2ZjmOXE6Dqk/xuooG49QT7ihABs7k9U27Fw3xKF6MkC
+7pca1FwT82eZK1N3XKKpZe7Flu1fMKt2o/XSiBkDjWwUcChVnwGsUBe8hJFwFqg7
+olNJn1kaVBJUqZIiXF9kS0d+1H55rStOd0CNXAzp9utr2A==
+-----END CERTIFICATE-----
diff --git a/connector/saml/testdata/oam-resp.xml b/connector/saml/testdata/oam-resp.xml
new file mode 100644
index 0000000000000000000000000000000000000000..99d148770ce8221261716254104a6f8271005ca3
--- /dev/null
+++ b/connector/saml/testdata/oam-resp.xml
@@ -0,0 +1 @@
+<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:enc="http://www.w3.org/2001/04/xmlenc#" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="http://127.0.0.1:5556/callback" ID="id-IWlPTptSB-PlR80dwt8ZhVeG70mrz7nPvTVrhduK" InResponseTo="_e66b3a98-831c-4c96-5706-b63fe0549624" IssueInstant="2016-12-12T16:54:35Z" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://deaoam-dev02.jpl.nasa.gov:14101/oam/fed</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion ID="id-rT9rTqxdQC9j34YhVeNayUWC9EbIBgym6gp-MZt-" IssueInstant="2016-12-12T16:54:35Z" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://deaoam-dev02.jpl.nasa.gov:14101/oam/fed</saml:Issuer><dsig:Signature><dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><dsig:Reference URI="#id-rT9rTqxdQC9j34YhVeNayUWC9EbIBgym6gp-MZt-"><dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><dsig:DigestValue>z1HD/59hv6UOd5+jeG+ihaFWLgI=</dsig:DigestValue></dsig:Reference></dsig:SignedInfo><dsig:SignatureValue>I99oG5kiOfIgbXYa21z/TOmzftTkFnXe9ObhBNSKit9kAhT93apYROqqXv4Ax96P144Ld7ERX1hgJsytK8LC2874Pk7QrSNm4zvW3x0D4GR4lM06CvJK/EhIur3TrCUJDPigvyP7TJitheCyBejwt0x0lqNP/OzR3tMbAIMRoho=</dsig:SignatureValue></dsig:Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="https://deaoam-dev02.jpl.nasa.gov:14101/oam/fed" SPNameQualifier="JSAuth">pkieu</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData InResponseTo="_e66b3a98-831c-4c96-5706-b63fe0549624" NotOnOrAfter="2016-12-12T16:59:35Z" Recipient="http://127.0.0.1:5556/callback"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2016-12-12T16:54:35Z" NotOnOrAfter="2016-12-12T16:59:35Z"><saml:AudienceRestriction><saml:Audience>JSAuth</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2016-12-12T16:54:10Z" SessionIndex="id-l3NCbxKoBfUZcuKhlotMuIF3ydgYJgGGG6BGTTU6" SessionNotOnOrAfter="2016-12-12T17:54:35Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion></samlp:Response>
diff --git a/glide.lock b/glide.lock
index 63ae90d2c5da71530081e7644a5be03cd5e13164..93ac43c27ebc423ebe757bd5c258bbf11372ee4f 100644
--- a/glide.lock
+++ b/glide.lock
@@ -1,5 +1,5 @@
-hash: 4a3ac3a2a2b39357dc5de7ba296dbe20a97dd2fe13bc15a68e904e69afae2adb
-updated: 2017-03-21T09:24:08.089284929-07:00
+hash: ba77a77f03b1750479aa4a61de59d7a545dc8bd5c71be10e1c2e9afed37e1925
+updated: 2017-03-24T11:03:21.332291207-07:00
 imports:
 - name: github.com/beevik/etree
   version: 4cd0dd976db869f817248477718071a28e978df0
@@ -46,9 +46,10 @@ imports:
   subpackages:
   - cacheobject
 - name: github.com/russellhaering/goxmldsig
-  version: 51810e925e5fc495822fbddda8202f70a6e4a3f3
+  version: eaac44c63fe007124f8f6255b09febc906784981
   subpackages:
   - etreeutils
+  - types
 - name: github.com/Sirupsen/logrus
   version: d26492970760ca5d33129d2d799e34be5c4782eb
 - name: github.com/spf13/cobra
diff --git a/glide.yaml b/glide.yaml
index bde1eb5ce9054e1d43add648c49227b007051891..2af9964f385a2f684f74735d88461f82bb3fff79 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -73,7 +73,7 @@ import:
 - package: golang.org/x/oauth2
   version: 08c8d727d2392d18286f9f88ad775ad98f09ab33
   subpackages: []
-# The oauth2 package only imports the appengine code when it's given a 
+# The oauth2 package only imports the appengine code when it's given a
 # specific build tags, but glide detects it anyway.
 #
 # https://github.com/golang/oauth2/blob/d5040cdd/client_appengine.go
@@ -133,7 +133,7 @@ import:
 
 # XML signature validation for SAML connector
 - package: github.com/russellhaering/goxmldsig
-  version: 51810e925e5fc495822fbddda8202f70a6e4a3f3
+  version: eaac44c63fe007124f8f6255b09febc906784981
 - package: github.com/beevik/etree
   version: 4cd0dd976db869f817248477718071a28e978df0
 - package: github.com/jonboulle/clockwork
diff --git a/vendor/github.com/russellhaering/goxmldsig/canonicalize.go b/vendor/github.com/russellhaering/goxmldsig/canonicalize.go
index 2a2c92275e1eb7e6cd0e62811cfc742f93f14914..34e1a581ffd037ae95050b8fc27221e9d4d21670 100644
--- a/vendor/github.com/russellhaering/goxmldsig/canonicalize.go
+++ b/vendor/github.com/russellhaering/goxmldsig/canonicalize.go
@@ -2,7 +2,6 @@ package dsig
 
 import (
 	"sort"
-	"strings"
 
 	"github.com/beevik/etree"
 	"github.com/russellhaering/goxmldsig/etreeutils"
@@ -15,28 +14,25 @@ type Canonicalizer interface {
 }
 
 type c14N10ExclusiveCanonicalizer struct {
-	InclusiveNamespaces map[string]struct{}
+	prefixList string
 }
 
 // MakeC14N10ExclusiveCanonicalizerWithPrefixList constructs an exclusive Canonicalizer
 // from a PrefixList in NMTOKENS format (a white space separated list).
 func MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList string) Canonicalizer {
-	prefixes := strings.Fields(prefixList)
-	prefixSet := make(map[string]struct{}, len(prefixes))
-
-	for _, prefix := range prefixes {
-		prefixSet[prefix] = struct{}{}
-	}
-
 	return &c14N10ExclusiveCanonicalizer{
-		InclusiveNamespaces: prefixSet,
+		prefixList: prefixList,
 	}
 }
 
 // Canonicalize transforms the input Element into a serialized XML document in canonical form.
 func (c *c14N10ExclusiveCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) {
-	scope := make(map[string]c14nSpace)
-	return canonicalSerialize(excCanonicalPrep(el, scope, c.InclusiveNamespaces))
+	err := etreeutils.TransformExcC14n(el, c.prefixList)
+	if err != nil {
+		return nil, err
+	}
+
+	return canonicalSerialize(el)
 }
 
 func (c *c14N10ExclusiveCanonicalizer) Algorithm() AlgorithmID {
@@ -75,94 +71,6 @@ type c14nSpace struct {
 
 const nsSpace = "xmlns"
 
-// excCanonicalPrep accepts an *etree.Element and recursively transforms it into one
-// which is ready for serialization to exclusive canonical form. Specifically this
-// entails:
-//
-// 1. Stripping re-declarations of namespaces
-// 2. Stripping unused namespaces
-// 3. Sorting attributes into canonical order.
-//
-// NOTE(russell_h): Currently this function modifies the passed element.
-func excCanonicalPrep(el *etree.Element, _nsAlreadyDeclared map[string]c14nSpace, inclusiveNamespaces map[string]struct{}) *etree.Element {
-	//Copy alreadyDeclared map (only contains namespaces)
-	nsAlreadyDeclared := make(map[string]c14nSpace, len(_nsAlreadyDeclared))
-	for k := range _nsAlreadyDeclared {
-		nsAlreadyDeclared[k] = _nsAlreadyDeclared[k]
-	}
-
-	//Track the namespaces used on the current element
-	nsUsedHere := make(map[string]struct{})
-
-	//Make sure to track the element namespace for the case:
-	//<foo:bar xmlns:foo="..."/>
-	if el.Space != "" {
-		nsUsedHere[el.Space] = struct{}{}
-	}
-
-	toRemove := make([]string, 0, 0)
-
-	for _, a := range el.Attr {
-		switch a.Space {
-		case nsSpace:
-
-			//For simplicity, remove all xmlns attribues; to be added in one pass
-			//later.  Otherwise, we need another map/set to track xmlns attributes
-			//that we left alone.
-			toRemove = append(toRemove, a.Space+":"+a.Key)
-			if _, ok := nsAlreadyDeclared[a.Key]; !ok {
-				//If we're not tracking ancestor state already for this namespace, add
-				//it to the map
-				nsAlreadyDeclared[a.Key] = c14nSpace{a: a, used: false}
-			}
-
-			// This algorithm accepts a set of namespaces which should be treated
-			// in an inclusive fashion. Specifically that means we should keep the
-			// declaration of that namespace closest to the root of the tree. We can
-			// accomplish that be pretending it was used by this element.
-			_, inclusive := inclusiveNamespaces[a.Key]
-			if inclusive {
-				nsUsedHere[a.Key] = struct{}{}
-			}
-
-		default:
-			//We only track namespaces, so ignore attributes without one.
-			if a.Space != "" {
-				nsUsedHere[a.Space] = struct{}{}
-			}
-		}
-	}
-
-	//Remove all attributes so that we can add them with much-simpler logic
-	for _, attrK := range toRemove {
-		el.RemoveAttr(attrK)
-	}
-
-	//For all namespaces used on the current element, declare them if they were
-	//not declared (and used) in an ancestor.
-	for k := range nsUsedHere {
-		spc := nsAlreadyDeclared[k]
-		//If previously unused, mark as used
-		if !spc.used {
-			el.Attr = append(el.Attr, spc.a)
-			spc.used = true
-
-			//Assignment here is only to update the pre-existing `used` tracking value
-			nsAlreadyDeclared[k] = spc
-		}
-	}
-
-	//Canonicalize all children, passing down the ancestor tracking map
-	for _, child := range el.ChildElements() {
-		excCanonicalPrep(child, nsAlreadyDeclared, inclusiveNamespaces)
-	}
-
-	//Sort attributes lexicographically
-	sort.Sort(etreeutils.SortedAttrs(el.Attr))
-
-	return el.Copy()
-}
-
 // canonicalPrep accepts an *etree.Element and transforms it into one which is ready
 // for serialization into inclusive canonical form. Specifically this
 // entails:
@@ -208,7 +116,7 @@ func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}) *etree.Elem
 
 func canonicalSerialize(el *etree.Element) ([]byte, error) {
 	doc := etree.NewDocument()
-	doc.SetRoot(el)
+	doc.SetRoot(el.Copy())
 
 	doc.WriteSettings = etree.WriteSettings{
 		CanonicalAttrVal: true,
diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go
new file mode 100644
index 0000000000000000000000000000000000000000..9e6df954d230fef099d9fbc7deb5eff5244dacc0
--- /dev/null
+++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go
@@ -0,0 +1,98 @@
+package etreeutils
+
+import (
+	"sort"
+	"strings"
+
+	"github.com/beevik/etree"
+)
+
+// TransformExcC14n transforms the passed element into xml-exc-c14n form.
+func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) error {
+	prefixes := strings.Fields(inclusiveNamespacesPrefixList)
+	prefixSet := make(map[string]struct{}, len(prefixes))
+
+	for _, prefix := range prefixes {
+		prefixSet[prefix] = struct{}{}
+	}
+
+	err := transformExcC14n(DefaultNSContext, EmptyNSContext, el, prefixSet)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNamespaces map[string]struct{}) error {
+	scope, err := ctx.SubContext(el)
+	if err != nil {
+		return err
+	}
+
+	visiblyUtilizedPrefixes := map[string]struct{}{
+		el.Space: struct{}{},
+	}
+
+	filteredAttrs := []etree.Attr{}
+
+	// Filter out all namespace declarations
+	for _, attr := range el.Attr {
+		switch {
+		case attr.Space == xmlnsPrefix:
+			if _, ok := inclusiveNamespaces[attr.Key]; ok {
+				visiblyUtilizedPrefixes[attr.Key] = struct{}{}
+			}
+
+		case attr.Space == defaultPrefix && attr.Key == xmlnsPrefix:
+			if _, ok := inclusiveNamespaces[defaultPrefix]; ok {
+				visiblyUtilizedPrefixes[defaultPrefix] = struct{}{}
+			}
+
+		default:
+			if attr.Space != defaultPrefix {
+				visiblyUtilizedPrefixes[attr.Space] = struct{}{}
+			}
+
+			filteredAttrs = append(filteredAttrs, attr)
+		}
+	}
+
+	el.Attr = filteredAttrs
+
+	declared = declared.Copy()
+
+	// Declare all visibly utilized prefixes that are in-scope but haven't
+	// been declared in the canonicalized form yet. These might have been
+	// declared on this element but then filtered out above, or they might
+	// have been declared on an ancestor (before canonicalization) which
+	// didn't visibly utilize and thus had them removed.
+	for prefix := range visiblyUtilizedPrefixes {
+		// Skip redundant declarations - they have to already have the same
+		// value.
+		if declaredNamespace, ok := declared.prefixes[prefix]; ok {
+			if value, ok := scope.prefixes[prefix]; ok && declaredNamespace == value {
+				continue
+			}
+		}
+
+		namespace, err := scope.LookupPrefix(prefix)
+		if err != nil {
+			return err
+		}
+
+		el.Attr = append(el.Attr, declared.declare(prefix, namespace))
+	}
+
+	sort.Sort(SortedAttrs(el.Attr))
+
+	// Transform child elements
+	for _, child := range el.ChildElements() {
+		err := transformExcC14n(scope, declared, child, inclusiveNamespaces)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go
index 3034ff1a5b24013fa17639d98cbbecb520b79944..45f3bea1647c59e0290c57a0ad66377fce898889 100644
--- a/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go
+++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go
@@ -47,13 +47,38 @@ type NSContext struct {
 	prefixes map[string]string
 }
 
-func (ctx NSContext) SubContext(el *etree.Element) (NSContext, error) {
-	// The subcontext should inherit existing declared prefixes
+func (ctx NSContext) Copy() NSContext {
 	prefixes := make(map[string]string, len(ctx.prefixes)+4)
 	for k, v := range ctx.prefixes {
 		prefixes[k] = v
 	}
 
+	return NSContext{prefixes: prefixes}
+}
+
+func (ctx NSContext) declare(prefix, namespace string) etree.Attr {
+	ctx.prefixes[prefix] = namespace
+
+	switch prefix {
+	case defaultPrefix:
+		return etree.Attr{
+			Key:   xmlnsPrefix,
+			Value: namespace,
+		}
+
+	default:
+		return etree.Attr{
+			Space: xmlnsPrefix,
+			Key:   prefix,
+			Value: namespace,
+		}
+	}
+}
+
+func (ctx NSContext) SubContext(el *etree.Element) (NSContext, error) {
+	// The subcontext should inherit existing declared prefixes
+	newCtx := ctx.Copy()
+
 	// Merge new namespace declarations on top of existing ones.
 	for _, attr := range el.Attr {
 		if attr.Space == xmlnsPrefix {
@@ -69,7 +94,7 @@ func (ctx NSContext) SubContext(el *etree.Element) (NSContext, error) {
 				return ctx, ErrReservedNamespace
 			}
 
-			prefixes[attr.Key] = attr.Value
+			newCtx.declare(attr.Key, attr.Value)
 		} else if attr.Space == defaultPrefix && attr.Key == xmlnsPrefix {
 			// This attribute is a default namespace declaration
 
@@ -78,11 +103,21 @@ func (ctx NSContext) SubContext(el *etree.Element) (NSContext, error) {
 				return ctx, ErrInvalidDefaultNamespace
 			}
 
-			prefixes[defaultPrefix] = attr.Value
+			newCtx.declare(defaultPrefix, attr.Value)
 		}
 	}
 
-	return NSContext{prefixes: prefixes}, nil
+	return newCtx, nil
+}
+
+// Prefixes returns a copy of this context's prefix map.
+func (ctx NSContext) Prefixes() map[string]string {
+	prefixes := make(map[string]string, len(ctx.prefixes))
+	for k, v := range ctx.prefixes {
+		prefixes[k] = v
+	}
+
+	return prefixes
 }
 
 // LookupPrefix attempts to find a declared namespace for the specified prefix. If the prefix
@@ -98,7 +133,13 @@ func (ctx NSContext) LookupPrefix(prefix string) (string, error) {
 	}
 }
 
-func nsTraverse(ctx NSContext, el *etree.Element, handle func(NSContext, *etree.Element) error) error {
+// NSIterHandler is a function which is invoked with a element and its surrounding
+// NSContext during traversals.
+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)
 	if err != nil {
 		return err
@@ -111,7 +152,7 @@ func nsTraverse(ctx NSContext, el *etree.Element, handle func(NSContext, *etree.
 
 	// Recursively traverse child elements.
 	for _, child := range el.ChildElements() {
-		err := nsTraverse(ctx, child, handle)
+		err := NSTraverse(ctx, child, handle)
 		if err != nil {
 			return err
 		}
@@ -120,7 +161,9 @@ func nsTraverse(ctx NSContext, el *etree.Element, handle func(NSContext, *etree.
 	return nil
 }
 
-func detachWithNamespaces(ctx NSContext, el *etree.Element) (*etree.Element, error) {
+// NSDetatch makes a copy of the passed element, and declares any namespaces in
+// the passed context onto the new element before returning it.
+func NSDetatch(ctx NSContext, el *etree.Element) (*etree.Element, error) {
 	ctx, err := ctx.SubContext(el)
 	if err != nil {
 		return nil, err
@@ -177,43 +220,52 @@ func detachWithNamespaces(ctx NSContext, el *etree.Element) (*etree.Element, err
 	return el, nil
 }
 
-// NSSelectOne conducts a depth-first search for an element with the specified namespace
+// 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)
+}
+
+// NSSelectOneCtx conducts a depth-first search for an element with the specified namespace
 // and tag. If such an element is found, a new *etree.Element is returned which is a
 // copy of the found element, but with all in-context namespace declarations attached
 // to the element as attributes.
-func NSSelectOne(el *etree.Element, namespace, tag string) (*etree.Element, error) {
+func NSSelectOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) {
 	var found *etree.Element
 
-	err := nsTraverse(DefaultNSContext, el, func(ctx NSContext, el *etree.Element) error {
-		currentNS, err := ctx.LookupPrefix(el.Space)
+	err := NSFindIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error {
+		var err error
+
+		found, err = NSDetatch(ctx, el)
 		if err != nil {
 			return err
 		}
 
-		// Base case, el is the sought after element.
-		if currentNS == namespace && el.Tag == tag {
-			found, err = detachWithNamespaces(ctx, el)
-			return ErrTraversalHalted
-		}
-
-		return nil
+		return ErrTraversalHalted
 	})
 
-	if err != nil && err != ErrTraversalHalted {
+	if err != nil {
 		return nil, err
 	}
 
 	return found, nil
 }
 
-// NSFindIterate conducts a depth-first traversal searching for elements with the
-// specified tag in the specified namespace. For each such element, the passed
-// handler function is invoked. If the handler function returns an error
-// traversal is immediately halted. If the error returned by the handler is
-// ErrTraversalHalted then nil will be returned by NSFindIterate. If any other
-// error is returned by the handler, that error will be returned by NSFindIterate.
-func NSFindIterate(el *etree.Element, namespace, tag string, handle func(*etree.Element) error) error {
-	err := nsTraverse(DefaultNSContext, el, func(ctx NSContext, el *etree.Element) error {
+// 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)
+}
+
+// NSFindIterateCtx conducts a depth-first traversal searching for elements with the
+// specified tag in the specified namespace. It uses the passed NSContext for prefix
+// lookups. For each such element, the passed handler function is invoked. If the
+// handler function returns an error traversal is immediately halted. If the error
+// returned by the handler is  ErrTraversalHalted then nil will be returned by
+// NSFindIterate. If any other error is returned by the handler, that error will be
+// returned by NSFindIterate.
+func NSFindIterateCtx(ctx NSContext, el *etree.Element, namespace, tag string, handle NSIterHandler) error {
+	err := NSTraverse(ctx, el, func(ctx NSContext, el *etree.Element) error {
 		currentNS, err := ctx.LookupPrefix(el.Space)
 		if err != nil {
 			return err
@@ -221,7 +273,7 @@ func NSFindIterate(el *etree.Element, namespace, tag string, handle func(*etree.
 
 		// Base case, el is the sought after element.
 		if currentNS == namespace && el.Tag == tag {
-			return handle(el)
+			return handle(ctx, el)
 		}
 
 		return nil
@@ -234,12 +286,18 @@ func NSFindIterate(el *etree.Element, namespace, tag string, handle func(*etree.
 	return nil
 }
 
-// NSFindOne conducts a depth-first search for the specified element. If such an element
-// is found a reference to it is returned.
+// 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)
+}
+
+// NSFindOneCtx conducts a depth-first search for the specified element. If such an element
+// is found a reference to it is returned.
+func NSFindOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) {
 	var found *etree.Element
 
-	err := NSFindIterate(el, namespace, tag, func(el *etree.Element) error {
+	err := NSFindIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error {
 		found = el
 		return ErrTraversalHalted
 	})
@@ -250,3 +308,21 @@ func NSFindOne(el *etree.Element, namespace, tag string) (*etree.Element, error)
 
 	return found, nil
 }
+
+// NSBuildParentContext recurses upward from an element in order to build an NSContext
+// for its immediate parent. If the element has no parent DefaultNSContext
+// is returned.
+func NSBuildParentContext(el *etree.Element) (NSContext, error) {
+	parent := el.Parent()
+	if parent == nil {
+		return DefaultNSContext, nil
+	}
+
+	ctx, err := NSBuildParentContext(parent)
+
+	if err != nil {
+		return ctx, err
+	}
+
+	return ctx.SubContext(parent)
+}
diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go
index f530b428f9ba532b67c38a3fd9691e024f907b73..5871a3913de94d4a3b2437db980326c3250be97f 100644
--- a/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go
+++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go
@@ -2,6 +2,8 @@ package etreeutils
 
 import "github.com/beevik/etree"
 
+// SortedAttrs provides sorting capabilities, compatible with XML C14N, on top
+// of an []etree.Attr
 type SortedAttrs []etree.Attr
 
 func (a SortedAttrs) Len() int {
@@ -13,17 +15,23 @@ func (a SortedAttrs) Swap(i, j int) {
 }
 
 func (a SortedAttrs) Less(i, j int) bool {
-	// As I understand it: any "xmlns" attribute should come first, followed by any
-	// any "xmlns:prefix" attributes, presumably ordered by prefix. Lastly any other
-	// attributes in lexicographical order.
-	if a[i].Space == defaultPrefix && a[i].Key == xmlnsPrefix {
-		return true
-	}
+	// This is the best reference I've found on sort order:
+	// http://dst.lbl.gov/~ksb/Scratch/XMLC14N.html
 
+	// If attr j is a default namespace declaration, attr i may
+	// not be strictly "less" than it.
 	if a[j].Space == defaultPrefix && a[j].Key == xmlnsPrefix {
 		return false
 	}
 
+	// Otherwise, if attr i is a default namespace declaration, it
+	// must be less than anything else.
+	if a[i].Space == defaultPrefix && a[i].Key == xmlnsPrefix {
+		return true
+	}
+
+	// Next, namespace prefix declarations, sorted by prefix, come before
+	// anythign else.
 	if a[i].Space == xmlnsPrefix {
 		if a[j].Space == xmlnsPrefix {
 			return a[i].Key < a[j].Key
@@ -35,6 +43,21 @@ func (a SortedAttrs) Less(i, j int) bool {
 		return false
 	}
 
+	// Then come unprefixed attributes, sorted by key.
+	if a[i].Space == defaultPrefix {
+		if a[j].Space == defaultPrefix {
+			return a[i].Key < a[j].Key
+		}
+		return true
+	}
+
+	if a[j].Space == defaultPrefix {
+		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.
 	if a[i].Space == a[j].Space {
 		return a[i].Key < a[j].Key
 	}
diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go
new file mode 100644
index 0000000000000000000000000000000000000000..b1fecf85a4cdff540e75e24eba8c817899e42af3
--- /dev/null
+++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go
@@ -0,0 +1,43 @@
+package etreeutils
+
+import (
+	"encoding/xml"
+
+	"github.com/beevik/etree"
+)
+
+// NSUnmarshalElement unmarshals the passed etree Element into the value pointed to by
+// v using encoding/xml in the context of the passed NSContext. If v implements
+// ElementKeeper, SetUnderlyingElement will be called on v with a reference to el.
+func NSUnmarshalElement(ctx NSContext, el *etree.Element, v interface{}) error {
+	detatched, err := NSDetatch(ctx, el)
+	if err != nil {
+		return err
+	}
+
+	doc := etree.NewDocument()
+	doc.AddChild(detatched)
+	data, err := doc.WriteToBytes()
+	if err != nil {
+		return err
+	}
+
+	err = xml.Unmarshal(data, v)
+	if err != nil {
+		return err
+	}
+
+	switch v := v.(type) {
+	case ElementKeeper:
+		v.SetUnderlyingElement(el)
+	}
+
+	return nil
+}
+
+// ElementKeeper should be implemented by types which will be passed to
+// UnmarshalElement, but wish to keep a reference
+type ElementKeeper interface {
+	SetUnderlyingElement(*etree.Element)
+	UnderlyingElement() *etree.Element
+}
diff --git a/vendor/github.com/russellhaering/goxmldsig/sign.go b/vendor/github.com/russellhaering/goxmldsig/sign.go
index b41364e4bb55d631649aa084e18c0bf00bb86a5f..82498098bd66af0d37e99889f44d178748f3cd20 100644
--- a/vendor/github.com/russellhaering/goxmldsig/sign.go
+++ b/vendor/github.com/russellhaering/goxmldsig/sign.go
@@ -11,6 +11,7 @@ import (
 	"fmt"
 
 	"github.com/beevik/etree"
+	"github.com/russellhaering/goxmldsig/etreeutils"
 )
 
 type SigningContext struct {
@@ -133,15 +134,39 @@ func (ctx *SigningContext) constructSignature(el *etree.Element, enveloped bool)
 	}
 
 	sig.CreateAttr(xmlns, Namespace)
+	sig.AddChild(signedInfo)
 
-	sig.Child = append(sig.Child, signedInfo)
+	// When using xml-c14n11 (ie, non-exclusive canonicalization) the canonical form
+	// of the SignedInfo must declare all namespaces that are in scope at it's final
+	// enveloped location in the document. In order to do that, we're going to construct
+	// a series of cascading NSContexts to capture namespace declarations:
 
-	// Must propagate down the attributes to the 'SignedInfo' before digesting
-	for _, attr := range sig.Attr {
-		signedInfo.CreateAttr(attr.Space+":"+attr.Key, attr.Value)
+	// First get the context surrounding the element we are signing.
+	rootNSCtx, err := etreeutils.NSBuildParentContext(el)
+	if err != nil {
+		return nil, err
+	}
+
+	// Then capture any declarations on the element itself.
+	elNSCtx, err := rootNSCtx.SubContext(el)
+	if err != nil {
+		return nil, err
+	}
+
+	// Followed by declarations on the Signature (which we just added above)
+	sigNSCtx, err := elNSCtx.SubContext(sig)
+	if err != nil {
+		return nil, err
+	}
+
+	// Finally detatch the SignedInfo in order to capture all of the namespace
+	// declarations in the scope we've constructed.
+	detatchedSignedInfo, err := etreeutils.NSDetatch(sigNSCtx, signedInfo)
+	if err != nil {
+		return nil, err
 	}
 
-	digest, err := ctx.digest(signedInfo)
+	digest, err := ctx.digest(detatchedSignedInfo)
 	if err != nil {
 		return nil, err
 	}
diff --git a/vendor/github.com/russellhaering/goxmldsig/types/signature.go b/vendor/github.com/russellhaering/goxmldsig/types/signature.go
new file mode 100644
index 0000000000000000000000000000000000000000..2c7b1632a8ebd0140af178f3b9617ccd507ae0e9
--- /dev/null
+++ b/vendor/github.com/russellhaering/goxmldsig/types/signature.go
@@ -0,0 +1,93 @@
+package types
+
+import (
+	"encoding/xml"
+
+	"github.com/beevik/etree"
+)
+
+type InclusiveNamespaces struct {
+	XMLName    xml.Name `xml:"http://www.w3.org/2001/10/xml-exc-c14n# InclusiveNamespaces"`
+	PrefixList string   `xml:"PrefixList,attr"`
+}
+
+type Transform struct {
+	XMLName             xml.Name             `xml:"http://www.w3.org/2000/09/xmldsig# Transform"`
+	Algorithm           string               `xml:"Algorithm,attr"`
+	InclusiveNamespaces *InclusiveNamespaces `xml:"InclusiveNamespaces"`
+}
+
+type Transforms struct {
+	XMLName    xml.Name    `xml:"http://www.w3.org/2000/09/xmldsig# Transforms"`
+	Transforms []Transform `xml:"Transform"`
+}
+
+type DigestMethod struct {
+	XMLName   xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# DigestMethod"`
+	Algorithm string   `xml:"Algorithm,attr"`
+}
+
+type Reference struct {
+	XMLName     xml.Name     `xml:"http://www.w3.org/2000/09/xmldsig# Reference"`
+	URI         string       `xml:"URI,attr"`
+	DigestValue string       `xml:"DigestValue"`
+	DigestAlgo  DigestMethod `xml:"DigestMethod"`
+	Transforms  Transforms   `xml:"Transforms"`
+}
+
+type CanonicalizationMethod struct {
+	XMLName   xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# CanonicalizationMethod"`
+	Algorithm string   `xml:"Algorithm,attr"`
+}
+
+type SignatureMethod struct {
+	XMLName   xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignatureMethod"`
+	Algorithm string   `xml:"Algorithm,attr"`
+}
+
+type SignedInfo struct {
+	XMLName                xml.Name               `xml:"http://www.w3.org/2000/09/xmldsig# SignedInfo"`
+	CanonicalizationMethod CanonicalizationMethod `xml:"CanonicalizationMethod"`
+	SignatureMethod        SignatureMethod        `xml:"SignatureMethod"`
+	References             []Reference            `xml:"Reference"`
+}
+
+type SignatureValue struct {
+	XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignatureValue"`
+	Data    string   `xml:",chardata"`
+}
+
+type KeyInfo struct {
+	XMLName  xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
+	X509Data X509Data `xml:"X509Data"`
+}
+
+type X509Data struct {
+	XMLName         xml.Name        `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
+	X509Certificate X509Certificate `xml:"X509Certificate"`
+}
+
+type X509Certificate struct {
+	XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Certificate"`
+	Data    string   `xml:",chardata"`
+}
+
+type Signature struct {
+	XMLName        xml.Name        `xml:"http://www.w3.org/2000/09/xmldsig# Signature"`
+	SignedInfo     *SignedInfo     `xml:"SignedInfo"`
+	SignatureValue *SignatureValue `xml:"SignatureValue"`
+	KeyInfo        *KeyInfo        `xml:"KeyInfo"`
+	el             *etree.Element
+}
+
+// SetUnderlyingElement will be called with a reference to the Element this Signature
+// was unmarshaled from.
+func (s *Signature) SetUnderlyingElement(el *etree.Element) {
+	s.el = el
+}
+
+// UnderlyingElement returns a reference to the Element this signature was unmarshaled
+// from, where applicable.
+func (s *Signature) UnderlyingElement() *etree.Element {
+	return s.el
+}
diff --git a/vendor/github.com/russellhaering/goxmldsig/validate.go b/vendor/github.com/russellhaering/goxmldsig/validate.go
index 250d9e78beb7bb8383233d615faf6086c510cbfb..7aa2d73e1472d955f4db52533a187c3d595d0b6a 100644
--- a/vendor/github.com/russellhaering/goxmldsig/validate.go
+++ b/vendor/github.com/russellhaering/goxmldsig/validate.go
@@ -11,6 +11,7 @@ import (
 
 	"github.com/beevik/etree"
 	"github.com/russellhaering/goxmldsig/etreeutils"
+	"github.com/russellhaering/goxmldsig/types"
 )
 
 var uriRegexp = regexp.MustCompile("^#[a-zA-Z_][\\w.-]*$")
@@ -82,7 +83,12 @@ func recursivelyRemoveElement(tree, el *etree.Element) bool {
 // instead return a copy. Unfortunately copying the tree makes it difficult to
 // correctly locate the signature. I'm opting, for now, to simply mutate the root
 // parameter.
-func (ctx *ValidationContext) transform(root, sig *etree.Element, transforms []*etree.Element) (*etree.Element, Canonicalizer, error) {
+func (ctx *ValidationContext) transform(
+	el *etree.Element,
+	sig *types.Signature,
+	ref *types.Reference) (*etree.Element, Canonicalizer, error) {
+	transforms := ref.Transforms.Transforms
+
 	if len(transforms) != 2 {
 		return nil, nil, errors.New("Expected Enveloped and C14N transforms")
 	}
@@ -90,25 +96,18 @@ func (ctx *ValidationContext) transform(root, sig *etree.Element, transforms []*
 	var canonicalizer Canonicalizer
 
 	for _, transform := range transforms {
-		algo := transform.SelectAttr(AlgorithmAttr)
-		if algo == nil {
-			return nil, nil, errors.New("Missing Algorithm attribute")
-		}
+		algo := transform.Algorithm
 
-		switch AlgorithmID(algo.Value) {
+		switch AlgorithmID(algo) {
 		case EnvelopedSignatureAltorithmId:
-			if !recursivelyRemoveElement(root, sig) {
+			if !recursivelyRemoveElement(el, sig.UnderlyingElement()) {
 				return nil, nil, errors.New("Error applying canonicalization transform: Signature not found")
 			}
 
 		case CanonicalXML10ExclusiveAlgorithmId:
 			var prefixList string
-			ins := transform.FindElement(childPath("", InclusiveNamespacesTag))
-			if ins != nil {
-				prefixListEl := ins.SelectAttr(PrefixListAttr)
-				if prefixListEl != nil {
-					prefixList = prefixListEl.Value
-				}
+			if transform.InclusiveNamespaces != nil {
+				prefixList = transform.InclusiveNamespaces.PrefixList
 			}
 
 			canonicalizer = MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList)
@@ -117,7 +116,7 @@ func (ctx *ValidationContext) transform(root, sig *etree.Element, transforms []*
 			canonicalizer = MakeC14N11Canonicalizer()
 
 		default:
-			return nil, nil, errors.New("Unknown Transform Algorithm: " + algo.Value)
+			return nil, nil, errors.New("Unknown Transform Algorithm: " + algo)
 		}
 	}
 
@@ -125,7 +124,7 @@ func (ctx *ValidationContext) transform(root, sig *etree.Element, transforms []*
 		return nil, nil, errors.New("Expected canonicalization transform")
 	}
 
-	return root, canonicalizer, nil
+	return el, canonicalizer, nil
 }
 
 func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string, canonicalizer Canonicalizer) ([]byte, error) {
@@ -148,19 +147,16 @@ func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string
 	return hash.Sum(nil), nil
 }
 
-func (ctx *ValidationContext) verifySignedInfo(signatureElement *etree.Element, canonicalizer Canonicalizer, signatureMethodId string, cert *x509.Certificate, sig []byte) error {
+func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicalizer Canonicalizer, signatureMethodId string, cert *x509.Certificate, decodedSignature []byte) error {
+	signatureElement := sig.UnderlyingElement()
+
 	signedInfo := signatureElement.FindElement(childPath(signatureElement.Space, SignedInfoTag))
 	if signedInfo == nil {
 		return errors.New("Missing SignedInfo")
 	}
 
-	// Any attributes from the 'Signature' element must be pushed down into the 'SignedInfo' element before it is canonicalized
-	for _, attr := range signatureElement.Attr {
-		signedInfo.CreateAttr(attr.Space+":"+attr.Key, attr.Value)
-	}
-
 	// Canonicalize the xml
-	canonical, err := canonicalizer.Canonicalize(signedInfo)
+	canonical, err := canonicalSerialize(signedInfo)
 	if err != nil {
 		return err
 	}
@@ -184,7 +180,7 @@ func (ctx *ValidationContext) verifySignedInfo(signatureElement *etree.Element,
 	}
 
 	// 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[:], sig)
+	err = rsa.VerifyPKCS1v15(pubKey, signatureAlgorithm, hashed[:], decodedSignature)
 	if err != nil {
 		return err
 	}
@@ -192,65 +188,37 @@ func (ctx *ValidationContext) verifySignedInfo(signatureElement *etree.Element,
 	return nil
 }
 
-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 {
-		return nil, errors.New("Missing SignedInfo")
-	}
-
-	reference := signedInfo.FindElement(childPath(sig.Space, ReferenceTag))
-	if reference == nil {
-		return nil, errors.New("Missing Reference")
-	}
-
-	transforms := reference.FindElement(childPath(sig.Space, TransformsTag))
-	if transforms == nil {
-		return nil, errors.New("Missing Transforms")
+func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Signature, cert *x509.Certificate) (*etree.Element, error) {
+	idAttr := el.SelectAttr(DefaultIdAttr)
+	if idAttr == nil || idAttr.Value == "" {
+		return nil, errors.New("Missing ID attribute")
 	}
 
-	uri := reference.SelectAttr("URI")
-	if uri == nil {
-		// TODO(russell_h): It is permissible to leave this out. We should be
-		// able to fall back to finding the referenced element some other way.
-		return nil, errors.New("Reference is missing URI attribute")
-	}
+	var ref *types.Reference
 
-	// Get the element referenced in the 'SignedInfo'
-	referencedElement := el.FindElement(fmt.Sprintf("//[@%s='%s']", ctx.IdAttribute, uri.Value[1:]))
-	if referencedElement == nil {
-		return nil, errors.New("Unable to find referenced element: " + uri.Value)
+	// Find the first reference which references the top-level element
+	for _, _ref := range sig.SignedInfo.References {
+		if _ref.URI == "" || _ref.URI[1:] == idAttr.Value {
+			ref = &_ref
+		}
 	}
 
 	// Perform all transformations listed in the 'SignedInfo'
 	// Basically, this means removing the 'SignedInfo'
-	transformed, canonicalizer, err := ctx.transform(referencedElement, sig, transforms.ChildElements())
+	transformed, canonicalizer, err := ctx.transform(el, sig, ref)
 	if err != nil {
 		return nil, err
 	}
 
-	digestMethod := reference.FindElement(childPath(sig.Space, DigestMethodTag))
-	if digestMethod == nil {
-		return nil, errors.New("Missing DigestMethod")
-	}
-
-	digestValue := reference.FindElement(childPath(sig.Space, DigestValueTag))
-	if digestValue == nil {
-		return nil, errors.New("Missing DigestValue")
-	}
-
-	digestAlgorithmAttr := digestMethod.SelectAttr(AlgorithmAttr)
-	if digestAlgorithmAttr == nil {
-		return nil, errors.New("Missing DigestMethod Algorithm attribute")
-	}
+	digestAlgorithm := ref.DigestAlgo.Algorithm
 
 	// Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo'
-	digest, err := ctx.digest(transformed, digestAlgorithmAttr.Value, canonicalizer)
+	digest, err := ctx.digest(transformed, digestAlgorithm, canonicalizer)
 	if err != nil {
 		return nil, err
 	}
 
-	decodedDigestValue, err := base64.StdEncoding.DecodeString(digestValue.Text())
+	decodedDigestValue, err := base64.StdEncoding.DecodeString(ref.DigestValue)
 	if err != nil {
 		return nil, err
 	}
@@ -259,30 +227,15 @@ func (ctx *ValidationContext) validateSignature(el, sig *etree.Element, cert *x5
 		return nil, errors.New("Signature could not be verified")
 	}
 
-	//Verify the signed info
-	signatureMethod := signedInfo.FindElement(childPath(sig.Space, SignatureMethodTag))
-	if signatureMethod == nil {
-		return nil, errors.New("Missing SignatureMethod")
-	}
-
-	signatureMethodAlgorithmAttr := signatureMethod.SelectAttr(AlgorithmAttr)
-	if digestAlgorithmAttr == nil {
-		return nil, errors.New("Missing SignatureMethod Algorithm attribute")
-	}
-
 	// Decode the 'SignatureValue' so we can compare against it
-	signatureValue := sig.FindElement(childPath(sig.Space, SignatureValueTag))
-	if signatureValue == nil {
-		return nil, errors.New("Missing SignatureValue")
-	}
-
-	decodedSignature, err := base64.StdEncoding.DecodeString(signatureValue.Text())
-
+	decodedSignature, err := base64.StdEncoding.DecodeString(sig.SignatureValue.Data)
 	if err != nil {
 		return nil, errors.New("Could not decode signature")
 	}
+
 	// Actually verify the 'SignedInfo' was signed by a trusted source
-	err = ctx.verifySignedInfo(sig, canonicalizer, signatureMethodAlgorithmAttr.Value, cert, decodedSignature)
+	signatureMethod := sig.SignedInfo.SignatureMethod.Algorithm
+	err = ctx.verifySignedInfo(sig, canonicalizer, signatureMethod, cert, decodedSignature)
 	if err != nil {
 		return nil, err
 	}
@@ -300,37 +253,88 @@ func contains(roots []*x509.Certificate, cert *x509.Certificate) bool {
 }
 
 // findSignature searches for a Signature element referencing the passed root element.
-func (ctx *ValidationContext) findSignature(el *etree.Element) (*etree.Element, error) {
+func (ctx *ValidationContext) findSignature(el *etree.Element) (*types.Signature, error) {
 	idAttr := el.SelectAttr(DefaultIdAttr)
 	if idAttr == nil || idAttr.Value == "" {
 		return nil, errors.New("Missing ID attribute")
 	}
 
-	var signatureElement *etree.Element
+	var sig *types.Signature
 
-	err := etreeutils.NSFindIterate(el, Namespace, SignatureTag, func(sig *etree.Element) error {
-		signedInfo := sig.FindElement(childPath(sig.Space, SignedInfoTag))
-		if signedInfo == nil {
-			return errors.New("Missing SignedInfo")
-		}
+	// Traverse the tree looking for a Signature element
+	err := etreeutils.NSFindIterate(el, Namespace, SignatureTag, func(ctx etreeutils.NSContext, el *etree.Element) error {
 
-		referenceElement := signedInfo.FindElement(childPath(sig.Space, ReferenceTag))
-		if referenceElement == nil {
-			return errors.New("Missing Reference Element")
+		found := false
+		err := etreeutils.NSFindIterateCtx(ctx, el, Namespace, SignedInfoTag,
+			func(ctx etreeutils.NSContext, signedInfo *etree.Element) error {
+				// Ignore any SignedInfo that isn't an immediate descendent of Signature.
+				if signedInfo.Parent() != el {
+					return nil
+				}
+
+				detachedSignedInfo, err := etreeutils.NSDetatch(ctx, signedInfo)
+				if err != nil {
+					return err
+				}
+
+				c14NMethod := detachedSignedInfo.FindElement(childPath(detachedSignedInfo.Space, CanonicalizationMethodTag))
+				if c14NMethod == nil {
+					return errors.New("missing CanonicalizationMethod on Signature")
+				}
+
+				c14NAlgorithm := c14NMethod.SelectAttrValue(AlgorithmAttr, "")
+
+				var canonicalSignedInfo *etree.Element
+
+				switch AlgorithmID(c14NAlgorithm) {
+				case CanonicalXML10ExclusiveAlgorithmId:
+					err := etreeutils.TransformExcC14n(detachedSignedInfo, "")
+					if err != nil {
+						return err
+					}
+
+					// NOTE: TransformExcC14n transforms the element in-place,
+					// while canonicalPrep isn't meant to. Once we standardize
+					// this behavior we can drop this, as well as the adding and
+					// removing of elements below.
+					canonicalSignedInfo = detachedSignedInfo
+
+				case CanonicalXML11AlgorithmId:
+					canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{})
+
+				default:
+					return fmt.Errorf("invalid CanonicalizationMethod on Signature: %s", c14NAlgorithm)
+				}
+
+				el.RemoveChild(signedInfo)
+				el.AddChild(canonicalSignedInfo)
+
+				found = true
+
+				return etreeutils.ErrTraversalHalted
+			})
+		if err != nil {
+			return err
 		}
 
-		uriAttr := referenceElement.SelectAttr(URIAttr)
-		if uriAttr == nil || uriAttr.Value == "" {
-			return errors.New("Missing URI attribute")
+		if !found {
+			return errors.New("Missing SignedInfo")
 		}
 
-		if !uriRegexp.MatchString(uriAttr.Value) {
-			return errors.New("Invalid URI: " + uriAttr.Value)
+		// Unmarshal the signature into a structured Signature type
+		_sig := &types.Signature{}
+		err = etreeutils.NSUnmarshalElement(ctx, el, _sig)
+		if err != nil {
+			return err
 		}
 
-		if uriAttr.Value[1:] == idAttr.Value {
-			signatureElement = sig
-			return etreeutils.ErrTraversalHalted
+		// Traverse references in the signature to determine whether it has at least
+		// one reference to the top level element. If so, conclude the search.
+		for _, ref := range _sig.SignedInfo.References {
+			if ref.URI == "" || ref.URI[1:] == idAttr.Value {
+				sig = _sig
+				return etreeutils.ErrTraversalHalted
+			}
 		}
 
 		return nil
@@ -340,14 +344,14 @@ func (ctx *ValidationContext) findSignature(el *etree.Element) (*etree.Element,
 		return nil, err
 	}
 
-	if signatureElement == nil {
+	if sig == nil {
 		return nil, ErrMissingSignature
 	}
 
-	return signatureElement, nil
+	return sig, nil
 }
 
-func (ctx *ValidationContext) verifyCertificate(signatureElement *etree.Element) (*x509.Certificate, error) {
+func (ctx *ValidationContext) verifyCertificate(sig *types.Signature) (*x509.Certificate, error) {
 	now := ctx.Clock.Now()
 
 	roots, err := ctx.CertificateStore.Certificates()
@@ -357,17 +361,13 @@ func (ctx *ValidationContext) verifyCertificate(signatureElement *etree.Element)
 
 	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")
+	if sig.KeyInfo != nil {
+		// If the Signature includes KeyInfo, extract the certificate from there
+		if sig.KeyInfo.X509Data.X509Certificate.Data == "" {
+			return nil, errors.New("missing X509Certificate within KeyInfo")
 		}
-	} else {
-		certData, err := base64.StdEncoding.DecodeString(x509Element.Text())
+
+		certData, err := base64.StdEncoding.DecodeString(sig.KeyInfo.X509Data.X509Certificate.Data)
 		if err != nil {
 			return nil, errors.New("Failed to parse certificate")
 		}
@@ -376,6 +376,13 @@ func (ctx *ValidationContext) verifyCertificate(signatureElement *etree.Element)
 		if err != nil {
 			return nil, err
 		}
+	} else {
+		// If the Signature doesn't have KeyInfo, Use the root certificate if there is only one
+		if len(roots) == 1 {
+			cert = roots[0]
+		} else {
+			return nil, errors.New("Missing x509 Element")
+		}
 	}
 
 	// Verify that the certificate is one we trust