diff --git a/.travis.yml b/.travis.yml
index fa7d80e..dac5ac9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,6 @@ addons:
- libxmlsec1-dev
go:
- - 1.6
- 1.7
- tip
diff --git a/Makefile b/Makefile
index 862202a..373ccaf 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
@@ -146,25 +145,25 @@ qa: fmtcheck test vet lint coverage cyclo ineffassign misspell astscan
# Get the dependencies
deps:
- GOPATH=$(GOPATH) go get $(go list ./... | grep -v /vendor/)
- GOPATH=$(GOPATH) go get github.com/inconshreveable/mousetrap
- GOPATH=$(GOPATH) go get github.com/golang/lint/golint
- GOPATH=$(GOPATH) go get github.com/jstemmer/go-junit-report
- GOPATH=$(GOPATH) go get github.com/axw/gocov/gocov
- GOPATH=$(GOPATH) go get github.com/fzipp/gocyclo
- GOPATH=$(GOPATH) go get github.com/gordonklaus/ineffassign
- GOPATH=$(GOPATH) go get github.com/client9/misspell/cmd/misspell
- GOPATH=$(GOPATH) go get github.com/HewlettPackard/gas
- GOPATH=$(GOPATH) go get gopkg.in/check.v1
+ $(GOENV) go get $(go list ./... | grep -v /vendor/)
+ $(GOENV) go get github.com/inconshreveable/mousetrap
+ $(GOENV) go get github.com/golang/lint/golint
+ $(GOENV) go get github.com/jstemmer/go-junit-report
+ $(GOENV) go get github.com/axw/gocov/gocov
+ $(GOENV) go get github.com/fzipp/gocyclo
+ $(GOENV) go get github.com/gordonklaus/ineffassign
+ $(GOENV) go get github.com/client9/misspell/cmd/misspell
+ $(GOENV) go get github.com/HewlettPackard/gas/cmd/gas
+ $(GOENV) go get gopkg.in/check.v1
# 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!"}