Merge branch 'tecnickcom-master'

Update Package with some fixes
This commit is contained in:
2018-12-13 00:35:47 +01:00
23 changed files with 767 additions and 155 deletions

5
.gitignore vendored
View File

@@ -1,2 +1,3 @@
coverage.html
coverage.out
target
vendor
/Dockerfile

View File

@@ -1,5 +1,15 @@
language: go
sudo: false # silence warning
sudo: false
branches:
except:
- release
branches:
only:
- master
- develop
addons:
apt:
@@ -8,14 +18,26 @@ addons:
- libxmlsec1-dev
go:
- 1.6
- 1.7
- '1.11.1'
- tip
install:
- go get -t ./...
- go get github.com/golang/lint/golint
matrix:
allow_failures:
- go: tip
before_install:
- if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi;
- if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi;
- go get github.com/mattn/goveralls
before_script:
- make deps
script:
- golint *.go
- go vet ./...
- go test -v ./...
- make qa
after_failure:
- cat ./target/test/report.xml
after_success:
- if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi;

View File

@@ -2,13 +2,13 @@ FROM ubuntu
RUN apt-get update -yy && \
apt-get install -yy git make curl libxml2-dev libxmlsec1-dev liblzma-dev pkg-config
RUN curl -s https://storage.googleapis.com/golang/go1.7.linux-amd64.tar.gz | tar -C /usr/local -xzf -
RUN curl -s https://storage.googleapis.com/golang/go1.11.2.linux-amd64.tar.gz | tar -C /usr/local -xzf -
ENV GOPATH=/go
ENV PATH=$PATH:/usr/local/go/bin:/go/bin
RUN mkdir -p /go/bin
ADD . /go/src/github.com/crewjam/go-xmlsec
WORKDIR /go/src/github.com/crewjam/go-xmlsec
ADD . /go/src/git.deineagentur.com/DeineAgenturUG/go-xmlsec
WORKDIR /go/src/git.deineagentur.com/DeineAgenturUG/go-xmlsec
RUN go get github.com/crewjam/errset
RUN go build -o /bin/xmldsig ./examples/xmldsig.go

View File

@@ -1,8 +1,8 @@
FROM ubuntu:16.04
RUN apt-get update -yy && \
apt-get install -yy git make curl pkg-config
apt-get install -yy git make curl pkg-config
RUN curl -s https://storage.googleapis.com/golang/go1.7.linux-amd64.tar.gz | tar -C /usr/local -xzf -
RUN curl -s https://storage.googleapis.com/golang/go1.7.3.linux-amd64.tar.gz | tar -C /usr/local -xzf -
ENV GOPATH=/go
ENV PATH=$PATH:/usr/local/go/bin:/go/bin
RUN mkdir -p /go/bin
@@ -22,7 +22,7 @@ RUN curl -sL ftp://xmlsoft.org/libxml2/libxml2-2.9.4.tar.gz | tar -xzf - && \
--without-history \
--without-html \
--without-http \
--without-iconv \
--without-iconv \
--without-icu \
--without-iso8859x \
--without-legacy \
@@ -31,7 +31,7 @@ RUN curl -sL ftp://xmlsoft.org/libxml2/libxml2-2.9.4.tar.gz | tar -xzf - && \
--with-output \
--without-pattern \
--with-push \
--without-python \
--without-python \
--without-reader \
--without-readline \
--without-regexps \
@@ -53,8 +53,7 @@ RUN curl -sL ftp://xmlsoft.org/libxml2/libxml2-2.9.4.tar.gz | tar -xzf - && \
--without-coverage && \
make install
RUN \
curl -sL ftp://ftp.openssl.org/source/openssl-1.0.2j.tar.gz | tar -xzf - && \
RUN curl -sL ftp://ftp.openssl.org/source/openssl-1.0.2j.tar.gz | tar -xzf - && \
cd openssl-1.0.2j && \
./config \
no-shared \
@@ -70,28 +69,28 @@ RUN \
make depend install
RUN curl -sL http://www.aleksey.com/xmlsec/download/xmlsec1-1.2.22.tar.gz | tar -xzf - && \
cd xmlsec1-1.2.22 && \
./configure \
--enable-static \
--disable-shared \
--disable-crypto-dl \
--disable-apps-crypto-dl \
--enable-static-linking \
--without-gnu-ld \
--with-default-crypto=openssl \
--with-openssl=/usr/local/ssl \
--with-libxml=/usr/local \
--without-nss \
--without-nspr \
--without-gcrypt \
--without-gnutls \
--without-libxslt && \
make -C src install && \
make -C include install && \
make install-pkgconfigDATA
cd xmlsec1-1.2.22 && \
./configure \
--enable-static \
--disable-shared \
--disable-crypto-dl \
--disable-apps-crypto-dl \
--enable-static-linking \
--without-gnu-ld \
--with-default-crypto=openssl \
--with-openssl=/usr/local/ssl \
--with-libxml=/usr/local \
--without-nss \
--without-nspr \
--without-gcrypt \
--without-gnutls \
--without-libxslt && \
make -C src install && \
make -C include install && \
make install-pkgconfigDATA
ADD . /go/src/github.com/crewjam/go-xmlsec
WORKDIR /go/src/github.com/crewjam/go-xmlsec
ADD . /go/src/git.deineagentur.com/DeineAgenturUG/go-xmlsec
WORKDIR /go/src/git.deineagentur.com/DeineAgenturUG/go-xmlsec
RUN go get github.com/crewjam/errset
RUN go build -tags static -ldflags '-s -extldflags "-static"' -o /bin/xmldsig ./examples/xmldsig.go
RUN ldd /bin/xmldsig || true

177
Makefile Normal file
View File

@@ -0,0 +1,177 @@
# MAKEFILE
#
# @author Nicola Asuni <info@tecnick.com>
# @link https://git.deineagentur.com/DeineAgenturUG/go-xmlsec
# ------------------------------------------------------------------------------
# List special make targets that are not associated with files
.PHONY: help all test format fmtcheck vet lint coverage cyclo ineffassign misspell astscan qa deps clean nuke buildall dbuild
# Use bash as shell (Note: Ubuntu now uses dash which doesn't support PIPESTATUS).
SHELL=/bin/bash
# CVS path (path to the parent dir containing the project)
CVSPATH=git.deineagentur.com/DeineAgenturUG/go-xmlsec
# Project vendor
VENDOR=miracl
# Project name
PROJECT=go-xmlsec
# Project version
VERSION=$(shell cat VERSION)
# Project release number (packaging build number)
RELEASE=$(shell cat RELEASE)
# Current directory
CURRENTDIR=$(shell pwd)
# GO lang path
ifneq ($(GOPATH),)
ifeq ($(findstring $(GOPATH),$(CURRENTDIR)),)
# the defined GOPATH is not valid
GOPATH=
endif
endif
ifeq ($(GOPATH),)
# extract the GOPATH
GOPATH=$(firstword $(subst /src/, ,$(CURRENTDIR)))
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
help:
@echo ""
@echo "$(PROJECT) Makefile."
@echo "GOPATH=$(GOPATH)"
@echo "The following commands are available:"
@echo ""
@echo " make qa : Run all the tests and static analysis reports"
@echo " make test : Run the unit tests"
@echo ""
@echo " make format : Format the source code"
@echo " make fmtcheck : Check if the source code has been formatted"
@echo " make vet : Check for suspicious constructs"
@echo " make lint : Check for style errors"
@echo " make coverage : Generate the coverage report"
@echo " make cyclo : Generate the cyclomatic complexity report"
@echo " make ineffassign : Detect ineffectual assignments"
@echo " make misspell : Detect commonly misspelled words in source files"
@echo " make astscan : GO AST scanner"
@echo ""
@echo " make docs : Generate source code documentation"
@echo ""
@echo " make deps : Get the dependencies"
@echo " make clean : Remove any build artifact"
@echo " make nuke : Deletes any intermediate file"
@echo ""
@echo " make buildall : Full build and test sequence"
@echo " make dbuild : Build everything inside a Docker container"
@echo ""
# Alias for help target
all: help
# Run the unit tests
test:
@mkdir -p target/test
$(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
format:
@find . -type f -name "*.go" -exec gofmt -s -w {} \;
# Check if the source code has been formatted
fmtcheck:
@mkdir -p target
@find . -type f -name "*.go" -exec gofmt -s -d {} \; | tee target/format.diff
@test ! -s target/format.diff || { echo "ERROR: the source code has not been formatted - please use 'make format' or 'gofmt'"; exit 1; }
# Check for syntax errors
vet:
$(GOENV) go vet .
# Check for style errors
lint:
$(GOENV) golint .
# Generate the coverage report
coverage:
@mkdir -p target/report
$(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
$(GOENV) gocyclo -avg . | tee target/report/cyclo.txt ; test $${PIPESTATUS[0]} -eq 0
# Detect ineffectual assignments
ineffassign:
@mkdir -p target/report
$(GOENV) ineffassign . | tee target/report/ineffassign.txt ; test $${PIPESTATUS[0]} -eq 0
# Detect commonly misspelled words in source files
misspell:
@mkdir -p target/report
$(GOENV) misspell -error . | tee target/report/misspell.txt ; test $${PIPESTATUS[0]} -eq 0
# AST scanner
astscan:
@mkdir -p target/report
$(GOENV) gas ./*.go | tee target/report/astscan.txt ; test $${PIPESTATUS[0]} -eq 0 || true
# Generate source docs
docs:
@mkdir -p target/docs
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 '<html><head><meta http-equiv="refresh" content="0;./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html"/></head><a href="./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html">'${PKGNAME}' Documentation ...</a></html>' > target/docs/index.html
# Alias to run targets: fmtcheck test vet lint coverage
qa: fmtcheck test vet lint coverage cyclo ineffassign misspell astscan
# --- INSTALL ---
# 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 golang.org/x/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/securego/gosec/cmd/gosec/...
GOPATH=$(GOPATH) go get gopkg.in/check.v1
# Remove any build artifact
clean:
$(GOENV) go clean ./...
# Deletes any intermediate file
nuke:
rm -rf ./target
$(GOENV) go clean -i ./...
# Full build and test sequence
buildall: deps qa
# Build everything inside a Docker container
dbuild:
@mkdir -p target
@rm -rf target/*
@echo 0 > target/make.exit
CVSPATH=$(CVSPATH) VENDOR=$(VENDOR) PROJECT=$(PROJECT) MAKETARGET='$(MAKETARGET)' ./dockerbuild.sh
@exit `cat target/make.exit`

View File

@@ -1,21 +1,24 @@
# go-xmlsec
[![](https://godoc.org/github.com/crewjam/go-xmlsec?status.png)](http://godoc.org/github.com/crewjam/go-xmlsec) [![Build Status](https://travis-ci.org/crewjam/go-xmlsec.svg?branch=master)](https://travis-ci.org/crewjam/go-xmlsec)
[![Documentation](https://godoc.org/git.deineagentur.com/DeineAgenturUG/go-xmlsec?status.png)](http://godoc.org/git.deineagentur.com/DeineAgenturUG/go-xmlsec)
[![Master Build Status](https://secure.travis-ci.org/tecnickcom/go-xmlsec.png?branch=master)](https://travis-ci.org/tecnickcom/go-xmlsec?branch=master)
[![Master Coverage Status](https://coveralls.io/repos/tecnickcom/go-xmlsec/badge.svg?branch=master&service=github)](https://coveralls.io/github/tecnickcom/go-xmlsec?branch=master)
[![Go Report Card](https://goreportcard.com/badge/git.deineagentur.com/DeineAgenturUG/go-xmlsec)](https://goreportcard.com/report/git.deineagentur.com/DeineAgenturUG/go-xmlsec)
A partial wrapper for [xmlsec](https://www.aleksey.com/xmlsec).
A partial wrapper for [xmlsec](https://www.aleksey.com/xmlsec).
As seems to be the case for many things in the XMLish world, the xmldsig and xmlenc standards are more complex that may be nessesary. This library is as general as I could reasonably make it with an eye towards supporting the parts of the standards that are needed to support a SAML implementation. If there are missing bits you feel you need, please raise an issue or submit a pull request.
As seems to be the case for many things in the XMLish world, the xmldsig and xmlenc standards are more complex that may be nessesary. This library is as general as I could reasonably make it with an eye towards supporting the parts of the standards that are needed to support a SAML implementation. If there are missing bits you feel you need, please raise an issue or submit a pull request.
# Examples
## Examples
## Signing
### Signing
key, _ := ioutil.ReadFile("saml.key")
doc, _ := ioutil.ReadAll(os.Stdin)
signedDoc, err := Sign(key, doc, SignatureOptions{})
os.Stdout.Write(signedDoc)
## Verifying
### Verifying
key, _ := ioutil.ReadFile("saml.crt")
doc, _ := ioutil.ReadAll(os.Stdin)
@@ -24,59 +27,59 @@ As seems to be the case for many things in the XMLish world, the xmldsig and xml
os.Exit(1)
}
## Decrypting
### Decrypting
key, _ := ioutil.ReadFile("saml.key")
doc, _ := ioutil.ReadAll(os.Stdin)
plaintextDoc, err := Decrypt(key, doc)
os.Stdout.Write(plaintextDoc)
## Encrypting
### Encrypting
key, _ := ioutil.ReadFile("saml.crt")
doc, _ := ioutil.ReadAll(os.Stdin)
encryptedDoc, err := Encrypt(key, doc, EncryptOptions{})
os.Stdout.Write(encryptedDoc)
# Install
## Install
This package uses cgo to wrap libxmlsec. As such, you'll need libxmlsec headers and a C compiler to make it work. On linux, this might look like:
$ apt-get install libxml2-dev libxmlsec1-dev pkg-config
$ go get github.com/crewjam/go-xmlsec
$ go get git.deineagentur.com/DeineAgenturUG/go-xmlsec
On Mac with homebrew, this might look like:
$ brew install libxmlsec1 libxml2 pkg-config
$ go get github.com/crewjam/go-xmlsec
$ go get git.deineagentur.com/DeineAgenturUG/go-xmlsec
# Static Linking
## Static Linking
It may annoy you to grow a depenency on the shared libraries for libxmlsec, libxml2, etc. After some fighting, here is what I made work on Linux to get
a static binary. See also `Dockerfile.build-static` which build the example
program using this method.
## Compile libxml
### Compile libxml
```
```shell
curl -sL ftp://xmlsoft.org/libxml2/libxml2-2.9.4.tar.gz | tar -xzf -
cd /libxml2-2.9.4
./configure --enable-static --disable-shared --without-gnu-ld --with-c14n --without-catalog --without-debug --without-docbook --without-fexceptions --without-ftp --without-history --without-html --without-http --without-iconv --without-icu --without-iso8859x --without-legacy --without-mem-debug --without-minimum --with-output --without-pattern --with-push --without-python --without-reader --without-readline --without-regexps --without-run-debug --with-sax1 --without-schemas --without-schematron --without-threads --without-thread-alloc --with-tree --without-valid --without-writer --without-xinclude --without-xpath --with-xptr --without-modules --without-zlib --without-lzma --without-coverage
make install
```
## Compile openssl
### Compile openssl
```
```shell
curl -sL ftp://ftp.openssl.org/source/openssl-1.0.2h.tar.gz | tar -xzf -
cd openssl-1.0.2h
./config no-shared no-weak-ssl-ciphers no-ssl2 no-ssl3 no-comp no-idea no-dtls no-hw no-threads no-dso
make install
```
## Compile libxmlsec
### Compile libxmlsec
```
```shell
curl -sL http://www.aleksey.com/xmlsec/download/xmlsec1-1.2.22.tar.gz | tar -xzf -
./configure --enable-static --disable-shared --disable-crypto-dl --disable-apps-crypto-dl --enable-static-linking --without-gnu-ld --with-default-crypto=openssl --with-openssl=/usr/local/ssl --with-libxml=/usr/local --without-nss --without-nspr --without-gcrypt --without-gnutls --without-libxslt
make -C src install
@@ -84,12 +87,10 @@ make -C include install
make install-pkgconfigDATA
```
## Build with static tag
### Build with static tag
```
```shell
go build -tags static -ldflags '-s -extldflags "-static"' -o /bin/xmldsig-static.bin ./examples/xmldsig.go
```
Running `ldd` on the output should produce `not a dynamic executable`.
Running `ldd` on the output should produce `not a dynamic executable`.

View File

@@ -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 <xmlsec/xmlsec.h>
// #include <xmlsec/xmltree.h>
// #include <xmlsec/xmlenc.h>
// #include <xmlsec/templates.h>
// #include <xmlsec/crypto.h>
import "C"
// #cgo pkg-config: libxml-2.0
// #include <libxml/parser.h>
// #include <libxml/parserInternals.h>
// #include <libxml/xmlmemory.h>

View File

@@ -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 <xmlsec/xmlsec.h>
// #include <xmlsec/xmltree.h>
// #include <xmlsec/xmlenc.h>
// #include <xmlsec/templates.h>
// #include <xmlsec/crypto.h>
import "C"
// #cgo pkg-config: --static libxml-2.0
// #include <libxml/parser.h>
// #include <libxml/parserInternals.h>
// #include <libxml/xmlmemory.h>
import "C"

View File

@@ -33,6 +33,7 @@ func Decrypt(privateKey []byte, doc []byte) ([]byte, error) {
return nil, popError()
}
// #nosec
key := C.xmlSecCryptoAppKeyLoadMemory(
(*C.xmlSecByte)(unsafe.Pointer(&privateKey[0])),
C.xmlSecSize(len(privateKey)),
@@ -59,6 +60,7 @@ func Decrypt(privateKey []byte, doc []byte) ([]byte, error) {
}
defer C.xmlSecEncCtxDestroy(encCtx)
// #nosec
encDataNode := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc),
(*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeEncryptedData)),
(*C.xmlChar)(unsafe.Pointer(&C.xmlSecEncNs)))
@@ -70,7 +72,6 @@ func Decrypt(privateKey []byte, doc []byte) ([]byte, error) {
if rv := C.xmlSecEncCtxDecrypt(encCtx, encDataNode); rv < 0 {
return nil, popError()
}
encDataNode = nil // the template is inserted in the doc, so we don't own it
return dumpDoc(parsedDoc), nil
}

58
dockerbuild.sh Executable file
View File

@@ -0,0 +1,58 @@
#!/bin/sh
#
# dockerbuild.sh
#
# Build the software inside a Docker container
#
# @author Nicola Asuni <info@tecnick.com>
# ------------------------------------------------------------------------------
# NOTES:
# This script requires Docker
# EXAMPLE USAGE:
# VENDOR=vendorname PROJECT=projectname MAKETARGET=buildall ./dockerbuild.sh
# Get vendor and project name
: ${CVSPATH:=project}
: ${VENDOR:=vendor}
: ${PROJECT:=project}
# make target to execute
: ${MAKETARGET:=buildall}
# Name of the base development Docker image
DOCKERDEV=${VENDOR}/dev_${PROJECT}
# Build the base environment and keep it cached locally
docker build -t ${DOCKERDEV} ./resources/DockerDev/
# Define the project root path
PRJPATH=/root/src/${CVSPATH}/${PROJECT}
# Generate a temporary Dockerfile to build and test the project
# NOTE: The exit status of the RUN command is stored to be returned later,
# so in case of error we can continue without interrupting this script.
cat > Dockerfile <<- EOM
FROM ${DOCKERDEV}
RUN mkdir -p ${PRJPATH}
ADD ./ ${PRJPATH}
WORKDIR ${PRJPATH}
RUN make ${MAKETARGET} || (echo \$? > target/make.exit)
EOM
# Define the temporary Docker image name
DOCKER_IMAGE_NAME=${VENDOR}/build_${PROJECT}
# Build the Docker image
docker build --no-cache -t ${DOCKER_IMAGE_NAME} .
# Start a container using the newly created Docker image
CONTAINER_ID=$(docker run -d ${DOCKER_IMAGE_NAME})
# Copy all build/test artifacts back to the host
docker cp ${CONTAINER_ID}:"${PRJPATH}/target" ./
# Remove the temporary container and image
docker rm -f ${CONTAINER_ID} || true
docker rmi -f ${DOCKER_IMAGE_NAME} || true

View File

@@ -91,6 +91,7 @@ var errInvalidAlgorithm = errors.New("invalid algorithm")
// Note: the invocations of C.CString() here return a pointer to a string
// allocated from the C heap that would normally need to freed by calling
// C.free, but because these are global, we can just leak them.
// #nosec
var (
constDsigNamespace = (*C.xmlChar)(unsafe.Pointer(C.CString("http://www.w3.org/2000/09/xmldsig#")))
constDigestMethod = (*C.xmlChar)(unsafe.Pointer(C.CString("DigestMethod")))
@@ -117,6 +118,7 @@ func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) {
return nil, mustPopError()
}
// #nosec
key := C.xmlSecCryptoAppKeyLoadMemory(
(*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])),
C.xmlSecSize(len(publicKey)),
@@ -126,6 +128,7 @@ func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) {
return nil, mustPopError()
}
// #nosec
if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key,
(*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])),
C.xmlSecSize(len(publicKey)),
@@ -162,6 +165,7 @@ func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) {
// create encryption template to encrypt XML file and replace
// its content with encryption result
// #nosec
encDataNode := C.xmlSecTmplEncDataCreate(parsedDoc, sessionCipherTransform,
nil, (*C.xmlChar)(unsafe.Pointer(&C.xmlSecTypeEncElement)), nil, nil)
if encDataNode == nil {
@@ -279,5 +283,8 @@ func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) {
}
encDataNode = nil // the template is inserted in the doc, so we don't own it
return dumpDoc(parsedDoc), nil
rootNode := C.xmlDocGetRootElement(parsedDoc)
buf := dumpNode(rootNode)
return buf, nil
}

View File

@@ -49,8 +49,8 @@ func onXmlsecError(file *C.char, line C.int, funcName *C.char, errorObject *C.ch
globalErrors[threadID] = append(globalErrors[threadID], err)
}
//export onXmlError
func onXmlError(msg *C.char) {
//export onXMLError
func onXMLError(msg *C.char) {
threadID := getThreadID()
globalErrors[threadID] = append(globalErrors[threadID],
fmt.Errorf("%s", strings.TrimSuffix(C.GoString(msg), "\n")))

View File

@@ -8,7 +8,7 @@ package xmlsec
// #include <xmlsec/xmlsec.h>
// #include <xmlsec/errors.h>
//
// void onXmlError(const char *msg); // implemented in go
// void onXMLError(const char *msg); // implemented in go
// void onXmlsecError(const char *file, int line, const char *funcName, const char *errorObject, const char *errorSubject, int reason, const char *msg); // implemented in go
//
// static void onXmlGenericError_cgo(void *ctx, const char *format, ...) {
@@ -17,7 +17,7 @@ package xmlsec
// va_start(args, format);
// vsnprintf(buffer, 256, format, args);
// va_end (args);
// onXmlError(buffer);
// onXMLError(buffer);
// }
//
// static void onXmlsecError_cgo(const char *file, int line, const char *funcName, const char *errorObject, const char *errorSubject, int reason, const char *msg) {

View File

@@ -6,7 +6,7 @@ import (
"io/ioutil"
"os"
"github.com/gofly/go-xmlsec"
xmlsec "git.deineagentur.com/DeineAgenturUG/go-xmlsec"
)
func main() {
@@ -31,6 +31,10 @@ func main() {
}
buf, err := ioutil.ReadAll(os.Stdin)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}
if *doSign {
signedBuf, err := xmlsec.Sign(key, buf, xmlsec.SignatureOptions{})
@@ -38,7 +42,7 @@ func main() {
fmt.Printf("%s\n", err)
os.Exit(1)
}
os.Stdout.Write(signedBuf)
os.Stdout.Write(signedBuf) //#nosec
}
if *doVerify {

View File

@@ -0,0 +1,10 @@
# Dockerfile
#
# Linux development environment
#
# Extend the tecnickcom/alldev image defined in
# https://github.com/tecnickcom/alldev
# ------------------------------------------------------------------------------
FROM tecnickcom/alldev
MAINTAINER info@tecnick.com

24
resources/certs/cert1 Normal file
View File

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

25
resources/certs/cert2 Normal file
View File

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

23
resources/certs/cert3 Normal file
View File

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

View File

@@ -11,6 +11,21 @@ type Method struct {
Algorithm string `xml:",attr"`
}
// Reference data struct
type Reference struct {
URI string `xml:"URI,attr"`
ReferenceTransforms []Method `xml:"Transforms>Transform"`
DigestMethod Method `xml:"DigestMethod"`
DigestValue string `xml:"DigestValue"`
}
// SignedInfo struct
type SignedInfo struct {
CanonicalizationMethod Method `xml:"CanonicalizationMethod"`
SignatureMethod Method `xml:"SignatureMethod"`
Reference Reference `xml:"Reference"`
}
// Signature is a model for the Signature object specified by XMLDSIG. This is
// convenience object when constructing XML that you'd like to sign. For example:
//
@@ -24,17 +39,7 @@ type Method struct {
// buf, _ := xml.Marshal(f)
// buf, _ = Sign(key, buf)
//
type Reference struct {
URI string `xml:",attr"`
Transforms []Method `xml:"Transforms>Transform"`
DigestMethod Method
DigestValue string
}
type SignedInfo struct {
CanonicalizationMethod Method `xml:"CanonicalizationMethod"`
SignatureMethod Method `xml:"SignatureMethod"`
Reference Reference
}
type Signature struct {
XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Signature"`
SignedInfo SignedInfo
@@ -65,7 +70,7 @@ func DefaultSignature(pemEncodedPublicKey []byte) Signature {
},
Reference: Reference{
Transforms: []Method{
Method{Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"},
{Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"},
},
DigestMethod: Method{
Algorithm: "http://www.w3.org/2000/09/xmldsig#sha1",

View File

@@ -9,5 +9,6 @@ import "C"
func getThreadID() uintptr {
// Darwin lacks a meaningful version of gettid() so instead we use
// ptread_self() as a proxy.
// #nosec
return uintptr(unsafe.Pointer(C.pthread_self()))
}

View File

@@ -5,12 +5,36 @@ import (
"unsafe"
)
// #include <xmlsec/xmlsec.h>
// #include <xmlsec/xmltree.h>
// #include <xmlsec/xmlenc.h>
// #include <xmlsec/xmldsig.h>
// #include <xmlsec/errors.h>
// #include <xmlsec/crypto.h>
/*
#include <xmlsec/xmlsec.h>
#include <xmlsec/xmltree.h>
#include <xmlsec/xmlenc.h>
#include <xmlsec/xmldsig.h>
#include <xmlsec/errors.h>
#include <xmlsec/crypto.h>
#include <xmlsec/nodeset.h>
#include <libxml/list.h>
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,36 +66,58 @@ 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)
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
}
defer closeDoc(parsedDoc)
node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc),
// #nosec
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
@@ -106,6 +152,7 @@ func Verify(publicKey []byte, doc []byte, opts SignatureOptions) error {
return mustPopError()
}
// #nosec
key := C.xmlSecCryptoAppKeyLoadMemory(
(*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])),
C.xmlSecSize(len(publicKey)),
@@ -115,6 +162,7 @@ func Verify(publicKey []byte, doc []byte, opts SignatureOptions) error {
return mustPopError()
}
// #nosec
if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key,
(*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])),
C.xmlSecSize(len(publicKey)),
@@ -127,31 +175,48 @@ 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
}
defer closeDoc(parsedDoc)
node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc),
// #nosec
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
}

View File

@@ -2,9 +2,8 @@ package xmlsec
import (
"encoding/xml"
"strings"
. "gopkg.in/check.v1"
"strings"
)
type Envelope struct {
@@ -163,6 +162,207 @@ fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga</X509Certificate>
c.Assert(err, IsNil)
}
func (testSuite *XMLDSigTest) TestSignAndVerifyMultiple(c *C) {
expectedSignedString := `<?xml version="1.0"?>
<Envelope xmlns="urn:envelope">
<Data1 ID="id1">
Hello, World!
<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="#id1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>ixa7UpgiS2UJ37IG9HzhfK7z+Fo=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>xaMgajZ9tBswZmIP5JoBwXMpD9W74fVbfWJ/HkfTHYkXNejOXT+UocvaGaVCqPNE
+6rzavcVq18agibmYCkm6w==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<Data2 ID="id2">
Hello, World!
<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="#id2">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>6hs7C+iZA45BBGAcaI0aNnMz+Ts=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>F23IldNw0Gozri5ySU5Esopz7llkBrDJNHNgm+Ww93mrU5w1IrP0J7Cv0Xn19ro2
QsO3oBVrpdMotMsFkbEVkA==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</Data2>
</Data1>
</Envelope>
`
actualUnsignedString := `
<Envelope xmlns="urn:envelope">
<Data1 ID="id1">
Hello, World!
<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="#id1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue/>
</Reference>
</SignedInfo>
<SignatureValue/>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<Data2 ID="id2">
Hello, World!
<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="#id2">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue/>
</Reference>
</SignedInfo>
<SignatureValue/>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</Data2>
</Data1>
</Envelope>
`
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 := `<SignatureValue>xaMgajZ9tBswZmIP5JoBwXMpD9W74fVbfWJ/HkfTHYkXNejOXT+UocvaGaVCqPNE
+6rzavcVq18agibmYCkm6w==</SignatureValue>`
data2Sig := `<SignatureValue>F23IldNw0Gozri5ySU5Esopz7llkBrDJNHNgm+Ww93mrU5w1IrP0J7Cv0Xn19ro2
QsO3oBVrpdMotMsFkbEVkA==</SignatureValue>`
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!"}
@@ -179,7 +379,7 @@ func (testSuite *XMLDSigTest) TestConstructFromSignature(c *C) {
<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>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
@@ -187,8 +387,8 @@ func (testSuite *XMLDSigTest) TestConstructFromSignature(c *C) {
<DigestValue>sEenIPkW9ssFSB9t4UU6VUrytqc=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>chSWfpQBIQraySsUHzs5N51+ruelu2HMHh5Mnd3EjcLqFBVD0f23kmXUp7zVhCVD
vCfqu9yXDYKVOBI57F0Efg==</SignatureValue>
<SignatureValue>xGbrj3FkyalDesH7R8xS41i5w69sM9WvuFmPeJ/LQ1zIjHoeHBq4SRzTOPg9xgjj
YYGrWwpJY9khPQsfwjwWTQ==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAnBgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQDEw1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7LjqdnsYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQABo4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTMQygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGuMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZIhvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJfBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga</X509Certificate>
@@ -197,6 +397,7 @@ vCfqu9yXDYKVOBI57F0Efg==</SignatureValue>
</Signature>
</Envelope>
`
c.Assert(string(actualSignedString), Equals, expectedSignedString)
err = Verify(testSuite.Cert, actualSignedString, SignatureOptions{})

View File

@@ -42,6 +42,7 @@ func init() {
}
func newDoc(buf []byte, idattrs []XMLIDOption) (*C.xmlDoc, error) {
// #nosec
ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])),
C.int(len(buf)))
if ctx == nil {
@@ -78,15 +79,18 @@ func addIDAttr(node *C.xmlNode, attrName, nodeName, nsHref string) {
cur = C.xmlSecGetNextElementNode(cur.next)
}
// #nosec
if C.GoString((*C.char)(unsafe.Pointer(node.name))) != nodeName {
return
}
// #nosec
if nsHref != "" && node.ns != nil && C.GoString((*C.char)(unsafe.Pointer(node.ns.href))) != nsHref {
return
}
// the attribute with name equal to attrName should exist
for attr := node.properties; attr != nil; attr = attr.next {
// #nosec
if C.GoString((*C.char)(unsafe.Pointer(attr.name))) == attrName {
id := C.xmlNodeListGetString(node.doc, attr.children, 1)
if id == nil {
@@ -106,7 +110,15 @@ func dumpDoc(doc *C.xmlDoc) []byte {
var buffer *C.xmlChar
var bufferSize C.int
C.xmlDocDumpMemory(doc, &buffer, &bufferSize)
defer C.MY_xmlFree(unsafe.Pointer(buffer))
defer C.MY_xmlFree(unsafe.Pointer(buffer)) // #nosec
return C.GoBytes(unsafe.Pointer(buffer), bufferSize)
return C.GoBytes(unsafe.Pointer(buffer), bufferSize) // #nosec
}
func dumpNode(node *C.xmlNode) []byte {
buffer := C.xmlBufferCreate()
defer C.xmlBufferFree(buffer)
bufferSize := C.xmlNodeDump(buffer, nil, node, 0, 0)
return C.GoBytes(unsafe.Pointer(buffer.content), bufferSize) // #nosec
}