russellhaering / goxmldsig Goto Github PK
View Code? Open in Web Editor NEWPure Go implementation of XML Digital Signatures
License: Apache License 2.0
Pure Go implementation of XML Digital Signatures
License: Apache License 2.0
The current clockwork dependency is used in exactly one place.
type ValidationContext struct {
CertificateStore X509CertificateStore
IdAttribute string
Clock *Clock
}
This can easily be replaced with a method for getting the current time.
type ValidationContext struct {
CertificateStore X509CertificateStore
IdAttribute string
// Now is used to determine the current time. If not provided, time.Now is used.
Now func() time.Time
}
Basically what tls.Config does https://golang.org/pkg/crypto/tls/#Config
It's a breaking change so I wanted to see how y'all feel about it before sending a PR.
Hey, I noticed something interesting.
xmlsec1 requires this format: <soap:Body Id="xmltosign">
But your package requires this format: <soap:Body ID="xmltosign">
This makes the two incompatible. I was hoping to use your package to talk with an old banking system that uses xmlsec1 with the first format, but I can not do that since you require the second.
Is there a chance you can refactor your parsing to that both ID and Id can be used ?
See russellhaering/gosaml2#59 for background.
Program which exhibits the issue:
package main
import (
"crypto/x509"
"encoding/base64"
"encoding/xml"
"fmt"
"time"
saml2 "github.com/russellhaering/gosaml2"
"github.com/russellhaering/gosaml2/types"
dsig "github.com/russellhaering/goxmldsig"
)
const (
timeString = "2019-08-12T12:00:52.718Z"
oktaMetadata = `<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor entityID="http://www.okta.com/exk133onomIuOW98z357" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"><md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAWxzAwX1MA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi05MDUyNTExHDAaBgkqhkiG9w0BCQEW
DWluZm9Ab2t0YS5jb20wHhcNMTkwODA4MjA1MzMzWhcNMjkwODA4MjA1NDMzWjCBkjELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNV
BAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtOTA1MjUxMRwwGgYJ
KoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
m+ZZF6aEG6ehLLIV6RPA+i1z6ss3HBG2bZD3efwKCDDXYUkp59AE7JsjVHMtpJPHhzHuScuHDMlu
HmkBQTW7j9XpnaRn8SfZXkwlCUHTo+HAC9lwbQxO4d4wnwgnm6FAjm1I/gbfFAobd8BR9pDxHuXE
MQ0DtQu/W3WbDUrz/bhSxPJAoVy2koQn9G0y3unm7eRwYWHeuW6GdPWV2szTtDS0c3qtUXVF5Ugg
iQYlwQu6xkfy4l8iGJL7ETa2BmJzwCFecMIct87SqNhYQwCBH54MBaHcaSsCKyimNvMY9B7RmC+H
4+awePPA1q3R/UQ3Pfom8mx6yDdKIWqlkG3MsQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAiURCZ
P4oJWcf1o5nm4yG15UH01g/S6Y4OUWMi6BFJy9fCrJ0h/2BZKi68SQ0uMAbdK6anxCzq3Rr5MSzW
OWPQ1Zljn3LGPsiTFdFca/GVRen5IYQ7Dr2Mvhtm+QVscEY9TDjtETbTAHEVEjwXmB21wtdIhizv
sQS7wz0A8LV+Atpbev45RiV6COmB6T6vJuFQ7ZsDZMSHZriTYiETTJvHBGd7PtbCxYNc6LRB2JDb
wlekRhVEjR0UhnM+nn2sqqbv7tDEPs63lZSDXCnR1PhscHrEuQ04rHI3OL0gCULVQFvJrj85IAZF
1QQuGUK8ozfOyFpQWAJUW71INnF/SLWv</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-905251.okta.com/app/medev905251_test_1/exk133onomIuOW98z357/sso/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-905251.okta.com/app/medev905251_test_1/exk133onomIuOW98z357/sso/saml"/></md:IDPSSODescriptor></md:EntityDescriptor>`
badInput = `<p ID="5"o=""t=""n=""xmlns:saml2p=""s=""><saml2 t=""l=""></l><s s=""><s><s I=""><s><s m=""></m></s><s></e></e></o><s></e><s><s><s></X></X></o></e><saml2p l=""></l><saml2:Assertion ID="id1684056077776386493060641"IssueInstant="2019-08-12T12:00:52.718Z"Version="2.0"xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"xmlns="">http://www.okta.com/exk133onomIuOW98z357</l><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:Reference URI="#id1684056077776386493060641"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces PrefixList="xs"xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/></m></s><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>dC1cm0pLLjIWZC6G2Pmf0JogmqHztp9W1euXPd/TUHo=</e></e></o><ds></e><ds><ds><ds></X></X></o></e><saml2:Subject xmlns:=""><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</l><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData InResponseTo="_40a419f5-5c1c-43d0-5834-5caf268a5f01"NotOnOrAfter="2019-08-12T12:05:52.718Z"Recipient="https://127.0.0.1/login"/></l></l><saml2:Conditions NotBefore="2019-08-12T11:55:52.718Z"NotOnOrAfter="2019-08-12T12:05:52.718Z"xmlns:=""><saml2:AudienceRestriction><saml2:Audience>37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f.jazznetworks.com</l></l></l><saml2:AuthnStatement AuthnInstant="2019-08-12T12:00:52.718Z"SessionIndex="_40a419f5-5c1c-43d0-5834-5caf268a5f01"xmlns:=""><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</l></l></l><saml2:AttributeStatement xmlns:=""><saml2:Attribute Name="FirstName"NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:=""xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:type="xs:string">Steven</l></l><saml2:Attribute Name="LastName"NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:=""xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:type="xs:string">Johnstone</l></l><saml2:Attribute Name="Email"NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:=""xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:type="xs:string">[email protected]</l></l>`
)
func newServiceProvider() *saml2.SAMLServiceProvider {
metadata := &types.EntityDescriptor{} // may need to support EntityDescriptors (plural)
if err := xml.Unmarshal([]byte(oktaMetadata), metadata); err != nil {
panic(err)
}
certStore := dsig.MemoryX509CertificateStore{
Roots: []*x509.Certificate{},
}
for _, kd := range metadata.IDPSSODescriptor.KeyDescriptors {
for _, xcert := range kd.KeyInfo.X509Data.X509Certificates {
if xcert.Data == "" {
panic("nope")
}
certData, err := base64.StdEncoding.DecodeString(xcert.Data)
if err != nil {
panic(err)
}
idpCert, err := x509.ParseCertificate(certData)
if err != nil {
panic(err)
}
certStore.Roots = append(certStore.Roots, idpCert)
}
}
SSOs := metadata.IDPSSODescriptor.SingleSignOnServices
tenantURI := "test.example.com"
fakeTime, err := time.Parse(time.RFC3339, timeString)
if err != nil {
panic(err)
}
clock := dsig.NewFakeClockAt(fakeTime)
return &saml2.SAMLServiceProvider{
Clock: clock,
IdentityProviderSSOURL: SSOs[0].Location,
IdentityProviderIssuer: metadata.EntityID,
ServiceProviderIssuer: tenantURI,
AssertionConsumerServiceURL: "https://127.0.0.1/login",
SignAuthnRequests: true,
AudienceURI: tenantURI,
IDPCertificateStore: &certStore,
ValidateEncryptionCert: true,
}
}
func main() {
base64Input := base64.StdEncoding.EncodeToString([]byte(badInput))
if _, err := newServiceProvider().RetrieveAssertionInfo(base64Input); err != nil {
fmt.Printf("error %v\n", err)
}
}
Panic:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x66bca4]
goroutine 1 [running]:
github.com/russellhaering/goxmldsig.(*ValidationContext).validateSignature(0xc000154f88, 0xc00019c240, 0xc00019e4c0, 0xc000126580, 0x0, 0x1, 0x6010105)
/goroot/go/src/github.com/russellhaering/goxmldsig/validate.go:275 +0x2b4
github.com/russellhaering/goxmldsig.(*ValidationContext).Validate(0xc000154f88, 0xc00017d560, 0xc00017d560, 0x0, 0x0)
/goroot/go/src/github.com/russellhaering/goxmldsig/validate.go:466 +0xf3
github.com/russellhaering/gosaml2.(*SAMLServiceProvider).validateAssertionSignatures.func1(0xc000191080, 0xc0000ada40, 0x9, 0x1)
/goroot/go/src/github.com/russellhaering/gosaml2/decode_response.go:178 +0x2fc
github.com/russellhaering/goxmldsig/etreeutils.NSFindIterateCtx.func1(0xc000191080, 0xc0000ada40, 0xc000191080, 0x0)
/goroot/go/src/github.com/russellhaering/goxmldsig/etreeutils/namespace.go:281 +0x137
github.com/russellhaering/goxmldsig/etreeutils.NSTraverse(0xc000190ba0, 0xc0000ada40, 0xc000190b70, 0x0, 0x0)
/goroot/go/src/github.com/russellhaering/goxmldsig/etreeutils/namespace.go:148 +0x6e
github.com/russellhaering/goxmldsig/etreeutils.NSTraverse(0xc0000ccc60, 0xc0000ad4a0, 0xc000190b70, 0x30, 0x6ebda0)
/goroot/go/src/github.com/russellhaering/goxmldsig/etreeutils/namespace.go:155 +0xe5
github.com/russellhaering/goxmldsig/etreeutils.NSFindIterateCtx(0xc0000ccc60, 0xc0000ad4a0, 0x71c4d1, 0x25, 0x712a6e, 0x9, 0xc000190b40, 0x7152c8, 0x12)
/goroot/go/src/github.com/russellhaering/goxmldsig/etreeutils/namespace.go:268 +0xa4
github.com/russellhaering/goxmldsig/etreeutils.NSFindIterate(...)
/goroot/go/src/github.com/russellhaering/goxmldsig/etreeutils/namespace.go:257
github.com/russellhaering/gosaml2.(*SAMLServiceProvider).validateAssertionSignatures(0xc000164000, 0xc0000ad4a0, 0x0, 0x0)
/goroot/go/src/github.com/russellhaering/gosaml2/decode_response.go:200 +0xed
github.com/russellhaering/gosaml2.(*SAMLServiceProvider).ValidateEncodedResponse(0xc000164000, 0xc000143000, 0xe24, 0xc000013510, 0xc00015e000, 0xc0000d8b40)
/goroot/go/src/github.com/russellhaering/gosaml2/decode_response.go:248 +0x30e
github.com/russellhaering/gosaml2.(*SAMLServiceProvider).RetrieveAssertionInfo(0xc000164000, 0xc000143000, 0xe24, 0xa9b, 0xc000143000, 0xe24)
/goroot/go/src/github.com/russellhaering/gosaml2/retrieve_assertion.go:40 +0x9b
main.main()
/goroot/go/src/github.com/russellhaering/gosaml2/crasher/main.go:93 +0xb6
exit status 2
Potential fix:
diff --git a/validate.go b/validate.go
index 55feb39..fe63af4 100644
--- a/validate.go
+++ b/validate.go
@@ -271,6 +271,10 @@ func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Si
return nil, errors.New("Signature could not be verified")
}
+ if sig.SignatureValue == nil {
+ return nil, errors.New("nil signature value")
+ }
+
// Decode the 'SignatureValue' so we can compare against it
decodedSignature, err := base64.StdEncoding.DecodeString(sig.SignatureValue.Data)
if err != nil {
Running tests in dex with the latest commit (ff1b2e1)
Ref: dexidp/dex#870
=== RUN TestVerifySignedMessageAndUnsignedAssertion
--- FAIL: TestVerifySignedMessageAndUnsignedAssertion (0.00s)
saml_test.go:56: crypto/rsa: verification error
=== RUN TestVerifyUnsignedMessageAndSignedAssertion
--- FAIL: TestVerifyUnsignedMessageAndSignedAssertion (0.00s)
saml_test.go:56: crypto/rsa: verification error
=== RUN TestVerifySignedMessageAndSignedAssertion
--- FAIL: TestVerifySignedMessageAndSignedAssertion (0.00s)
saml_test.go:56: crypto/rsa: verification error
Please add go.mod
for Go modules.
It seems NSSelectOne
returns a nil pointer w/o an error for found
if the element is not present.
I found this while chasing a production panic that's using this repo as a dependency:
I'm not sure if it would make sense to just do a found == nil
check in NSSelectOne
and return an error.
from what I'm seeing it's generating the canonicalization with indentation which I believe makes the signature fail with SOAP
Taking Example 3.3 from the REC-xml-c14n-20010315 specification does not properly canonicalize the document.
--- FAIL: TestC14N10RecCanonicalizer (0.00s)
canonicalize_test.go:31:
Error Trace: canonicalize_test.go:31
canonicalize_test.go:118
Error: Not equal:
expected: "<doc>\n <e1></e1>\n <e2></e2>\n <e3 id=\"elem3\" name=\"elem3\"></e3>\n <e4 id=\"elem4\" name=\"elem4\"></e4>\n <e5 xmlns=\"http://example.org\" xmlns:a=\"http://www.w3.org\" xmlns:b=\"http://www.ietf.org\" attr=\"I'm\" attr2=\"all\" b:attr=\"sorted\" a:attr=\"out\"></e5>\n <e6 xmlns:a=\"http://www.w3.org\">\n <e7 xmlns=\"http://www.ietf.org\">\n <e8 xmlns=\"\">\n <e9 xmlns:a=\"http://www.ietf.org\" attr=\"default\"></e9>\n </e8>\n </e7>\n </e6>\n</doc>"
actual : "<doc>\n <e1></e1>\n <e2></e2>\n <e3 id=\"elem3\" name=\"elem3\"></e3>\n <e4 id=\"elem4\" name=\"elem4\"></e4>\n <e5 xmlns=\"http://example.org\" xmlns:a=\"http://www.w3.org\" xmlns:b=\"http://www.ietf.org\" attr=\"I'm\" attr2=\"all\" b:attr=\"sorted\" a:attr=\"out\"></e5>\n <e6 xmlns=\"\" xmlns:a=\"http://www.w3.org\">\n <e7 xmlns=\"http://www.ietf.org\">\n <e8 xmlns=\"\">\n <e9 xmlns=\"\"></e9>\n </e8>\n </e7>\n </e6>\n</doc>"
Diff:
--- Expected
+++ Actual
@@ -6,6 +6,6 @@
<e5 xmlns="http://example.org" xmlns:a="http://www.w3.org" xmlns:b="http://www.ietf.org" attr="I'm" attr2="all" b:attr="sorted" a:attr="out"></e5>
- <e6 xmlns:a="http://www.w3.org">
+ <e6 xmlns="" xmlns:a="http://www.w3.org">
<e7 xmlns="http://www.ietf.org">
<e8 xmlns="">
- <e9 xmlns:a="http://www.ietf.org" attr="default"></e9>
+ <e9 xmlns=""></e9>
</e8>
Test: TestC14N10RecCanonicalizer
FAIL
FAIL github.com/russellhaering/goxmldsig 1.175s
It appears we are injecting empty xmlns
attributes into the response.
Hi,
Please provide a copyright so your rights are properly represented and companies can use your code the proper legal way.
E.g.
Copyright
Thank you!
Have a nice day!
Use go-fuzz to compare compare our canonicalization's to those generated by another implementation.
Hi,
First of all, thanks for the hard work and for sharing this lib with the community.
I am trying to use your library in my app using go mod with the latest fixes but as you forgot to create a new tag I am getting a old version that contains a bug already fixed at sign.go - constructSignedInfo.
So, could you please just create a new tag with this small revision?
Thanks in advance.
PS.: I know we could run go get github.com/russellhaering/goxmldsig@master
but this small adjust will avoid this inconvenience
Hey, could you make the privateKey and cert fields Exported ?
Line 31 in 7acd5e4
That way I don't have to make my own KeyStore implementation.
So as I've been working on russellhaering/gosaml2#3, I've hit a minor snag with signed AuthN request. It seems that Shibboleth wants signatures that use the original xml-c14n algorithm.
I'd like to try to tackle the issue, but I'm curious as to whether you have any advice/experience on the differences and how I would go about prepping the etree.Document differently. No worries if not, but it might save me some reading of the spec. :-)
The Usages says
Include the types.Signature struct from this package in your application messages
proceeds to create the AppHdr struct
which is never used or referenced again, LOL.
I need to sign Response and Assertion objects from for post binding, I got an starting base by copying them from gosaml2 and adding the Signature property.
How do I get from embedding the Signature struct to actually signing the objects?
When validating a signature, the function verifyCertificate verifies that the certificate hasn't expired. Since we've already verified that the certificate is one we trust, it would be nice if we could as an option skip the check of the certificate's notBefore/notAfter.
I can get around it by setting a fake clock to the cert's notBefore in the validation context (and calling Validate multiple times if there are multiple certificates). But it would be nice if you could set a flag in ValidationContext instead.
For context, see also crewjam/saml#234
Would you consider such a feature? I can provide a PR if you wish.
After bumping to the latest master
revs in gosaml2
and goxmldsig
, I see several regressions when testing my app against http://saml.oktadev.com/.
Here's a subset:
<?xml version="1.0" ?>
<samlp:Response Destination="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0" ID="_0bb6e7bd0c86a18e04e8" IssueInstant="2017-03-24T21:58:36Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">idp.oktadev.com</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>PoDJiuV7l8rwQiSUJz13y6OdaJkbd9ZlV/bIRdQM4cc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>CogrL+tKzDDd2G8l0D+spvGoBM1Z3EejIumWwds+ttAydrQWuFPnRa0i/7vGNU4bQk3g2JUbo+/60rt88uaH8kzxE+Lz62YYSxQn//bGPhXkHGLMbsIbAAJk19KmSRhDBRY/mM+LySu4+HKVS4wIDpoTdGOkGNJgrGI0DzMqyo9EI3orh8Pe/nf4AkWCY+qLbSKHQF28+00dvdCn3xekbQQ7aY8Df24x4sxTf3YBcMXo6sCglS8G4xBnexzI6NDYy/EUGf2CsyG3qtYMDc2y515XiG0VDHAn9LI0/QlvZkwJIrI9Jur7nM0wUWVBnAiHT7KW8xbl3atxWW3wBWRgNA==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDPDCCAiQCCQDydJgOlszqbzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHSmFua3lDbzESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTE0MDMxMjE5NDYzM1oXDTI3MTExOTE5NDYzM1owYDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAOBgNVBAoTB0phbmt5Q28xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGvJpRTTasRUSPqcbqCG+ZnTAurnu0vVpIG9lzExnh11o/BGmzu7lB+yLHcEdwrKBBmpepDBPCYxpVajvuEhZdKFx/Fdy6j5mH3rrW0Bh/zd36CoUNjbbhHyTjeM7FN2yF3u9lcyubuvOzr3B3gX66IwJlU46+wzcQVhSOlMk2tXR+fIKQExFrOuK9tbX3JIBUqItpI+HnAow509CnM134svw8PTFLkR6/CcMqnDfDK1m993PyoC1Y+N4X9XkhSmEQoAlAHPI5LHrvuujM13nvtoVYvKYoj7ScgumkpWNEvX652LfXOnKYlkB8ZybuxmFfIkzedQrbJsyOhfL03cMECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAeHwzqwnzGEkxjzSD47imXaTqtYyETZow7XwBc0ZaFS50qRFJUgKTAmKS1xQBP/qHpStsROT35DUxJAE6NY1Kbq3ZbCuhGoSlY0L7VzVT5tpu4EY8+Dq/u2EjRmmhoL7UkskvIZ2n1DdERtd+YUMTeqYl9co43csZwDno/IKomeN5qaPc39IZjikJ+nUC6kPFKeu/3j9rgHNlRtocI6S1FdtFz9OZMQlpr0JbUt2T3xS/YoQJn6coDmJL5GTiiKM6cOe+Ur1VwzS1JEDbSS2TWWhzq8ojLdrotYLGd9JOsoQhElmz+tMfCFQUFLExinPAyy7YHlSiVX13QH2XTu/iQQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ID="_zMpSsMVcfYO2oWQvTJw4KjlQKssPBsPu" IssueInstant="2017-03-24T21:58:36.487Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Issuer>idp.oktadev.com</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2017-03-24T22:58:36.487Z" Recipient="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2017-03-24T21:58:36.487Z">
<saml:AudienceRestriction>
<saml:Audience>app.launchdarkly.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<saml:Attribute Name="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="Email">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="FirstName">
<saml:AttributeValue xsi:type="xs:anyType">Jane</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="LastName">
<saml:AttributeValue xsi:type="xs:anyType">Doe</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<saml:AuthnStatement AuthnInstant="2017-03-24T21:58:36.487Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
<?xml version="1.0" ?>
<samlp:Response Destination="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0" ID="_e285f2ec1c708548071f" IssueInstant="2017-03-24T21:58:37Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">idp.oktadev.com</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>NhdPcbTm85iOEiqPM+r51L4ARVsmSgjNYIJHTGxAdhA=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>nvTpT24dpnfxBv4xFwgP/Q3TJ3vKTmR3eXc67hnDXhRpOmoRruVIBUgm/+aLm0uFaZDzay9yOPaBwI1yFeikoM4/iCMWpUhrTyA1orIJC/GZ4YOG+owbawvXcamLlfavxgsAE1f4dWsu4qOCkIjpejC57M+wTgDHV4C74GWABuFCTDWQfTvspK0GAKlwvbccgXR+eRO8nrQkh4xb/wCfu5gTAp1gzB4Z31KXjPf+72hDU0xZ/gDAXUYUFuMJPeYzSMPTN2qUUF/oA/QaM/QOO2BCqTIjtTZa6W7KHgncx8feYo/LzzOGUDWzqeECFM1zvcR1Bbo55TTxEsoOIf5J8w==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDPDCCAiQCCQDydJgOlszqbzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHSmFua3lDbzESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTE0MDMxMjE5NDYzM1oXDTI3MTExOTE5NDYzM1owYDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAOBgNVBAoTB0phbmt5Q28xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGvJpRTTasRUSPqcbqCG+ZnTAurnu0vVpIG9lzExnh11o/BGmzu7lB+yLHcEdwrKBBmpepDBPCYxpVajvuEhZdKFx/Fdy6j5mH3rrW0Bh/zd36CoUNjbbhHyTjeM7FN2yF3u9lcyubuvOzr3B3gX66IwJlU46+wzcQVhSOlMk2tXR+fIKQExFrOuK9tbX3JIBUqItpI+HnAow509CnM134svw8PTFLkR6/CcMqnDfDK1m993PyoC1Y+N4X9XkhSmEQoAlAHPI5LHrvuujM13nvtoVYvKYoj7ScgumkpWNEvX652LfXOnKYlkB8ZybuxmFfIkzedQrbJsyOhfL03cMECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAeHwzqwnzGEkxjzSD47imXaTqtYyETZow7XwBc0ZaFS50qRFJUgKTAmKS1xQBP/qHpStsROT35DUxJAE6NY1Kbq3ZbCuhGoSlY0L7VzVT5tpu4EY8+Dq/u2EjRmmhoL7UkskvIZ2n1DdERtd+YUMTeqYl9co43csZwDno/IKomeN5qaPc39IZjikJ+nUC6kPFKeu/3j9rgHNlRtocI6S1FdtFz9OZMQlpr0JbUt2T3xS/YoQJn6coDmJL5GTiiKM6cOe+Ur1VwzS1JEDbSS2TWWhzq8ojLdrotYLGd9JOsoQhElmz+tMfCFQUFLExinPAyy7YHlSiVX13QH2XTu/iQQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ID="_OGBYRimn0dCxa8EIS0MGw12Fo7usJBgH" IssueInstant="2017-03-24T21:58:37.182Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Issuer>idp.oktadev.com</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2017-03-24T22:58:37.182Z" Recipient="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions>
<saml:AudienceRestriction>
<saml:Audience>app.launchdarkly.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<saml:Attribute Name="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="Email">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="FirstName">
<saml:AttributeValue xsi:type="xs:anyType">Jane</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="LastName">
<saml:AttributeValue xsi:type="xs:anyType">Doe</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<saml:AuthnStatement AuthnInstant="2017-03-24T21:58:37.182Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
<?xml version="1.0" ?>
<samlp:Response Destination="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0" ID="_a06edb0384760275e261" IssueInstant="2017-03-24T21:58:38Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">idp.oktadev.com</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>MiGu+cAsT81eZ1/bb6ck35gMMj777pkx/1Wg37p7lHc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>SA7a7rVq6Dx9RrEwkVL4LCfUFBfcfm815NZh9vrVX1G8Y6PJmpdk5B6Eos+8cuYhEDDheud5ts4U6Qur5rKTIDzPpN28r0/mTu+NfMmz9QYqlxvv3mDFA2bqtbQg6o6mTJnMeYiUNFjixzqNokFUDn6JOsHB68ysLMqGJYoIDEKo83rNGnc4VDXbO/txoWkyYJR6veXkftrUPvPvO91KhLFEIQTI3QEoMqUdjtBLJ40rcewYtJjdJBhuuLp5Gswf/tA40nlx/hBvYC8PvtaMd72KR26RvIG6ybAQGd0mcpLoRQnDI5pHhUXn4KVMUcL1UPahrRTihkXg3lmNWlHQzQ==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDPDCCAiQCCQDydJgOlszqbzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHSmFua3lDbzESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTE0MDMxMjE5NDYzM1oXDTI3MTExOTE5NDYzM1owYDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAOBgNVBAoTB0phbmt5Q28xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGvJpRTTasRUSPqcbqCG+ZnTAurnu0vVpIG9lzExnh11o/BGmzu7lB+yLHcEdwrKBBmpepDBPCYxpVajvuEhZdKFx/Fdy6j5mH3rrW0Bh/zd36CoUNjbbhHyTjeM7FN2yF3u9lcyubuvOzr3B3gX66IwJlU46+wzcQVhSOlMk2tXR+fIKQExFrOuK9tbX3JIBUqItpI+HnAow509CnM134svw8PTFLkR6/CcMqnDfDK1m993PyoC1Y+N4X9XkhSmEQoAlAHPI5LHrvuujM13nvtoVYvKYoj7ScgumkpWNEvX652LfXOnKYlkB8ZybuxmFfIkzedQrbJsyOhfL03cMECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAeHwzqwnzGEkxjzSD47imXaTqtYyETZow7XwBc0ZaFS50qRFJUgKTAmKS1xQBP/qHpStsROT35DUxJAE6NY1Kbq3ZbCuhGoSlY0L7VzVT5tpu4EY8+Dq/u2EjRmmhoL7UkskvIZ2n1DdERtd+YUMTeqYl9co43csZwDno/IKomeN5qaPc39IZjikJ+nUC6kPFKeu/3j9rgHNlRtocI6S1FdtFz9OZMQlpr0JbUt2T3xS/YoQJn6coDmJL5GTiiKM6cOe+Ur1VwzS1JEDbSS2TWWhzq8ojLdrotYLGd9JOsoQhElmz+tMfCFQUFLExinPAyy7YHlSiVX13QH2XTu/iQQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ID="_tUUdPl0s8js1VgSLz2dwcnRVGZXhzwNj" IssueInstant="2017-03-24T21:58:38.347Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Issuer>idp.oktadev.com</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2017-03-24T22:58:38.347Z" Recipient="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="1997-09-29T06:14:00.000Z" NotOnOrAfter="2004-07-25T22:18:00.000Z">
<saml:AudienceRestriction>
<saml:Audience>app.launchdarkly.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<saml:Attribute Name="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="Email">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="FirstName">
<saml:AttributeValue xsi:type="xs:anyType">Jane</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="LastName">
<saml:AttributeValue xsi:type="xs:anyType">Doe</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<saml:AuthnStatement AuthnInstant="2017-03-24T21:58:38.347Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
<?xml version="1.0" ?>
<samlp:Response Destination="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0" ID="_16223f44fcc4370680fb" IssueInstant="2017-03-24T21:58:41Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">idp.oktadev.com</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>o7uuTeqwDts5SjXd5Q9b+uxD42lLJQaj5nBBkwLHNx4=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>r2wnckxyJAw28htJ9MJVH136Cx67NziCWB84A0OrRCZHjJylzkOe/tLQ5gGlFUe3PTXgW+aCO7b3mrN92Y50Q04Eho9+z+o4kDOjQaZaD2hw6HiSjnvapMVKNPYvYlVmhHqedekShBaz55XeOTQaDjmRA0c92iDtCpWqFjeaDRM3nL5lm6JPKR52AXKM0j/KK/uuGrVVN9AZ0rE33K8PcHX35nnHc4lzqCFgCqqoNvcJUW7VWT0fnvfWO7g22/ixzulCuXbA49HJakuZkrcEbLid7RKqxRD9LBJTOsWZ91rm50OwMCpnarJ4k7T7jmzv3TD61Mm/LgnttCiWIumzkA==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDPDCCAiQCCQDydJgOlszqbzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHSmFua3lDbzESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTE0MDMxMjE5NDYzM1oXDTI3MTExOTE5NDYzM1owYDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAOBgNVBAoTB0phbmt5Q28xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGvJpRTTasRUSPqcbqCG+ZnTAurnu0vVpIG9lzExnh11o/BGmzu7lB+yLHcEdwrKBBmpepDBPCYxpVajvuEhZdKFx/Fdy6j5mH3rrW0Bh/zd36CoUNjbbhHyTjeM7FN2yF3u9lcyubuvOzr3B3gX66IwJlU46+wzcQVhSOlMk2tXR+fIKQExFrOuK9tbX3JIBUqItpI+HnAow509CnM134svw8PTFLkR6/CcMqnDfDK1m993PyoC1Y+N4X9XkhSmEQoAlAHPI5LHrvuujM13nvtoVYvKYoj7ScgumkpWNEvX652LfXOnKYlkB8ZybuxmFfIkzedQrbJsyOhfL03cMECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAeHwzqwnzGEkxjzSD47imXaTqtYyETZow7XwBc0ZaFS50qRFJUgKTAmKS1xQBP/qHpStsROT35DUxJAE6NY1Kbq3ZbCuhGoSlY0L7VzVT5tpu4EY8+Dq/u2EjRmmhoL7UkskvIZ2n1DdERtd+YUMTeqYl9co43csZwDno/IKomeN5qaPc39IZjikJ+nUC6kPFKeu/3j9rgHNlRtocI6S1FdtFz9OZMQlpr0JbUt2T3xS/YoQJn6coDmJL5GTiiKM6cOe+Ur1VwzS1JEDbSS2TWWhzq8ojLdrotYLGd9JOsoQhElmz+tMfCFQUFLExinPAyy7YHlSiVX13QH2XTu/iQQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="Failure"/>
</samlp:Status>
<saml:Assertion ID="_v1MQkIzG5Y4vDlBVo4CA86CEuod36QF6" IssueInstant="2017-03-24T21:58:40.992Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Issuer>idp.oktadev.com</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2017-03-24T22:58:40.992Z" Recipient="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2017-03-24T21:58:40.992Z" NotOnOrAfter="2017-03-24T22:58:40.992Z">
<saml:AudienceRestriction>
<saml:Audience>app.launchdarkly.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<saml:Attribute Name="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="Email">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="FirstName">
<saml:AttributeValue xsi:type="xs:anyType">Jane</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="LastName">
<saml:AttributeValue xsi:type="xs:anyType">Doe</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<saml:AuthnStatement AuthnInstant="2017-03-24T21:58:40.992Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
<?xml version="1.0" ?>
<samlp:Response Destination="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0" ID="_24582fac1560df7ea0d2" IssueInstant="2017-03-24T21:58:41Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">idp.oktadev.com</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>hDuyacRyffzisWMz0QW3uIB7+ZYnqVFonU7ckjbh/34=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>mXHkgcPnJBxGeA2RlZkwzFAaNNUejP+ZEOO58ObW2U2qYItEZvzeH11WYuNrFJs4dN9b1eqH5U7rW26BegL24a0RfDGMxsRnPl+/CZaekGYdLScldap26KdFPMLC2YTIYoyA0HhV+vQm0/Wu2t574gnp4JtxfxFtyPmWUAg15nwt9SQKBhp96tiAt6jsFuMfjmTchknGWcIXcwocPUfngpY8gs6lMms5/3NP8g+8OMhTGm0EXg2Y0vq7yhvioLk8y6AFBwy2qiZlxK0ypSiHjwB6T42yPL7FzuEOicLFhoC8NT5AeQ4J7m9iO/JkmeQ4wa4fyLKVHwdFMA6hfZK0xA==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDPDCCAiQCCQDydJgOlszqbzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHSmFua3lDbzESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTE0MDMxMjE5NDYzM1oXDTI3MTExOTE5NDYzM1owYDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAOBgNVBAoTB0phbmt5Q28xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGvJpRTTasRUSPqcbqCG+ZnTAurnu0vVpIG9lzExnh11o/BGmzu7lB+yLHcEdwrKBBmpepDBPCYxpVajvuEhZdKFx/Fdy6j5mH3rrW0Bh/zd36CoUNjbbhHyTjeM7FN2yF3u9lcyubuvOzr3B3gX66IwJlU46+wzcQVhSOlMk2tXR+fIKQExFrOuK9tbX3JIBUqItpI+HnAow509CnM134svw8PTFLkR6/CcMqnDfDK1m993PyoC1Y+N4X9XkhSmEQoAlAHPI5LHrvuujM13nvtoVYvKYoj7ScgumkpWNEvX652LfXOnKYlkB8ZybuxmFfIkzedQrbJsyOhfL03cMECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAeHwzqwnzGEkxjzSD47imXaTqtYyETZow7XwBc0ZaFS50qRFJUgKTAmKS1xQBP/qHpStsROT35DUxJAE6NY1Kbq3ZbCuhGoSlY0L7VzVT5tpu4EY8+Dq/u2EjRmmhoL7UkskvIZ2n1DdERtd+YUMTeqYl9co43csZwDno/IKomeN5qaPc39IZjikJ+nUC6kPFKeu/3j9rgHNlRtocI6S1FdtFz9OZMQlpr0JbUt2T3xS/YoQJn6coDmJL5GTiiKM6cOe+Ur1VwzS1JEDbSS2TWWhzq8ojLdrotYLGd9JOsoQhElmz+tMfCFQUFLExinPAyy7YHlSiVX13QH2XTu/iQQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Requester"/>
</samlp:Status>
<saml:Assertion ID="_dINDjicytb7BCCZGjo6JHXqfDTjlMnKm" IssueInstant="2017-03-24T21:58:41.740Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Issuer>idp.oktadev.com</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2017-03-24T22:58:41.740Z" Recipient="https://4ee49844.ngrok.io/api/sso/saml2/acs/58d4b05673d4f375b8e70fa0"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2017-03-24T21:58:41.740Z" NotOnOrAfter="2017-03-24T22:58:41.740Z">
<saml:AudienceRestriction>
<saml:Audience>app.launchdarkly.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<saml:Attribute Name="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="Email">
<saml:AttributeValue xsi:type="xs:anyType">[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="FirstName">
<saml:AttributeValue xsi:type="xs:anyType">Jane</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="LastName">
<saml:AttributeValue xsi:type="xs:anyType">Doe</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<saml:AuthnStatement AuthnInstant="2017-03-24T21:58:41.740Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
The lib is generating wrong digest value and siganture when the Id is in subelement of the XML, if we put the ID in root of the document it works.
XML sample
<test><subelement Id="123"></subelement></test>
DigestValue generated is <DigestValue>NW8608eQ8/D7oW+DkK4APEcoSmQ=</DigestValue>
correct digest value is <DigestValue>Yyr4tGjKVRhghWuw38f3gwZwt3g=</DigestValue>
, I'm comparing with a Lib I use for Python, I'd like to implement it in Go.
so, if I use the xml below it works
<test Id="123"><subelement></subelement></test>
I tried to undesrtand and modify something here https://github.com/russellhaering/goxmldsig/blob/master/canonicalize.go#L135 and here https://github.com/russellhaering/goxmldsig/blob/master/canonicalize.go#L167 with no luck, I coudn't undesrtand the reason it's changing digest value if ID is not on the root of the document
This would be the correct signature
<?xml version="1.0" encoding="UTF-8"?>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#123">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>Yyr4tGjKVRhghWuw38f3gwZwt3g=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>FYHaTric4WHTcULweGeTNmXByHAxbfA2YMThFbWsnymQSuM/2sh0IUq8MGw3h/o37FumeMdHnSJ/hC9VpmZaCFq2lyVoGhAa72Sbz7euxtqN5zbvBN1O6EfL+CMjHhl06n1esMn86OTI0/XZ0oUtThd6x+VKxzRggwZ8d2T6+VMhzxGugtalKni21u+2HeoEwt+Oi72rkSD52Tm82L/2cuf/IyV16bhLhBifIkCBDtoHTTftDK1Znpu1AW5c4FnQnjh0D6GgQK6HMaf0UqJcyVRns3t3wkJmLUqlKehHrgyA85w/DA3SHtzVXsj+MnDYbZ3h1w7Psev+UnWk66tfAg==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIIGjCCBgKgAwIBAgIIY7m57qeJkQMwDQYJKoZIhvcNAQELBQAwezELMAkGA1UE
BhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxNjA0BgNVBAsTLVNlY3JldGFyaWEg
ZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEfMB0GA1UEAxMWQUMg
Q09OU1VMVEkgQlJBU0lMIFJGQjAeFw0xOTExMjExMzM3MzVaFw0yMDExMjExMzM3
MzVaMIHzMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDELMAkGA1UE
CBMCUk4xEDAOBgNVBAcTB01PU1NPUj8xNjA0BgNVBAsTLVNlY3JldGFyaWEgZGEg
UmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEWMBQGA1UECxMNUkZCIGUt
Q05QSiBBMTEXMBUGA1UECxMOMTIwNzM3NDMwMDAxNzAxRzBFBgNVBAMTPkNBU0Eg
RE8gQ09OU1RSVVRPUiBNQVRFUklBSVMgREUgQ09OU1RSVUNBTyBMVERBOjE5ODQz
NjU3MDAwMTQ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuq6a8xin
3KPto4rhLoT10Nkd8gqMrZMWN/G7p4mw9pDcxWPvugIGjKIPgAqr1spvh4Nosvuk
ugXuj8vObI5ZAmk6aGJnLcz9sqYKwBgI1cxr2Ac7ufZ9ia0ScFDPTfJEVerZLxyD
6B51AGruyxjvwDGSC/i3m51v/xFvkK1VNhnici5QBCiU18/3rtyw2p52lT9tlnmc
fiiMAM2onNq3Wc91suKOvEMj9MW/QEsZdngMEQ1MiUlxtJ90Inw2M8WPgmCtVEqd
IofxVrvhb6UXGUnzEmCurZXR/ZwGgyioeqU4dglRn2zrHGMqzYExLuS6n3BeAq05
EjWJTGOpFJV2qQIDAQABo4IDJzCCAyMwHwYDVR0jBBgwFoAUrvGhcHYTavvnlHec
MixXyxQ4Wd8wDgYDVR0PAQH/BAQDAgXgMIGABgNVHSAEeTB3MHUGBmBMAQIBQTBr
MGkGCCsGAQUFBwIBFl1odHRwOi8vcmVwb3NpdG9yaW8uYWNjb25zdWx0aWJyYXNp
bC5jb20uYnIvYWMtYWNjb25zdWx0aWJyYXNpbHJmYi9kcGMtYWNjb25zdWx0aWJy
YXNpbHJmYi5wZGYwgeAGA1UdHwSB2DCB1TBooGagZIZiaHR0cDovL3JlcG9zaXRv
cmlvLmFjY29uc3VsdGlicmFzaWwuY29tLmJyL2FjLWFjY29uc3VsdGlicmFzaWxy
ZmIvbGNyLWFjLWFjY29uc3VsdGlicmFzaWxyZmJ2NC5jcmwwaaBnoGWGY2h0dHA6
Ly9yZXBvc2l0b3JpbzIuYWNjb25zdWx0aWJyYXNpbC5jb20uYnIvYWMtYWNjb25z
dWx0aWJyYXNpbHJmYi9sY3ItYWMtYWNjb25zdWx0aWJyYXNpbHJmYnY0LmNybDCB
rQYIKwYBBQUHAQEEgaAwgZ0wagYIKwYBBQUHMAKGXmh0dHA6Ly9yZXBvc2l0b3Jp
by5hY2NvbnN1bHRpYnJhc2lsLmNvbS5ici9hYy1hY2NvbnN1bHRpYnJhc2lscmZi
L2FjLWFjY29uc3VsdGlicmFzaWxyZmJ2NC5wN2IwLwYIKwYBBQUHMAGGI2h0dHA6
Ly9vY3NwLmFjY29uc3VsdGlicmFzaWwuY29tLmJyMIG6BgNVHREEgbIwga+BFlRJ
VElDTzE5NTNASE9UTUFJTC5DT02gJwYFYEwBAwKgHhMcTUFSSUEgREUgRkFUSU1B
IEJFWkVSUkEgTElNQaAZBgVgTAEDA6AQEw4xOTg0MzY1NzAwMDE0OaA4BgVgTAED
BKAvEy0yOTA5MTk1MzEzMTAxOTQzNDM0MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDCgFwYFYEwBAwegDhMMMDAwMDAwMDAwMDAwMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDBDANBgkqhkiG9w0BAQsFAAOCAgEAccSve2usWDae/iWS/olz5HvE
tb7Li89dj27nv4vOHSDE5flGFZOdWbDUvCSP5slaDBhdwRSo+ZVd85nq6VBcbUnm
VyqU+biF2YP4RCnHOCMpCUx0uG/AW1eIZ8F32u2BdoeqQG5moYznfCk6ImAwtOPG
u6DHhP4DXKg0Xk3Lbn5VHD4/0ShATBBN+1gDn3DHGNmEcOgW15NwIm2otI6dUE50
l+Qhwiy7jqHXlazrbVdUmIR/y3DIEqBtcjPPEiUxZEDo/ijNyqOrn/AAM8WguAti
oexNu8tJhUIFJLM6J/+ojaoQKwPOggw4m8I58nTsvq3PnsAWb1t69OUfltn3YXbO
/BfF3fvVcbMGpq4kISGNn1BssgcNia8+FSL3Uijzt6rL+63PmlCzPNd8zcbBSdAY
qEhJpOReQxEf+uVxEWtxFX2cC3yPxfW4axvCpsF2m7QI3w3+FkHIsMLtE6bKyMBW
R9LUF5iJ/IDZK3JId0ijsk0p7W5xnWCMFpnej5F5G6q75SLcxuEPdRjON6kzXr8P
RIFaeyzPHzm25MkdRPzEOBV+bNHZkhGCY8UfiS03qElNcjsKBFjdPoGuNM+/0NR/
9MnkzJ1jx8K+WEaMR/3WKRicXY7Yzs1wFFzg3lWpImTIbgBABBlIRJtbVlAnfMUG
GkZpOXJM/XrVtzLssL8=</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
this is my code used to generated the signature
ctx := dsig.NewDefaultSigningContext(keyStore)
ctx.Canonicalizer = dsig.MakeC14N10RecCanonicalizer()
ctx.Hash = crypto.SHA1
ctx.IdAttribute = "Id"
ctx.ElementContainId = "subelement"
ctx.Prefix = ""
doc := etree.NewDocument()
err = doc.ReadFromString(xml)
failOnError(err, "Lendo string xml")
element := doc.FindElements("//")[0]
signedElement, err := ctx.SignEnveloped(element)
signatureElement := signedElement.FindElements("//Signature")[0]
doc.SetRoot(signatureElement)
//nfeElement := doc.FindElements("//NFe")[0]
//nfeElement.Child = append(nfeElement.Child, signatureElement)
signedXml, err := doc.WriteToString()
return signedXml
I changed line 95 for it get the id based on the ElementContainId
field I added
dataId := el.FindElement("//"+ctx.ElementContainId).SelectAttrValue(ctx.IdAttribute, "")
I use below code to verify the signature of the xml file. But, it gives me error:- Could not verify certificate against trusted certs
func ValidateXMLSignature(xmlData []byte, publicKey string) (bool, error) {
doc := etree.NewDocument()
err := doc.ReadFromBytes(xmlData)
if err != nil {
return false, err
}
block, _ := pem.Decode([]byte(aadhaarLatestPublicKey))
pub, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return false, err
}
ctx := goxmldsig.NewDefaultValidationContext(&goxmldsig.MemoryX509CertificateStore{
Roots: []*x509.Certificate{pub},
})
if el := doc.FindElement("OfflinePaperlessKyc"); el != nil {
_, err = ctx.Validate(el)
if err != nil {
helpers.Logger.Errorf("error in validating xml signature:%s", err.Error())
return false, nil
}
return true, nil
}
return false, nil
}
const aadhaarLatestPublicKey = `-----BEGIN CERTIFICATE-----
MIIG7jCCBdagAwIBAgIEAv5vUzANBgkqhkiG9w0BAQsFADCB4jELMAkGA1UEBhMCSU4xLTArBgNVBAoTJENhcHJpY29ybiBJZGVudGl0eSBTZXJ2aWNlcyBQdnQgTHRkLjEdMBsGA1UECxMUQ2VydGlmeWluZyBBdXRob3JpdHkxDzANBgNVBBETBjExMDA5MjEOMAwGA1UECBMFREVMSEkxJzAlBgNVBAkTHjE4LExBWE1JIE5BR0FSIERJU1RSSUNUIENFTlRFUjEfMB0GA1UEMxMWRzUsVklLQVMgREVFUCBCVUlMRElORzEaMBgGA1UEAxMRQ2Fwcmljb3JuIENBIDIwMTQwHhcNMjAwNTI3MDUwMzA1WhcNMjMwNTI3MDUwMzA1WjCCARAxCzAJBgNVBAYTAklOMQ4wDAYDVQQKEwVVSURBSTEaMBgGA1UECxMRVGVjaG5vbG9neSBDZW50cmUxDzANBgNVBBETBjU2MDA5MjESMBAGA1UECBMJS2FybmF0YWthMRIwEAYDVQQJEwliYW5nYWxvcmUxOzA5BgNVBDMTMlVJREFJIFRlY2ggQ2VudHJlLCBBYWRoYXIgQ29tcGxleCwgTlRJIExheW91dCwgVGF0MUkwRwYDVQQFE0BiMTlhODdmYWU3YWU5ZWY1NWZmMTY2YjVjYzYyNTcwMGUyOGQ4MmRhNzZiZDUzZjA5ODM2ZWVhZWFiM2ZlMzg1MRQwEgYDVQQDEwtEUyBVSURBSSAwMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANSINogOm/Y3pyz0xqILE4C8eJ79af1dk9Kt0QWuICQyq2beNWzBFml5BVBLjeUvjbWbz2zv4yY9lotTb0kKlWEwP+yctIVVDliaWHr+/zxcwAFDoJKLULJokvIYaUeSDrLDvtSq2K3eypIvmS5Df/T6miBJKyYbxDj+8LTZxeSXh12xBUs9X6RxkWSM2cqIJkPPb2mPYFwchtTCczapaUYaGoQB6mbbwW1PQR6qXxUBVefFe373sGh3Pyty0bOOw/NBYHLES1p+3jUXSp2ovqMxsEEIq0c/oCjjhbJYUKa0190EhZDyTYojGuNsD4VCb7jJk1xN67szEKyYQ2Ld/40CAwEAAaOCAnkwggJ1MEAGA1UdJQQ5MDcGCisGAQQBgjcUAgIGCCsGAQUFBwMEBggrBgEFBQcDAgYKKwYBBAGCNwoDDAYJKoZIhvcvAQEFMBMGA1UdIwQMMAqACEOABKAHteDPMIGIBggrBgEFBQcBAQR8MHowLAYIKwYBBQUHMAGGIGh0dHA6Ly9vY3ZzLmNlcnRpZmljYXRlLmRpZ2l0YWwvMEoGCCsGAQUFBzAChj5odHRwczovL3d3dy5jZXJ0aWZpY2F0ZS5kaWdpdGFsL3JlcG9zaXRvcnkvQ2Fwcmljb3JuQ0EyMDE0LmNlcjCB+AYDVR0gBIHwMIHtMFYGBmCCZGQCAzBMMEoGCCsGAQUFBwICMD4aPENsYXNzIDMgQ2VydGlmaWNhdGUgaXNzdWVkIGJ5IENhcHJpY29ybiBDZXJ0aWZ5aW5nIEF1dGhvcml0eTBEBgZggmRkCgEwOjA4BggrBgEFBQcCAjAsGipPcmdhbml6YXRpb25hbCBEb2N1bWVudCBTaWduZXIgQ2VydGlmaWNhdGUwTQYHYIJkZAEKAjBCMEAGCCsGAQUFBwIBFjRodHRwczovL3d3dy5jZXJ0aWZpY2F0ZS5kaWdpdGFsL3JlcG9zaXRvcnkvY3BzdjEucGRmMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHBzOi8vd3d3LmNlcnRpZmljYXRlLmRpZ2l0YWwvY3JsL0NhcHJpY29ybkNBLmNybDARBgNVHQ4ECgQITfksz0HaUFUwDgYDVR0PAQH/BAQDAgbAMCIGA1UdEQQbMBmBF2FudXAua3VtYXJAdWlkYWkubmV0LmluMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBACED9DwfU+qImzRkqc4FLN1ED4wgKXsvqwszJrvKKjwiQSxILTcapKPaTuW51HTlKOYUDmQH8MXGWLYjnyJDp/gpj6thcuwiXRFL87UarUMDd5A+dBn4UPkUSuThn+CjrhGQcStaKSz5QfzdOO/2fZeZgDB0xo7IyDtVfC2ZvW1xrxWngKNVkp8XkPNmPW/jHk7395/1obaHsjKNcAaAxNztXGG6azwsURx83Fy6irF4pHFTfZV3Y93iBZovXeetYc1bgIAvLSFd2Yvuy6yGyL8nb8vUMbWYIasZ47E4q+kMDmB49xedQg97L5CRfN0gIrk7foxnTexvSlLtEVo2M/A=
-----END CERTIFICATE-----`
Format of the xml file:-
<OfflinePaperlessKyc referenceId="">
<UidData>
<Poi dob="" gender="" name="" e="" m=""/>
<Poa careof="" country="" dist="" house="" loc="" pc="" po="" state="" street="" subdist="" vtc="" />
<Pht></Pht>
</UidData>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue></DigestValue>
</Reference>
</SignedInfo>
<SignatureValue></SignatureValue>
<KeyInfo>
</KeyInfo>
</Signature>
</OfflinePaperlessKyc>```
I have attempted to sign a entities descriptor element, but I have not been able to use xmlsectool to validate the result:
xmlsectool.sh --verifySignature --certificate saml.crt --inFile example.xml
INFO XMLSecTool - Reading XML document from file 'example.xml'
INFO XMLSecTool - XML document parsed and is well-formed.
WARN Reference - Verification failed for URI "#id1234"
WARN Reference - Expected Digest: D+SEh34cA7/atdQ8ojV9rzUcJcJSAslFZ0aOIwplGfI=
WARN Reference - Actual Digest: EYun0wngsN35ci20wRziCXs0Io7J4bZN+NYRnnTR5QM=
ERROR XMLSecTool - XML document signature verification failed
Could you provide any pointers as to where I am going wrong?
package main
import (
"crypto/tls"
"io/ioutil"
"log"
"github.com/beevik/etree"
"github.com/russellhaering/goxmldsig"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func main() {
certBytes := []byte(`-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIJAKMxnSbqmztEMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD
VQQGEwJHQjETMBEGA1UECAwKQmlybWluZ2hhbTETMBEGA1UEBwwKQmlybWluZ2hh
bTEOMAwGA1UECgwFVGFsaXMxDjAMBgNVBAsMBVRhbGlzMQ4wDAYDVQQDDAVUYWxp
czEbMBkGCSqGSIb3DQEJARYMbXdAdGFsaXMuY29tMB4XDTE3MDgwODIxNTA0NFoX
DTI3MDgwNjIxNTA0NFowgYQxCzAJBgNVBAYTAkdCMRMwEQYDVQQIDApCaXJtaW5n
aGFtMRMwEQYDVQQHDApCaXJtaW5naGFtMQ4wDAYDVQQKDAVUYWxpczEOMAwGA1UE
CwwFVGFsaXMxDjAMBgNVBAMMBVRhbGlzMRswGQYJKoZIhvcNAQkBFgxtd0B0YWxp
cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfyQiwTxAbc6HJ
6aB6NrmDYoVUBqWZ4njZyQqnhf0ZvpqGh8ppMiXjiuJjn72pJYHnOqRQNgJDNhAZ
X5KtJ/YI4XbOruJU3TWX/KnGn7l8TJ5FFmnJWHohJ0f9/+uVv0hivRkSVUwh+q2e
TpKNypNu2Kf8iiGW3dMOY1CYWxWnksM1xoaWKV3mWgMqRqcj4kyLT1t8UctOhKhg
m04HPNTeFCkcmH3IuIiVAi3uVU+zDKec8+cxSHHmnm0iphm8jpT0OjNSGWt7F7+N
NhIa2FOI+Lz6t+VU0WToWnB16qJIhMGcIGPZR7fp/di/0h9Huc+GJBNfbgdVEYiv
7DuF28zzAgMBAAGjUDBOMB0GA1UdDgQWBBRjnMEGZsZR+cSX5/UJcwAZULsKijAf
BgNVHSMEGDAWgBRjnMEGZsZR+cSX5/UJcwAZULsKijAMBgNVHRMEBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQBNrPOgLt1bZPO8283HddeASfzoVK40qqBP0HgLihja
VvABPRkE2046lka6MSDXJTpbg9rMT/JDplWea4gCroD+UX79W/r2WBEHgJ63piq+
wVFoxB4S8IgbQi2N5CEM/yLexWq9O2YDl7gemRc1EES01x64YBlBgHGpMvc6NyjD
ecMdTmUAXgNTTGKlpistVRtArQHaqw3FJE3LfoyEx9fP0joA7Q5U7Z6pvveYXEHl
fSoCeI4UUPOlAGBOR5VWnDYuS+FwB9RIcegycxB12Sd+RLxojpFg6VSk2SSiG9/4
u02uKxgXiZ7/41lHjoTHS9BOoPOT0ZD8C7Goeg8OAMgs
-----END CERTIFICATE-----`)
keyBytes := []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAn8kIsE8QG3Ohyemgeja5g2KFVAalmeJ42ckKp4X9Gb6ahofK
aTIl44riY5+9qSWB5zqkUDYCQzYQGV+SrSf2COF2zq7iVN01l/ypxp+5fEyeRRZp
yVh6ISdH/f/rlb9IYr0ZElVMIfqtnk6SjcqTbtin/Iohlt3TDmNQmFsVp5LDNcaG
lild5loDKkanI+JMi09bfFHLToSoYJtOBzzU3hQpHJh9yLiIlQIt7lVPswynnPPn
MUhx5p5tIqYZvI6U9DozUhlrexe/jTYSGthTiPi8+rflVNFk6FpwdeqiSITBnCBj
2Ue36f3Yv9IfR7nPhiQTX24HVRGIr+w7hdvM8wIDAQABAoIBADrEjdWKvrnaBZ9l
tgg9KG4SRkdpSm8WxKwVLT4AId7eI6dnOiMGtrjB1BIgJnmXufd5sgVuV9awg6tR
Y3kcQXlys2fBGq1rztJfs3HCPU5iP7PZUn8jc4fOEsRw5AznlY/7TMVZae71a/XV
oEFWSHN0bBSOGVyLqZyZGoNuvMAsvZ7ObmfAddLQerPV0nOvv9X332wgo2a+8rnb
NHqcZOLdmGjJRkBbAd0IHFciynb1YlhHIEObmZzD8LVFV0UxhhPDHbRwmrj1T2+j
u9U3rBduJKG+mQxelLOLUB6CNbvcyNtj3wAnyq6IVA9qb/CLXJbEhTgnvNTLnYA3
FJxZysECgYEAzw67MVhQY1VZnN49NiXhhl6ypVIlp3fKOUMMZVgiUeSDPSs4Un9q
ABoFBHT9x/Rs6repl/Yr6V3o8uWz/7V7yArom9/yhErunW8bORfiGVUqibYIKi51
qNJMpamQGI/Uw2AbKCjKhpnCcRjt0YTfuTWXxAxOPYNJZqXEvUaUoNUCgYEAxY3P
H07aR2zTDfjvddG2eieaMLoaTWSuGTUH1P7KplQHEsoE135PyLayzYy5I2HX+JDn
fUDDWXWeI4+NdGdUnRrXOedr/Rewu8RZFxxqBV0TJhmTJzGpoun08YXkj7CBCs60
faohJS5iSpi39XNf2k5/RJHGm2FePfPYQR7sWqcCgYEAx6LYcZdIyr18DXdpZU/Y
xgmADU3K6FDjNZqj1QLI9FRzBQMq5r/aoAZ2V/nExomwig5TAiVj6TmWZLt8dUux
8QozhDbESTFGJ5z8jmusn+gxf113OdRZtVAufnuiZ0wmQ8nh5TKPMoAFra3vfley
rYwyq9+BgGWY29NwgV4P55ECgYB5ThRqkw6xYP9PyxWu8PDtnTeux/eyoinNTKTc
gv+Ilnwpa2cBs4vmIVk1oj1knoXxGXkrjgLmAbTy/QjM+04Xkg2qfpHuvQdGpNBX
wpjPZlGFyZp0LKiPYr2HOMIaATWbn0VxDHCB1jOAvrnmu8uVzzGStziO3IDz5bFa
e1SCbQKBgGNUKKppH7BYDMrb+dqRsB6YI5mFlHZoDhVWkPgDba8klp/NvhTI8ACu
URVaPLlgTRdiG2Q5NVDYPpTrhsCbKwE6HeshNKqhL/VsrK77/oSpSQHeLf88oBV2
rDFpN/In31Wp6c+C4crPQNSWZ9jMohHQkCFOUAyBc6UzcqCa4vqd
-----END RSA PRIVATE KEY-----`)
xmlBytes := []byte(`<EntitiesDescriptor Name="https://your-federation.org/metadata/federation-name.xml" xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><EntityDescriptor entityID="https://idp.example.org/idp/shibboleth"><IDPSSODescriptor protocolSupportEnumeration="urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:2.0:protocol"><Extensions><shibmd:Scope regexp="false">example.org</shibmd:Scope></Extensions><KeyDescriptor><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIEKjCCAxKgAwIBAgIJAIgUuHL4QvkYMA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNVq1og9SGCUU2yRL1tC+Y=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></KeyDescriptor><NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat><NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat><SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://idp.example.org/idp/profile/Shibboleth/SSO" /><SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.example.org/idp/profile/SAML2/POST/SSO" /><SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.example.org/idp/profile/SAML2/Redirect/SSO" /></IDPSSODescriptor><AttributeAuthorityDescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol"><KeyDescriptor><ds:KeyInfo><ds:X509Data><ds:X509Certificate> MIIEKjCCAxKgAwIBAgIJAIgUuHL4QvkYMA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNVq1og9SGCUU2yRL1tC+Y= </ds:X509Certificate></ds:X509Data></ds:KeyInfo></KeyDescriptor><AttributeService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://idp.example.org:8443/idp/profile/SAML1/SOAP/AttributeQuery" /><AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://idp.example.org:8443/idp/profile/SAML2/SOAP/AttributeQuery" /><NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat><NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat></AttributeAuthorityDescriptor><Organization><OrganizationName xml:lang="en">Your Identities</OrganizationName><OrganizationDisplayName xml:lang="en"> Your Identities</OrganizationDisplayName><OrganizationURL xml:lang="en">http://www.example.org/</OrganizationURL></Organization><ContactPerson contactType="technical"><GivenName>Your</GivenName><SurName>Contact</SurName><EmailAddress>[email protected]</EmailAddress></ContactPerson></EntityDescriptor><EntityDescriptor entityID="https://sp.example.org/shibboleth-sp"><SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol"><Extensions><idpdisc:DiscoveryResponse xmlns:idpdisc="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" index="1" Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="http://sp.example.org/Shibboleth.sso/DS"/><idpdisc:DiscoveryResponse xmlns:idpdisc="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" index="2" Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="https://sp.example.org/Shibboleth.sso/DS"/></Extensions><KeyDescriptor><ds:KeyInfo><ds:X509Data><ds:X509Certificate> MIIEPjCCAyagAwIBAgIBADANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQGEwJVUzEVInh+vYSYngQB2sx9LGkR9KHaMKNIGCDehk93Xla4pWJx1w== </ds:X509Certificate></ds:X509Data></ds:KeyInfo></KeyDescriptor><NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat><NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat><AssertionConsumerService index="1" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.example.org/Shibboleth.sso/SAML2/POST"/><AssertionConsumerService index="2" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://sp.example.org/Shibboleth.sso/SAML2/POST-SimpleSign"/><AssertionConsumerService index="3" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sp.example.org/Shibboleth.sso/SAML2/Artifact"/><AssertionConsumerService index="4" Binding="urn:oasis:names:tc:SAML:1.0:profiles:browser-post" Location="https://sp.example.org/Shibboleth.sso/SAML/POST"/><AssertionConsumerService index="5" Binding="urn:oasis:names:tc:SAML:1.0:profiles:artifact-01" Location="https://sp.example.org/Shibboleth.sso/SAML/Artifact"/></SPSSODescriptor><Organization><OrganizationName xml:lang="en">Your Service</OrganizationName><OrganizationDisplayName xml:lang="en">Your Service</OrganizationDisplayName><OrganizationURL xml:lang="en">http://sp.example.org/</OrganizationURL></Organization><ContactPerson contactType="technical"><GivenName>Your</GivenName><SurName>Admin</SurName><EmailAddress>[email protected]</EmailAddress></ContactPerson></EntityDescriptor></EntitiesDescriptor>`)
keyPair, err := tls.X509KeyPair(certBytes, keyBytes)
failOnError(err, "invalided to load keypair")
keyStore := dsig.TLSCertKeyStore(keyPair)
signingContext := dsig.NewDefaultSigningContext(keyStore)
signingContext.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList("")
err = signingContext.SetSignatureMethod(dsig.RSASHA256SignatureMethod)
failOnError(err, "failed to set signature method")
readXMLDoc := etree.NewDocument()
err = readXMLDoc.ReadFromBytes(xmlBytes)
failOnError(err, "cannot parse xml")
elementToSign := readXMLDoc.Root()
elementToSign.CreateAttr("ID", "id1234")
signedElement, err := signingContext.SignEnveloped(elementToSign)
failOnError(err, "failed to sign envelop")
var signedAssertionBuf []byte
{
readXMLDoc.SetRoot(signedElement)
signedAssertionBuf, err = readXMLDoc.WriteToBytes()
failOnError(err, "failed to convert doc to bytes")
}
ioutil.WriteFile("/tmp/test/example.xml", signedAssertionBuf, 0775)
}
I am trying to sign some ISO 20022 messages and the X509Data
type is missing some fields such as X509SubjectName
, X509IssuerSerial
, X509IssuerName
, and X509SerialNumber
(among others).
RFC 3075 provides details on the fields and there are references in other projects as well.
Would a PR be accepted with these additional fields?
For my use case, I wanted empty reference uri = "", but it seems from the code it isn't possible. I would have to assign an id attribute always. Could you provide a fix please ?
We'd like to use HSMs with goxmldsig (and ultimately SAML) for signing, but right now the API requires an RSA private key. I'm not sure if there were any plans to add it, so I've made a pull request #44 that uses the golang crypto.Signer
interface to accomplish this. There's also a few minor changes to enable ECDSA signing and verification. I've made the changes to preserve backwards compatibility so existing code won't break.
Please let me know if you have any questions about the use cases or would like a different approach.
I sadly have to build a Soap client that also supports WSSE signing for messages for interaction with some legacy system. I'm looking into this library to see if I can use it to generate the required signature before sending the message off.
The first problem I ran into is that, for signing SOAP messages, only the body element should be signed. But if I try to do that, the signature generator complains that the namespace is not defined. Which is true; the namespace is defined on the envelope, not deeper down.
Test code;
package main
import (
"crypto/tls"
"fmt"
"log"
"github.com/beevik/etree"
"github.com/russellhaering/goxmldsig"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func main() {
certBytes := []byte(`-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
`)
keyBytes := []byte(`-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
`)
xmlBytes := []byte(`<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://sys.svc.tennet.nl/MMCHub/v1" xmlns:ns2="http://sys.svc.tennet.nl/MMCHub/Header/v1">
<SOAP-ENV:Header>
<ns2:MessageAddressing>
<ns2:technicalMessageId>0849df0a-1912-11eb-8b2d-6c5d3a074dc2</ns2:technicalMessageId>
<ns2:senderId>8720299053908</ns2:senderId>
<ns2:receiverId>8716867999983</ns2:receiverId>
<ns2:carrierId>8719333014463</ns2:carrierId>
<ns2:contentType>ACK_ACTIVATED_FCR</ns2:contentType>
</ns2:MessageAddressing>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<ns1:getMessageRequest>
<ns1:technicalMessageId>3c72e741-190e-11eb-86d0-c0b6f97cb937</ns1:technicalMessageId>
</ns1:getMessageRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>`)
keyPair, err := tls.X509KeyPair(certBytes, keyBytes)
failOnError(err, "Invalid keypair")
keyStore := dsig.TLSCertKeyStore(keyPair)
ctx := dsig.NewDefaultSigningContext(keyStore)
ctx.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList("")
err = ctx.SetSignatureMethod(dsig.RSASHA256SignatureMethod)
failOnError(err, "Failed to set signature mode")
readXMLDoc := etree.NewDocument()
err = readXMLDoc.ReadFromBytes(xmlBytes)
failOnError(err, "Cannot parse XML doc")
elementToSign := readXMLDoc.Root().FindElement("Body")
elementToSign.CreateAttr("ID", "id1234")
signedElement, err := ctx.SignEnveloped(elementToSign)
failOnError(err, "Could not sign")
var signedBuf []byte
readXMLDoc.SetRoot(signedElement)
signedBuf, err = readXMLDoc.WriteToBytes()
failOnError(err, "Failed to write to bytes")
fmt.Println(string(signedBuf))
}
Errors out with; Could not sign: undeclared namespace prefix: 'SOAP-ENV'
Is there any way to get this to work, or am I trying to do something incredibly unholy here?
Full disclaimer; I know very little about SOAP and only a moderate amount about xml signatures, so perhaps this is a really obvious question. I previously tried to write this client in Python, but an issue in the way it handles signatures makes it not viable. I also built a test implementation in PHP, which works, but I'm extremely reluctant to use that for a production deployment.
Hope someone can help me out a bit here :)
Not always the error message coming from this package makes sense in a broader context.
That's where our application sometimes struggles to offer a better diagnostic for users.
One example is the error that occurs when the signing certificate differs from the one in the XML document:
Could not verify certificate against trusted certs
The message seems sufficient in this context but we'd love to offer more insights for a quicker resolution, for example stating that signing certificate may need to be updated.
There's always room for improvement in error messages but we have no expectation that this package be responsible for provide such high level diagnostic in all cases. However, providing means for applications to handle errors selectively seems something within the reach of the package.
Currently to achieve this goal, we would have to watch for a particular error message with a logic based on string matching, which tends to be fragile. Instead, we'd rather match a particular error type.
In the last few years, the Go community has been moving in that direction:
https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully
https://golang.org/doc/go1.13#error_wrapping
https://github.com/golang/go/wiki/ErrorValueFAQ
We're looking forward to see strongly typed errors over time.
A few issues with OAM (Oracle Access Manager) generated assertions:
Signature
does not always reference the top-level elementxmlns
defined at the top level causes canonicalization problemsSigned payload and certificate:
https://gist.github.com/Calpicow/fd1d03ded8dc9da1570155bc14aa689a
https://gist.github.com/Calpicow/ef34701804053d042739137b2efd708a
Expected canonicalization: https://gist.github.com/Calpicow/22062f1cf9283621226c5dee2cb9bb0d
Current canonicalization: https://gist.github.com/Calpicow/405b039350d4efff2537ce2f204b6964
I'm trying to validate signed xml, but getting error: invalid CanonicalizationMethod on Signature: w3.org/TR/2001/REC-xml-c14n-20010315. Code below:
package main
import (
"crypto/x509"
"io/ioutil"
"log"
"net/http"
"github.com/beevik/etree"
dsig "github.com/russellhaering/goxmldsig"
)
const (
rootCertURL = "http://root.gov.kz/root_cer/root_rsa.crt"
pkiCertURL = "http://root.gov.kz/root_cer/pki_rsa.crt"
)
func main() {
roots := getTrustedCerts()
doc := etree.NewDocument()
if err := doc.ReadFromString(testXML); err != nil {
log.Fatalln(err)
}
if err := validate(roots, doc.Root()); err != nil {
log.Fatalln(err)
}
log.Println("success")
}
func getTrustedCerts() []*x509.Certificate {
store := []*x509.Certificate{}
rootCert, err := downloadCert(rootCertURL)
if err != nil {
log.Println(err)
} else {
store = append(store, rootCert)
}
pkiCert, err := downloadCert(pkiCertURL)
if err != nil {
log.Println(err)
} else {
store = append(store, pkiCert)
}
return store
}
func downloadCert(url string) (*x509.Certificate, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
cert, err := x509.ParseCertificate(body)
if err != nil {
return nil, err
}
return cert, nil
}
// Validate an element against a root certificate
func validate(roots []*x509.Certificate, el *etree.Element) error {
// Construct a signing context with one or more roots of trust.
ctx := dsig.NewDefaultValidationContext(&dsig.MemoryX509CertificateStore{
Roots: roots,
})
// It is important to only use the returned validated element.
// See: https://www.w3.org/TR/xmldsig-bestpractices/#check-what-is-signed
validated, err := ctx.Validate(el)
if err != nil {
return err
}
doc := etree.NewDocument()
doc.SetRoot(validated)
str, err := doc.WriteToString()
if err != nil {
return err
}
log.Println(str)
return nil
}
Signed XML:
<?xml version="1.0" encoding="utf-8" standalone="no"?><root ID="rootID">
<name>Ivan</name>
<iin>123456789012</iin>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>6b9amiF3pI3EjKBHADPH0xgoqYtewg5+oeovWEaBmzA=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
ost70Ykv++A9Ls4G4T8622d+atoQyA388Ttf7Kc8JocwBBns4ytdlnaYhPfGNLIdQDD+3k6tbEOw
gBEzuW/SEyR/bXkTTFZCdpLdEmfBYa+PY6S+ZtV9TUkces7IQ9OxwiE+3hwo0FmMiBp7DMeJmjC7
XjvaBKJUO4MGRyIAyxn/S0e6rI5GPYRWAAH3dnIyIF+rQOi8I/B8H9+rQ9FZKgtPH4RzxMsj+YQ7
Hp8JgdGuQnzn2mzJuAVGEgFYlN0NxR40vlOrsu1FSfVlR/3OBCxwen+zHwysLeixpXHNIzQ6D1xW
+KRV7iDWK3bLLgJ15F07x7wptO5+0gGOOVr06A==
</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIG9DCCBNygAwIBAgIUTFVCYjrFFRdWjgJW0G8fUs6LLk4wDQYJKoZIhvcNAQELBQAwgc4xCzAJ
BgNVBAYTAktaMRUwEwYDVQQHDAzQkNCh0KLQkNCd0JAxFTATBgNVBAgMDNCQ0KHQotCQ0J3QkDFM
MEoGA1UECgxD0KDQnNCaIMKr0JzQldCc0JvQldCa0JXQotCi0IbQmiDQotCV0KXQndCY0JrQkNCb
0KvSmiDSmtCr0JfQnNCV0KLCuzFDMEEGA1UEAww60rDQm9Ci0KLQq9KaINCa0KPTmNCb0JDQndCU
0KvQoNCj0KjQqyDQntCg0KLQkNCb0KvSmiAoUlNBKTAeFw0xNzA3MjcwMzU1MDZaFw0xODA3Mjcw
MzU1MDZaMIHJMSwwKgYDVQQDDCPQkdCQ0JnQotCj0KDQodCr0J3QntCSINCU0JDQndCY0K/QoDEf
MB0GA1UEBAwW0JHQkNCZ0KLQo9Cg0KHQq9Cd0J7QkjEYMBYGA1UEBRMPSUlOOTIwNzI3MzAwMDQ0
MQswCQYDVQQGEwJLWjEVMBMGA1UEBwwM0JDQm9Cc0JDQotCrMRUwEwYDVQQIDAzQkNCb0JzQkNCi
0KsxIzAhBgNVBCoMGtCh0JXQmdCi0JrQkNCh0KvQnNCe0JLQmNCnMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAvW0Lyoex/kkhq5Xb5uCOtEpp4zjc34M5UGftcgmY6FXvlCaPm4415cmk
Kyaz6M+vmsK3T/wH3S2Up5cLKo022BgpBTYg6+lPUQgigYM7PPc20aLySrMg+Gu4HitokrdWgA/H
hjr14HAOFNiEZm7UpeLAhBfuAz/S9TeCct0C/dp75X8K7zOdXX1n/npnMZKMStPVJ94Cbdpprz/O
lNWzk+MGUB5+2yy4k4zBUamyEk8QzsJZID4Hva8ZIwqSXe4gyCe46iPxPZ8EKiwR4Pn6BXj0k7G1
a8A1jYEqc91QMX+L4CCS5M+BeUvbrcdMjNEoy71YG6m9qgNsBGl7WueMawIDAQABo4IByzCCAccw
DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggqgw4DAwQBATAPBgNVHSMECDAG
gARVtbTiMB0GA1UdDgQWBBQKnKaePX9Y74pplb7yI5ql8zxiJDBeBgNVHSAEVzBVMFMGByqDDgMD
AgQwSDAhBggrBgEFBQcCARYVaHR0cDovL3BraS5nb3Yua3ovY3BzMCMGCCsGAQUFBwICMBcMFWh0
dHA6Ly9wa2kuZ292Lmt6L2NwczBOBgNVHR8ERzBFMEOgQaA/hh1odHRwOi8vY3JsLnBraS5nb3Yu
a3ovcnNhLmNybIYeaHR0cDovL2NybDEucGtpLmdvdi5rei9yc2EuY3JsMFIGA1UdLgRLMEkwR6BF
oEOGH2h0dHA6Ly9jcmwucGtpLmdvdi5rei9kX3JzYS5jcmyGIGh0dHA6Ly9jcmwxLnBraS5nb3Yu
a3ovZF9yc2EuY3JsMGIGCCsGAQUFBwEBBFYwVDAuBggrBgEFBQcwAoYiaHR0cDovL3BraS5nb3Yu
a3ovY2VydC9wa2lfcnNhLmNlcjAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AucGtpLmdvdi5rejAN
BgkqhkiG9w0BAQsFAAOCAgEAColZth/p4wVdcPU1AHTMhNeyLtSJI4K5A7/NoOsqYsH5qpE89gPI
mxB4NAvtmHD49f/lHLvzeIBh+snO+lfJZYXaWcYwU1+dJRyB/bE+W6vcEa5N79eihSyl9fsQTYcz
jBsXzUx0Sv2vAiZH+RIowSsg/m9+UZDt5eNcL7eqkr/JDs0I5VVYXFKwNP1rPam4jfuJKB9w/bEg
6G6RM0/DGaXxLAimVB6gLQzT1hdQzgG8YOERJxjlTeRUICUiEqFz5mZzlJ6zb2+N7lUCzRu385o1
DeWjRJZaTxFKM9JJv8a6zPjcuFA+PIsDy9GSLby1OfZaJJo/7w4iLtJiYDuyMTXisnOknmVr5LC6
fft4AXOq7zOTn7t5r3T9lb5VmorfnqdqSXrep6c/dlkSlyP2mYhUE3JOSQTraJQH/jjcWH5hfewb
/9kPWqDlTpBnok9pcciRSYOgzqkpe0CJ3ZNyj+YNuL58O+TkV9MOwe8wWrWe8rVYV61E597WJZJ/
m6qKBPYUy+zoRVK/XdYYAMsBC2zHrz8n7Z8k6s9FQo4YLgprMQh6Hcq42PgnCZZGxxJ4wU44STUj
HCtohHNYjhz+sZfKg6KEFPzGJN1O7rYd8q0Gl9vQtKMjIsETZ7BRYbXxuzMVA2CMhxiXJS929qH2
ce48JWaAdMkyzyjcF8t3tVY=
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature></root>
It would seem as if the xml namespace is not being handled correctly. If I create a signature for the following XML example the signature cannot be validated:
<Organization xmlns="http://www.w3.org/2000/xmlns" ID="id1234">
<OrganizationName xml:lang="en">Your Identities</OrganizationName>
<OrganizationDisplayName xml:lang="en">Your Identities</OrganizationDisplayName>
<OrganizationURL xml:lang="en">http://www.example.org/</OrganizationURL>
</Organization>
▶ ~/workspace/xmlsectool/xmlsectool-2.0.0/xmlsectool.sh --verifySignature --certificate saml.crt --inFile test.xml
INFO XMLSecTool - Reading XML document from file 'test.xml'
INFO XMLSecTool - XML document parsed and is well-formed.
WARN Reference - Verification failed for URI "#id1234"
WARN Reference - Expected Digest: 7G4WNjtqxoFobBdFzQtblVRj6oAFVVA/9Jac8HOioAI=
WARN Reference - Actual Digest: nisb5vb0nPW3Ajd6bkypeJ0QZIEC5VZ2cALuW4lUqYg=
ERROR XMLSecTool - XML document signature verification failed
Whereas the following XML can be verified:
<Organization xmlns="http://www.w3.org/2000/xmlns" ID="id1234">
<OrganizationName>Your Identities</OrganizationName>
<OrganizationDisplayName>Your Identities</OrganizationDisplayName>
<OrganizationURL>http://www.example.org/</OrganizationURL>
</Organization>
▶ ~/workspace/xmlsectool/xmlsectool-2.0.0/xmlsectool.sh --verifySignature --certificate saml.crt --inFile test.xml
INFO XMLSecTool - Reading XML document from file 'test.xml'
INFO XMLSecTool - XML document parsed and is well-formed.
INFO XMLSecTool - XML document signature verified.
Below is the minimum amount of code to demonstrate the issue:
package main
import (
"crypto/tls"
"fmt"
"log"
"github.com/beevik/etree"
"github.com/russellhaering/goxmldsig"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func main() {
certBytes := []byte(`-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIJAKMxnSbqmztEMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD
VQQGEwJHQjETMBEGA1UECAwKQmlybWluZ2hhbTETMBEGA1UEBwwKQmlybWluZ2hh
bTEOMAwGA1UECgwFVGFsaXMxDjAMBgNVBAsMBVRhbGlzMQ4wDAYDVQQDDAVUYWxp
czEbMBkGCSqGSIb3DQEJARYMbXdAdGFsaXMuY29tMB4XDTE3MDgwODIxNTA0NFoX
DTI3MDgwNjIxNTA0NFowgYQxCzAJBgNVBAYTAkdCMRMwEQYDVQQIDApCaXJtaW5n
aGFtMRMwEQYDVQQHDApCaXJtaW5naGFtMQ4wDAYDVQQKDAVUYWxpczEOMAwGA1UE
CwwFVGFsaXMxDjAMBgNVBAMMBVRhbGlzMRswGQYJKoZIhvcNAQkBFgxtd0B0YWxp
cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfyQiwTxAbc6HJ
6aB6NrmDYoVUBqWZ4njZyQqnhf0ZvpqGh8ppMiXjiuJjn72pJYHnOqRQNgJDNhAZ
X5KtJ/YI4XbOruJU3TWX/KnGn7l8TJ5FFmnJWHohJ0f9/+uVv0hivRkSVUwh+q2e
TpKNypNu2Kf8iiGW3dMOY1CYWxWnksM1xoaWKV3mWgMqRqcj4kyLT1t8UctOhKhg
m04HPNTeFCkcmH3IuIiVAi3uVU+zDKec8+cxSHHmnm0iphm8jpT0OjNSGWt7F7+N
NhIa2FOI+Lz6t+VU0WToWnB16qJIhMGcIGPZR7fp/di/0h9Huc+GJBNfbgdVEYiv
7DuF28zzAgMBAAGjUDBOMB0GA1UdDgQWBBRjnMEGZsZR+cSX5/UJcwAZULsKijAf
BgNVHSMEGDAWgBRjnMEGZsZR+cSX5/UJcwAZULsKijAMBgNVHRMEBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQBNrPOgLt1bZPO8283HddeASfzoVK40qqBP0HgLihja
VvABPRkE2046lka6MSDXJTpbg9rMT/JDplWea4gCroD+UX79W/r2WBEHgJ63piq+
wVFoxB4S8IgbQi2N5CEM/yLexWq9O2YDl7gemRc1EES01x64YBlBgHGpMvc6NyjD
ecMdTmUAXgNTTGKlpistVRtArQHaqw3FJE3LfoyEx9fP0joA7Q5U7Z6pvveYXEHl
fSoCeI4UUPOlAGBOR5VWnDYuS+FwB9RIcegycxB12Sd+RLxojpFg6VSk2SSiG9/4
u02uKxgXiZ7/41lHjoTHS9BOoPOT0ZD8C7Goeg8OAMgs
-----END CERTIFICATE-----`)
keyBytes := []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAn8kIsE8QG3Ohyemgeja5g2KFVAalmeJ42ckKp4X9Gb6ahofK
aTIl44riY5+9qSWB5zqkUDYCQzYQGV+SrSf2COF2zq7iVN01l/ypxp+5fEyeRRZp
yVh6ISdH/f/rlb9IYr0ZElVMIfqtnk6SjcqTbtin/Iohlt3TDmNQmFsVp5LDNcaG
lild5loDKkanI+JMi09bfFHLToSoYJtOBzzU3hQpHJh9yLiIlQIt7lVPswynnPPn
MUhx5p5tIqYZvI6U9DozUhlrexe/jTYSGthTiPi8+rflVNFk6FpwdeqiSITBnCBj
2Ue36f3Yv9IfR7nPhiQTX24HVRGIr+w7hdvM8wIDAQABAoIBADrEjdWKvrnaBZ9l
tgg9KG4SRkdpSm8WxKwVLT4AId7eI6dnOiMGtrjB1BIgJnmXufd5sgVuV9awg6tR
Y3kcQXlys2fBGq1rztJfs3HCPU5iP7PZUn8jc4fOEsRw5AznlY/7TMVZae71a/XV
oEFWSHN0bBSOGVyLqZyZGoNuvMAsvZ7ObmfAddLQerPV0nOvv9X332wgo2a+8rnb
NHqcZOLdmGjJRkBbAd0IHFciynb1YlhHIEObmZzD8LVFV0UxhhPDHbRwmrj1T2+j
u9U3rBduJKG+mQxelLOLUB6CNbvcyNtj3wAnyq6IVA9qb/CLXJbEhTgnvNTLnYA3
FJxZysECgYEAzw67MVhQY1VZnN49NiXhhl6ypVIlp3fKOUMMZVgiUeSDPSs4Un9q
ABoFBHT9x/Rs6repl/Yr6V3o8uWz/7V7yArom9/yhErunW8bORfiGVUqibYIKi51
qNJMpamQGI/Uw2AbKCjKhpnCcRjt0YTfuTWXxAxOPYNJZqXEvUaUoNUCgYEAxY3P
H07aR2zTDfjvddG2eieaMLoaTWSuGTUH1P7KplQHEsoE135PyLayzYy5I2HX+JDn
fUDDWXWeI4+NdGdUnRrXOedr/Rewu8RZFxxqBV0TJhmTJzGpoun08YXkj7CBCs60
faohJS5iSpi39XNf2k5/RJHGm2FePfPYQR7sWqcCgYEAx6LYcZdIyr18DXdpZU/Y
xgmADU3K6FDjNZqj1QLI9FRzBQMq5r/aoAZ2V/nExomwig5TAiVj6TmWZLt8dUux
8QozhDbESTFGJ5z8jmusn+gxf113OdRZtVAufnuiZ0wmQ8nh5TKPMoAFra3vfley
rYwyq9+BgGWY29NwgV4P55ECgYB5ThRqkw6xYP9PyxWu8PDtnTeux/eyoinNTKTc
gv+Ilnwpa2cBs4vmIVk1oj1knoXxGXkrjgLmAbTy/QjM+04Xkg2qfpHuvQdGpNBX
wpjPZlGFyZp0LKiPYr2HOMIaATWbn0VxDHCB1jOAvrnmu8uVzzGStziO3IDz5bFa
e1SCbQKBgGNUKKppH7BYDMrb+dqRsB6YI5mFlHZoDhVWkPgDba8klp/NvhTI8ACu
URVaPLlgTRdiG2Q5NVDYPpTrhsCbKwE6HeshNKqhL/VsrK77/oSpSQHeLf88oBV2
rDFpN/In31Wp6c+C4crPQNSWZ9jMohHQkCFOUAyBc6UzcqCa4vqd
-----END RSA PRIVATE KEY-----`)
xmlBytes := []byte(`<Organization xmlns="http://www.w3.org/2000/xmlns">
<OrganizationName xml:lang="en">Your Identities</OrganizationName>
<OrganizationDisplayName xml:lang="en">Your Identities</OrganizationDisplayName>
<OrganizationURL xml:lang="en">http://www.example.org/</OrganizationURL>
</Organization>`)
// xmlBytes := []byte(`<Organization xmlns="http://www.w3.org/2000/xmlns">
// <OrganizationName>Your Identities</OrganizationName>
// <OrganizationDisplayName>Your Identities</OrganizationDisplayName>
// <OrganizationURL>http://www.example.org/</OrganizationURL>
// </Organization>`)
keyPair, err := tls.X509KeyPair(certBytes, keyBytes)
failOnError(err, "invalided to load keypair")
keyStore := dsig.TLSCertKeyStore(keyPair)
signingContext := dsig.NewDefaultSigningContext(keyStore)
signingContext.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList("")
err = signingContext.SetSignatureMethod(dsig.RSASHA256SignatureMethod)
failOnError(err, "failed to set signature method")
readXMLDoc := etree.NewDocument()
err = readXMLDoc.ReadFromBytes(xmlBytes)
failOnError(err, "cannot parse xml")
elementToSign := readXMLDoc.Root()
elementToSign.CreateAttr("ID", "id1234")
signedElement, err := signingContext.SignEnveloped(elementToSign)
failOnError(err, "failed to sign envelop")
var signedAssertionBuf []byte
readXMLDoc.SetRoot(signedElement)
signedAssertionBuf, err = readXMLDoc.WriteToBytes()
failOnError(err, "failed to convert doc to bytes")
fmt.Println(string(signedAssertionBuf))
}
Hello there, reading this function:
func (ctx *ValidationContext) transform(
el *etree.Element,
sig *types.Signature,
ref *types.Reference) (*etree.Element, Canonicalizer, error) {
I can see that selects the canonicalizer based on the list of Transforms
But ommits the CanonicalizationMethod tag:
So then, digestValue calculations are wrong.
the rationale is that you'd like to avoid holding the key materials yourself, so allowing the signing context to use an external provider would help mitigate that by having a secure KMS/HSM/etc. sign the payload
I'm hitting the Expected Enveloped and C14N transforms
error when validating signatures. The relevant <Transforms>
element has only a single child:
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="#id">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
</Reference>
</SignedInfo>
The signature verifies if I hardcode pretty much any canonicalizer in the case where one isn't specified, but my reading of the spec doesn't seem to support this fallback canonicalizer. Any ideas?
Totally willing to spend some cycles investigating and bringing Reference transforms more inline with the spec if this is indeed some invalid behavior in goxmldsig.
Would be great to receive a notification through this issue when the author wants to add Manifest support. Thanks.
I have done some work see diff:
main...lafriks:go-xmldsig:main
Would you be interested in working together on merging this? (of course except my changes about package rename and CI stuff)
Just copy pasting the exact Signing
code from README, produces the following error. And so does in complex code whenever I try it.
panic: Missing ID attribute
When I look closely into the source code, the default ID attribute that is being set has an empty value. And I can't even find any option to set the ID attr, since in my XML the attribute is actually referenceId
and not ID
.
This line should be:
dataId := el.SelectAttrValue(ctx.IdAttribute, "")
I am using github.com/russellhaering/goxmldsig v1.2.0
I have the following Go structs that represent a document being signed, however the signature is nested inside of the header (AppHdr) struct.
type Request struct {
XMLName xml.Name `xml:"Message"`
Attrs []xml.Attr `xml:",attr"`
Header headreq.AppHdr `xml:"AppHdr"`
Body document.Iso20022Message
}
type AppHdr struct {
XMLName xml.Name `xml:"AppHdr"`
Attrs []xml.Attr `xml:",attr"`
...
Sgntr *Sgntr `xml:"head:Sgntr,omitempty"`
}
type Sgntr struct {
Attrs []xml.Attr `xml:",attr"`
Signature *sigtypes.Signature
}
We have the following code to sign the document.
edoc := etree.NewDocument()
err := edoc.ReadFromBytes(data)
ctx := dsig.NewDefaultSigningContext(mh.keyStore)
signed, err := ctx.SignEnveloped(notSigned)
// ...
signedDoc := etree.NewDocument()
signedDoc.SetRoot(notSigned)
out, err := signedDoc.WriteToBytes()
// ...
return out, nil
This generates the following xml:
<Message xmlns="urn:tch" xmlns:p3="http://www.w3.org/2001/XMLSchema-instance">
<AppHdr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
... (No head:Sgntr element)
</AppHdr>
<CreditTransfer>
...
</CreditTransfer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue></ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue></ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate></ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</Message>
This is unexpected because I would expect *sigtypes.Signature
to stand-in for the Signature when nested inside the object. It should look like the following (which matches the spec I'm following).
<Message xmlns="urn:tch" xmlns:p3="http://www.w3.org/2001/XMLSchema-instance">
<AppHdr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
...
<head:Sgntr>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>...</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>...</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</head:Sgntr>
</AppHdr>
<CreditTransfer>
...
</CreditTransfer>
</Message>
FWIW I've tried to hack in support for moving ds:Signature
after signing, but that seems to fail with my validator (3rd party). I understand that manipulating the XML would invalidate the signature, but was hoping it would work. The goxmlsig library will validate the document with ds:Signature
appended on the end, but that fails the spec I'm following.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.