diff --git a/.travis.yml b/.travis.yml index a651931..5ea7acd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,4 +40,4 @@ after_failure: - cat ./target/test/report.xml after_success: - - if [ "$TRAVIS_GO_VERSION" = "1.7" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi; + - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi; diff --git a/Makefile b/Makefile index 9059ea5..29869a7 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,8 @@ endif # Add the GO binary dir in the PATH export PATH := $(GOPATH)/bin:$(PATH) +GOENV=GOPATH=$(GOPATH) CGO_CFLAGS_ALLOW='-w' + # --- MAKE TARGETS --- # Display general help about this command @@ -81,9 +83,8 @@ all: help # Run the unit tests test: @mkdir -p target/test - GOPATH=$(GOPATH) \ - go test -covermode=atomic -bench=. -race -v . | \ - tee >(PATH=$(GOPATH)/bin:$(PATH) go-junit-report > target/test/report.xml); \ + $(GOENV) go test -covermode=atomic -bench=. -race -v . | \ + tee >($(GOENV) go-junit-report > target/test/report.xml); \ test $${PIPESTATUS[0]} -eq 0 # Format the source code @@ -98,44 +99,42 @@ fmtcheck: # Check for syntax errors vet: - GOPATH=$(GOPATH) go vet . + $(GOENV) go vet . # Check for style errors lint: - GOPATH=$(GOPATH) PATH=$(GOPATH)/bin:$(PATH) golint . + $(GOENV) golint . # Generate the coverage report coverage: @mkdir -p target/report - GOPATH=$(GOPATH) \ - go test -covermode=count -coverprofile=target/report/coverage.out -v . && \ - GOPATH=$(GOPATH) \ - go tool cover -html=target/report/coverage.out -o target/report/coverage.html + $(GOENV) go test -covermode=count -coverprofile=target/report/coverage.out -v . && \ + $(GOENV) go tool cover -html=target/report/coverage.out -o target/report/coverage.html # Report cyclomatic complexity cyclo: @mkdir -p target/report - GOPATH=$(GOPATH) gocyclo -avg . | tee target/report/cyclo.txt ; test $${PIPESTATUS[0]} -eq 0 + $(GOENV) gocyclo -avg . | tee target/report/cyclo.txt ; test $${PIPESTATUS[0]} -eq 0 # Detect ineffectual assignments ineffassign: @mkdir -p target/report - GOPATH=$(GOPATH) ineffassign . | tee target/report/ineffassign.txt ; test $${PIPESTATUS[0]} -eq 0 + $(GOENV) ineffassign . | tee target/report/ineffassign.txt ; test $${PIPESTATUS[0]} -eq 0 # Detect commonly misspelled words in source files misspell: @mkdir -p target/report - GOPATH=$(GOPATH) misspell -error . | tee target/report/misspell.txt ; test $${PIPESTATUS[0]} -eq 0 + $(GOENV) misspell -error . | tee target/report/misspell.txt ; test $${PIPESTATUS[0]} -eq 0 # AST scanner astscan: @mkdir -p target/report - GOPATH=$(GOPATH) gas ./*.go | tee target/report/astscan.txt ; test $${PIPESTATUS[0]} -eq 0 + $(GOENV) gas ./... | tee target/report/astscan.txt ; test $${PIPESTATUS[0]} -eq 0 # Generate source docs docs: @mkdir -p target/docs - nohup sh -c 'GOPATH=$(GOPATH) godoc -http=127.0.0.1:6060' > target/godoc_server.log 2>&1 & + nohup sh -c '$(GOENV) godoc -http=127.0.0.1:6060' > target/godoc_server.log 2>&1 & wget --directory-prefix=target/docs/ --execute robots=off --retry-connrefused --recursive --no-parent --adjust-extension --page-requisites --convert-links http://127.0.0.1:6060/pkg/github.com/${VENDOR}/${PROJECT}/ ; kill -9 `lsof -ti :6060` @echo ''${PKGNAME}' Documentation ...' > target/docs/index.html @@ -159,12 +158,12 @@ deps: # Remove any build artifact clean: - GOPATH=$(GOPATH) go clean ./... + $(GOENV) go clean ./... # Deletes any intermediate file nuke: rm -rf ./target - GOPATH=$(GOPATH) go clean -i ./... + $(GOENV) go clean -i ./... # Full build and test sequence buildall: deps qa diff --git a/cgo_dl.go b/cgo.go similarity index 66% rename from cgo_dl.go rename to cgo.go index 3340d08..3c6af32 100644 --- a/cgo_dl.go +++ b/cgo.go @@ -1,18 +1,13 @@ -// +build !static - package xmlsec +// #cgo pkg-config: xmlsec1 libxml-2.0 // #cgo linux CFLAGS: -w -// #cgo darwin CFLAGS: -Wno-invalid-pp-token -Wno-header-guard -// #cgo pkg-config: xmlsec1 +// #cgo linux LDFLAGS: -lxml2 -lm // #include // #include // #include // #include // #include -import "C" - -// #cgo pkg-config: libxml-2.0 // #include // #include // #include diff --git a/cgo_static.go b/cgo_static.go deleted file mode 100644 index eeb4791..0000000 --- a/cgo_static.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build static - -package xmlsec - -// #cgo linux CFLAGS: -w -// #cgo darwin CFLAGS: -Wno-invalid-pp-token -Wno-header-guard -// #cgo pkg-config: --static xmlsec1 -// #include -// #include -// #include -// #include -// #include -import "C" - -// #cgo pkg-config: --static libxml-2.0 -// #include -// #include -// #include -import "C" diff --git a/examples/xmldsig.go b/examples/xmldsig.go index 0563ad2..de1a4ba 100644 --- a/examples/xmldsig.go +++ b/examples/xmldsig.go @@ -42,7 +42,7 @@ func main() { fmt.Printf("%s\n", err) os.Exit(1) } - os.Stdout.Write(signedBuf) + os.Stdout.Write(signedBuf) //#nosec } if *doVerify { diff --git a/resources/certs/cert1 b/resources/certs/cert1 new file mode 100644 index 0000000..ec54c73 --- /dev/null +++ b/resources/certs/cert1 @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIDzzCCAzigAwIBAgIJAK+ii7kzrdqtMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEQMA4G +A1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3 +DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMCAXDTE0MDUyMzE3NTIzOFoYDzIxMTQw +NDI5MTc1MjM4WjCBnDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx +PTA7BgNVBAoTNFhNTCBTZWN1cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtz +ZXkuY29tL3htbHNlYykxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAfBgkqhkiG +9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC +QQCyuvKJ2CuUPD33ghPt4Q8MilesHxVbbpyKfmabrYVpDGVDmOKKp337qJUZZ95K +fwlXbR2j0zyKWJmvRxUx+PsTAgMBAAGjggFFMIIBQTAMBgNVHRMEBTADAQH/MCwG +CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV +HQ4EFgQU/uTsUyTwlZXHELXhRLVdOWVa434wgeMGA1UdIwSB2zCB2IAUBrWkrKeq +dUTqFZxP3wWDT2oe/guhgbSkgbEwga4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpD +YWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFyeSAoaHR0cDov +L3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMRAwDgYDVQQLEwdSb290IENBMRYwFAYD +VQQDEw1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3Nl +eS5jb22CCQCvoou5M63arDANBgkqhkiG9w0BAQUFAAOBgQBuTAW63AgWqqUDPGi8 +BiXbdKHhFP4J8qgkdv5WMa6SpSWVgNgOYXkK/BSg1aSmQtGv8/8UvBRPoJnO4y0N +jWUFf1ubOgUNmedYNLq7YbTp8yTGWeogCyM2xdWELMP8BMgQL0sP+MDAFMKO3itY +mEWnCEsP15HKSTms54RNj7oJ+A== +-----END CERTIFICATE----- + diff --git a/resources/certs/cert2 b/resources/certs/cert2 new file mode 100644 index 0000000..14fc320 --- /dev/null +++ b/resources/certs/cert2 @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIID9zCCA2CgAwIBAgIJAK+ii7kzrdqsMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEQMA4G +A1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3 +DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMCAXDTE0MDUyMzE3NTA1OVoYDzIxMTQw +NDI5MTc1MDU5WjCBrjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx +PTA7BgNVBAoTNFhNTCBTZWN1cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtz +ZXkuY29tL3htbHNlYykxEDAOBgNVBAsTB1Jvb3QgQ0ExFjAUBgNVBAMTDUFsZWtz +ZXkgU2FuaW4xITAfBgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtY4MCNj/qrOzVuex1BD/PuCYTDDOLLVj +tpKXQteQPqy0kgMwuQgRwdNnICIHQbnFKL40XoyACJVWKM7b0LkvWJNeyVzXPqEE +9ZPmNxWGUjVcr7powT7v8V7S2QflUnr8ZvR4XWwkZJ9EYKNhenijgJ5yYDrXCWdv +C+fnjBjv2LcCAwEAAaOCARcwggETMB0GA1UdDgQWBBQGtaSsp6p1ROoVnE/fBYNP +ah7+CzCB4wYDVR0jBIHbMIHYgBQGtaSsp6p1ROoVnE/fBYNPah7+C6GBtKSBsTCB +rjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhN +TCBTZWN1cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNl +YykxEDAOBgNVBAsTB1Jvb3QgQ0ExFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf +BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbYIJAK+ii7kzrdqsMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEARpb86RP/ck55X+NunXeIX81i763b +j7Z1VJwFbA/QfupzxnqJ2IP/lxC8YxJ3Bp2IJMI7rC9r0poa41ZxI5rGHip97Dpg +sxPF9lkRUmKBBQjkICOq1w/4d2DRInBoqXttD+0WsqDfNDVK+7kSE07ytn3RzHCj +j0gv0PdxmuCsR/E= +-----END CERTIFICATE----- + diff --git a/resources/certs/cert3 b/resources/certs/cert3 new file mode 100644 index 0000000..629f29a --- /dev/null +++ b/resources/certs/cert3 @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga +-----END CERTIFICATE----- + diff --git a/xmldsig.go b/xmldsig.go index f48be47..1ce91bc 100644 --- a/xmldsig.go +++ b/xmldsig.go @@ -5,12 +5,36 @@ import ( "unsafe" ) -// #include -// #include -// #include -// #include -// #include -// #include +/* +#include +#include +#include +#include +#include +#include +#include +#include + +void +xmlSecFindNodes(const xmlListPtr found, const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + + xmlNodePtr cur; + xmlNodePtr ret; + + xmlSecAssert2(name != NULL, NULL); + + cur = parent; + while(cur != NULL) { + if(cur->children != NULL) { + xmlSecFindNodes(found, cur->children, name, ns); + } + if((cur->type == XML_ELEMENT_NODE) && xmlSecCheckNodeName(cur, name, ns)) { + xmlListPushFront(found, cur); + } + cur = cur->next; + } +} +*/ import "C" // SignatureOptions represents additional, less commonly used, options for Sign and @@ -42,22 +66,6 @@ func Sign(key []byte, doc []byte, opts SignatureOptions) ([]byte, error) { startProcessingXML() defer stopProcessingXML() - ctx := C.xmlSecDSigCtxCreate(nil) - if ctx == nil { - return nil, errors.New("failed to create signature context") - } - defer C.xmlSecDSigCtxDestroy(ctx) - - // #nosec - ctx.signKey = C.xmlSecCryptoAppKeyLoadMemory( - (*C.xmlSecByte)(unsafe.Pointer(&key[0])), - C.xmlSecSize(len(key)), - C.xmlSecKeyDataFormatPem, - nil, nil, nil) - if ctx.signKey == nil { - return nil, errors.New("failed to load pem key") - } - parsedDoc, err := newDoc(doc, opts.XMLID) if err != nil { return nil, err @@ -65,15 +73,51 @@ func Sign(key []byte, doc []byte, opts SignatureOptions) ([]byte, error) { defer closeDoc(parsedDoc) // #nosec - node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), + found := C.xmlListCreate(nil, nil) + defer func() { C.xmlListDelete(found) }() + + C.xmlSecFindNodes( + found, + C.xmlDocGetRootElement(parsedDoc), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) - if node == nil { + + c := C.xmlListSize(found) + if c == 0 { return nil, errors.New("cannot find start node") } - if rv := C.xmlSecDSigCtxSign(ctx, node); rv < 0 { - return nil, errors.New("failed to sign") + for C.xmlListEmpty(found) == 0 { + link := C.xmlListFront(found) + if link == nil { + return nil, errors.New("Link is null") + } + + node := (C.xmlNodePtr)(C.xmlLinkGetData(link)) + if node != nil { + + ctx := C.xmlSecDSigCtxCreate(nil) + if ctx == nil { + return nil, errors.New("failed to create signature context") + } + defer C.xmlSecDSigCtxDestroy(ctx) + + // #nosec + ctx.signKey = C.xmlSecCryptoAppKeyLoadMemory( + (*C.xmlSecByte)(unsafe.Pointer(&key[0])), + C.xmlSecSize(len(key)), + C.xmlSecKeyDataFormatPem, + nil, nil, nil) + + if ctx.signKey == nil { + return nil, errors.New("failed to load pem key") + } + + if rv := C.xmlSecDSigCtxSign(ctx, node); rv < 0 { + return nil, errors.New("failed to sign") + } + } + C.xmlListPopFront(found) } return dumpDoc(parsedDoc), nil @@ -131,12 +175,6 @@ func Verify(publicKey []byte, doc []byte, opts SignatureOptions) error { return mustPopError() } - dsigCtx := C.xmlSecDSigCtxCreate(keysMngr) - if dsigCtx == nil { - return mustPopError() - } - defer C.xmlSecDSigCtxDestroy(dsigCtx) - parsedDoc, err := newDoc(doc, opts.XMLID) if err != nil { return err @@ -144,19 +182,41 @@ func Verify(publicKey []byte, doc []byte, opts SignatureOptions) error { defer closeDoc(parsedDoc) // #nosec - node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), + found := C.xmlListCreate(nil, nil) + defer func() { C.xmlListDelete(found) }() + + C.xmlSecFindNodes( + found, + C.xmlDocGetRootElement(parsedDoc), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) - if node == nil { + + c := C.xmlListSize(found) + if c == 0 { return errors.New("cannot find start node") } - if rv := C.xmlSecDSigCtxVerify(dsigCtx, node); rv < 0 { - return ErrVerificationFailed - } + for C.xmlListEmpty(found) == 0 { + link := C.xmlListFront(found) + if link == nil { + break + } + node := (C.xmlNodePtr)(C.xmlLinkGetData(link)) + if node != nil { + ctx := C.xmlSecDSigCtxCreate(keysMngr) + if ctx == nil { + return mustPopError() + } + defer C.xmlSecDSigCtxDestroy(ctx) - if dsigCtx.status != xmlSecDSigStatusSucceeded { - return ErrVerificationFailed + if rv := C.xmlSecDSigCtxVerify(ctx, node); rv < 0 { + return ErrVerificationFailed + } + if ctx.status != xmlSecDSigStatusSucceeded { + return ErrVerificationFailed + } + } + C.xmlListPopFront(found) } return nil } diff --git a/xmldsig_test.go b/xmldsig_test.go index 7ac74b2..6bf7e5d 100644 --- a/xmldsig_test.go +++ b/xmldsig_test.go @@ -2,9 +2,8 @@ package xmlsec import ( "encoding/xml" - "strings" - . "gopkg.in/check.v1" + "strings" ) type Envelope struct { @@ -163,6 +162,207 @@ fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga c.Assert(err, IsNil) } +func (testSuite *XMLDSigTest) TestSignAndVerifyMultiple(c *C) { + expectedSignedString := ` + + + Hello, World! + + + + + + + + + + ixa7UpgiS2UJ37IG9HzhfK7z+Fo= + + + xaMgajZ9tBswZmIP5JoBwXMpD9W74fVbfWJ/HkfTHYkXNejOXT+UocvaGaVCqPNE ++6rzavcVq18agibmYCkm6w== + + + MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga + + + + + Hello, World! + + + + + + + + + + 6hs7C+iZA45BBGAcaI0aNnMz+Ts= + + + F23IldNw0Gozri5ySU5Esopz7llkBrDJNHNgm+Ww93mrU5w1IrP0J7Cv0Xn19ro2 +QsO3oBVrpdMotMsFkbEVkA== + + + MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga + + + + + + +` + actualUnsignedString := ` + + + Hello, World! + + + + + + + + + + + + + + + + MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga + + + + + Hello, World! + + + + + + + + + + + + + + + + MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga + + + + + + +` + opts := SignatureOptions{XMLID: []XMLIDOption{ + {ElementName: "Data1", AttributeName: "ID"}, + {ElementName: "Data2", AttributeName: "ID"}, + }} + + actualSignedString, err := Sign(testSuite.Key, []byte(actualUnsignedString), opts) + c.Assert(err, IsNil) + c.Assert(string(actualSignedString), Equals, expectedSignedString) + + err = Verify(testSuite.Cert, actualSignedString, opts) + c.Assert(err, IsNil) + + data1Sig := `xaMgajZ9tBswZmIP5JoBwXMpD9W74fVbfWJ/HkfTHYkXNejOXT+UocvaGaVCqPNE ++6rzavcVq18agibmYCkm6w==` + data2Sig := `F23IldNw0Gozri5ySU5Esopz7llkBrDJNHNgm+Ww93mrU5w1IrP0J7Cv0Xn19ro2 +QsO3oBVrpdMotMsFkbEVkA==` + + breakData1 := strings.Replace(expectedSignedString, data1Sig, data2Sig, 1) + err = Verify(testSuite.Cert, []byte(breakData1), opts) + c.Assert(err, ErrorMatches, "signature verification failed") + + breakData2 := strings.Replace(expectedSignedString, data2Sig, data1Sig, 1) + err = Verify(testSuite.Cert, []byte(breakData2), opts) + c.Assert(err, ErrorMatches, "signature verification failed") +} + func (testSuite *XMLDSigTest) TestConstructFromSignature(c *C) { // Try again but this time construct the message from a struct having a Signature member doc := Envelope{Data: "Hello, World!"}