├── .gitignore ├── setup_test.go ├── thread_linux.go ├── xmlenc ├── setup_test.go ├── xmlenc.go └── decrypt.go ├── .travis.yml ├── thread_darwin.go ├── cgo_dl.go ├── cgo_static.go ├── error_thunk.go ├── examples └── xmldsig.go ├── LICENSE ├── Dockerfile.build ├── decrypt.go ├── signature.go ├── error.go ├── Dockerfile.build-static ├── xmlsec.go ├── README.md ├── xmldsig.go ├── encrypt.go ├── xmldsig_test.go ├── encrypt_test.go └── encrypt_realworld_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.html 2 | coverage.out -------------------------------------------------------------------------------- /setup_test.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "testing" 5 | 6 | . "gopkg.in/check.v1" 7 | ) 8 | 9 | // Hook up gocheck into the "go test" runner. 10 | func Test(t *testing.T) { TestingT(t) } 11 | -------------------------------------------------------------------------------- /thread_linux.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import "syscall" 4 | 5 | // getThreadID returns an opaque value that is unique per OS thread 6 | func getThreadID() uintptr { 7 | return uintptr(syscall.Gettid()) 8 | } 9 | -------------------------------------------------------------------------------- /xmlenc/setup_test.go: -------------------------------------------------------------------------------- 1 | package xmlenc 2 | 3 | import ( 4 | "testing" 5 | 6 | . "gopkg.in/check.v1" 7 | ) 8 | 9 | // Hook up gocheck into the "go test" runner. 10 | func Test(t *testing.T) { TestingT(t) } 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false # silence warning 3 | 4 | addons: 5 | apt: 6 | packages: 7 | - libxml2-dev 8 | - libxmlsec1-dev 9 | 10 | go: 11 | - 1.6 12 | - 1.7 13 | 14 | install: 15 | - go get -t ./... 16 | - go get github.com/golang/lint/golint 17 | 18 | script: 19 | - golint *.go 20 | - go vet ./... 21 | - go test -v ./... 22 | -------------------------------------------------------------------------------- /thread_darwin.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import "unsafe" 4 | 5 | // #include 6 | import "C" 7 | 8 | // getThreadID returns an opaque value that is unique per OS thread. 9 | func getThreadID() uintptr { 10 | // Darwin lacks a meaningful version of gettid() so instead we use 11 | // ptread_self() as a proxy. 12 | return uintptr(unsafe.Pointer(C.pthread_self())) 13 | } 14 | -------------------------------------------------------------------------------- /cgo_dl.go: -------------------------------------------------------------------------------- 1 | // +build !static 2 | 3 | package xmlsec 4 | 5 | // #cgo linux CFLAGS: -w 6 | // #cgo darwin CFLAGS: -Wno-invalid-pp-token -Wno-header-guard 7 | // #cgo pkg-config: xmlsec1 8 | // #include 9 | // #include 10 | // #include 11 | // #include 12 | // #include 13 | import "C" 14 | 15 | // #cgo pkg-config: libxml-2.0 16 | // #include 17 | // #include 18 | // #include 19 | import "C" 20 | -------------------------------------------------------------------------------- /cgo_static.go: -------------------------------------------------------------------------------- 1 | // +build static 2 | 3 | package xmlsec 4 | 5 | // #cgo linux CFLAGS: -w 6 | // #cgo darwin CFLAGS: -Wno-invalid-pp-token -Wno-header-guard 7 | // #cgo pkg-config: --static xmlsec1 8 | // #include 9 | // #include 10 | // #include 11 | // #include 12 | // #include 13 | import "C" 14 | 15 | // #cgo pkg-config: --static libxml-2.0 16 | // #include 17 | // #include 18 | // #include 19 | import "C" 20 | -------------------------------------------------------------------------------- /error_thunk.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | // #include 4 | // #include 5 | // #include 6 | // #include 7 | // #include 8 | // #include 9 | // #include 10 | // 11 | // void onXmlError(const char *msg); // implemented in go 12 | // void onXmlsecError(const char *file, int line, const char *funcName, const char *errorObject, const char *errorSubject, int reason, const char *msg); // implemented in go 13 | // 14 | // static void onXmlGenericError_cgo(void *ctx, const char *format, ...) { 15 | // char buffer[256]; 16 | // va_list args; 17 | // va_start(args, format); 18 | // vsnprintf(buffer, 256, format, args); 19 | // va_end (args); 20 | // onXmlError(buffer); 21 | // } 22 | // 23 | // static void onXmlsecError_cgo(const char *file, int line, const char *funcName, const char *errorObject, const char *errorSubject, int reason, const char *msg) { 24 | // onXmlsecError(file, line, funcName, errorObject, errorSubject, reason, msg); 25 | // } 26 | // 27 | // void captureXmlErrors() { 28 | // xmlSecErrorsSetCallback(onXmlsecError_cgo); 29 | // xmlSetGenericErrorFunc(NULL, onXmlGenericError_cgo); 30 | // } 31 | import "C" 32 | -------------------------------------------------------------------------------- /examples/xmldsig.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | 9 | "github.com/crewjam/go-xmlsec" 10 | ) 11 | 12 | func main() { 13 | doVerify := flag.Bool("v", false, "verify the document") 14 | doSign := flag.Bool("s", false, "sign the document") 15 | keyPath := flag.String("k", "", "the path to the key") 16 | flag.Parse() 17 | 18 | if !*doVerify && !*doSign { 19 | fmt.Println("you must specify -v to verify or -s to sign") 20 | os.Exit(1) 21 | } 22 | if *keyPath == "" { 23 | fmt.Println("you must specify a key file") 24 | os.Exit(1) 25 | } 26 | 27 | key, err := ioutil.ReadFile(*keyPath) 28 | if err != nil { 29 | fmt.Printf("%s\n", err) 30 | os.Exit(1) 31 | } 32 | 33 | buf, err := ioutil.ReadAll(os.Stdin) 34 | 35 | if *doSign { 36 | signedBuf, err := xmlsec.Sign(key, buf, xmlsec.SignatureOptions{}) 37 | if err != nil { 38 | fmt.Printf("%s\n", err) 39 | os.Exit(1) 40 | } 41 | os.Stdout.Write(signedBuf) 42 | } 43 | 44 | if *doVerify { 45 | err := xmlsec.Verify(key, buf, xmlsec.SignatureOptions{}) 46 | if err == xmlsec.ErrVerificationFailed { 47 | fmt.Println("signature is not correct") 48 | os.Exit(1) 49 | } 50 | if err != nil { 51 | fmt.Printf("error: %s\n", err) 52 | os.Exit(1) 53 | } 54 | fmt.Println("signature is correct") 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Ross Kinder 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Dockerfile.build: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | RUN apt-get update -yy && \ 3 | apt-get install -yy git make curl libxml2-dev libxmlsec1-dev liblzma-dev pkg-config 4 | 5 | RUN curl -s https://storage.googleapis.com/golang/go1.7.linux-amd64.tar.gz | tar -C /usr/local -xzf - 6 | ENV GOPATH=/go 7 | ENV PATH=$PATH:/usr/local/go/bin:/go/bin 8 | RUN mkdir -p /go/bin 9 | 10 | ADD . /go/src/github.com/crewjam/go-xmlsec 11 | WORKDIR /go/src/github.com/crewjam/go-xmlsec 12 | RUN go get github.com/crewjam/errset 13 | RUN go build -o /bin/xmldsig ./examples/xmldsig.go 14 | 15 | # Check our dynamic library dependencies. This will produce output like: 16 | # 17 | # linux-vdso.so.1 => (0x00007ffffa1d3000) 18 | # libxmlsec1-openssl.so.1 => /usr/lib/libxmlsec1-openssl.so.1 (0x00007f506b9dc000) 19 | # libxmlsec1.so.1 => /usr/lib/libxmlsec1.so.1 (0x00007f506b77e000) 20 | # libxml2.so.2 => /usr/lib/x86_64-linux-gnu/libxml2.so.2 (0x00007f506b3c3000) 21 | # libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f506b1a6000) 22 | # libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f506addd000) 23 | # libcrypto.so.1.0.0 => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007f506a981000) 24 | # libxslt.so.1 => /usr/lib/x86_64-linux-gnu/libxslt.so.1 (0x00007f506a744000) 25 | # libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f506a540000) 26 | # libicuuc.so.55 => /usr/lib/x86_64-linux-gnu/libicuuc.so.55 (0x00007f506a1ab000) 27 | # libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f5069f91000) 28 | # liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f5069d6f000) 29 | # libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5069a65000) 30 | # /lib64/ld-linux-x86-64.so.2 (0x000055cfaf030000) 31 | # libicudata.so.55 => /usr/lib/x86_64-linux-gnu/libicudata.so.55 (0x00007f5067fae000) 32 | # libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f5067c2b000) 33 | # libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5067a15000) 34 | RUN ldd /bin/xmldsig || true 35 | 36 | RUN /bin/xmldsig --help || true 37 | -------------------------------------------------------------------------------- /decrypt.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | // #include 9 | // #include 10 | // #include 11 | // #include 12 | // #include 13 | import "C" 14 | 15 | // #include 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | // Decrypt finds the first encrypted part of doc, decrypts it using 21 | // privateKey and returns the plaintext of the embedded document. 22 | func Decrypt(privateKey []byte, doc []byte) ([]byte, error) { 23 | startProcessingXML() 24 | defer stopProcessingXML() 25 | 26 | keysMngr := C.xmlSecKeysMngrCreate() 27 | if keysMngr == nil { 28 | return nil, popError() 29 | } 30 | defer C.xmlSecKeysMngrDestroy(keysMngr) 31 | 32 | if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { 33 | return nil, popError() 34 | } 35 | 36 | key := C.xmlSecCryptoAppKeyLoadMemory( 37 | (*C.xmlSecByte)(unsafe.Pointer(&privateKey[0])), 38 | C.xmlSecSize(len(privateKey)), 39 | C.xmlSecKeyDataFormatPem, 40 | nil, nil, nil) 41 | if key == nil { 42 | return nil, popError() 43 | } 44 | 45 | if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 { 46 | return nil, popError() 47 | } 48 | 49 | parsedDoc, err := newDoc(doc, nil) 50 | if err != nil { 51 | return nil, err 52 | } 53 | defer closeDoc(parsedDoc) 54 | 55 | // create encryption context 56 | encCtx := C.xmlSecEncCtxCreate(keysMngr) 57 | if encCtx == nil { 58 | return nil, popError() 59 | } 60 | defer C.xmlSecEncCtxDestroy(encCtx) 61 | 62 | encDataNode := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), 63 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeEncryptedData)), 64 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecEncNs))) 65 | if encDataNode == nil { 66 | return nil, fmt.Errorf("xmlSecFindNode cannot find EncryptedData node") 67 | } 68 | 69 | // decrypt the data 70 | if rv := C.xmlSecEncCtxDecrypt(encCtx, encDataNode); rv < 0 { 71 | return nil, popError() 72 | } 73 | encDataNode = nil // the template is inserted in the doc, so we don't own it 74 | 75 | return dumpDoc(parsedDoc), nil 76 | } 77 | -------------------------------------------------------------------------------- /signature.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/pem" 6 | "encoding/xml" 7 | ) 8 | 9 | // Method is part of Signature. 10 | type Method struct { 11 | Algorithm string `xml:",attr"` 12 | } 13 | 14 | // Signature is a model for the Signature object specified by XMLDSIG. This is 15 | // convenience object when constructing XML that you'd like to sign. For example: 16 | // 17 | // type Foo struct { 18 | // Stuff string 19 | // Signature Signature 20 | // } 21 | // 22 | // f := Foo{Suff: "hello"} 23 | // f.Signature = DefaultSignature() 24 | // buf, _ := xml.Marshal(f) 25 | // buf, _ = Sign(key, buf) 26 | // 27 | type Signature struct { 28 | XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Signature"` 29 | 30 | CanonicalizationMethod Method `xml:"SignedInfo>CanonicalizationMethod"` 31 | SignatureMethod Method `xml:"SignedInfo>SignatureMethod"` 32 | ReferenceTransforms []Method `xml:"SignedInfo>Reference>Transforms>Transform"` 33 | DigestMethod Method `xml:"SignedInfo>Reference>DigestMethod"` 34 | DigestValue string `xml:"SignedInfo>Reference>DigestValue"` 35 | SignatureValue string `xml:"SignatureValue"` 36 | KeyName string `xml:"KeyInfo>KeyName,omitempty"` 37 | X509Certificate *SignatureX509Data `xml:"KeyInfo>X509Data,omitempty"` 38 | } 39 | 40 | // SignatureX509Data represents the element of 41 | type SignatureX509Data struct { 42 | X509Certificate string `xml:"X509Certificate,omitempty"` 43 | } 44 | 45 | // DefaultSignature returns a Signature struct that uses the default c14n and SHA1 settings. 46 | func DefaultSignature(pemEncodedPublicKey []byte) Signature { 47 | // xmlsec wants the key to be base64-encoded but *not* wrapped with the 48 | // PEM flags 49 | pemBlock, _ := pem.Decode(pemEncodedPublicKey) 50 | certStr := base64.StdEncoding.EncodeToString(pemBlock.Bytes) 51 | 52 | return Signature{ 53 | CanonicalizationMethod: Method{ 54 | Algorithm: "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", 55 | }, 56 | SignatureMethod: Method{ 57 | Algorithm: "http://www.w3.org/2000/09/xmldsig#rsa-sha1", 58 | }, 59 | ReferenceTransforms: []Method{ 60 | Method{Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"}, 61 | }, 62 | DigestMethod: Method{ 63 | Algorithm: "http://www.w3.org/2000/09/xmldsig#sha1", 64 | }, 65 | X509Certificate: &SignatureX509Data{ 66 | X509Certificate: certStr, 67 | }, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /xmlenc/xmlenc.go: -------------------------------------------------------------------------------- 1 | // Package xmlenc implements xml encrytion natively 2 | // (https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html) 3 | package xmlenc 4 | 5 | import "encoding/xml" 6 | 7 | type EncryptedData struct { 8 | XMLName xml.Name `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedData"` 9 | ID *string `xml:"Id,attr"` 10 | Type *string `xml:",attr"` 11 | EncryptionMethod *EncryptionMethod `xml:"http://www.w3.org/2001/04/xmlenc# EncryptionMethod"` 12 | KeyInfo *KeyInfo `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` 13 | CipherData *CipherData `xml:"http://www.w3.org/2001/04/xmlenc# CipherData"` 14 | } 15 | 16 | type EncryptionMethod struct { 17 | XMLName xml.Name `xml:"http://www.w3.org/2001/04/xmlenc# EncryptionMethod"` 18 | Algorithm *string `xml:",attr"` 19 | OAEPparams *OAEPparams `xml:"http://www.w3.org/2001/04/xmlenc# OAEPparams"` 20 | DigestMethod *DigestMethod `xml:"http://www.w3.org/2000/09/xmldsig# DigestMethod"` 21 | } 22 | 23 | type DigestMethod struct { 24 | XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# DigestMethod"` 25 | Algorithm string `xml:",attr"` 26 | } 27 | 28 | type OAEPparams struct { 29 | XMLName xml.Name `xml:"http://www.w3.org/2001/04/xmlenc# OAEPparams"` 30 | Data []byte `xml:",chardata"` 31 | } 32 | 33 | type KeyInfo struct { 34 | XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` 35 | EncryptedKey *EncryptedKey `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedKey"` 36 | X509Data *X509Data `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"` 37 | } 38 | 39 | type EncryptedKey struct { 40 | XMLName xml.Name `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedKey"` 41 | EncryptionMethod *EncryptionMethod `xml:"http://www.w3.org/2001/04/xmlenc# EncryptionMethod"` 42 | KeyInfo *KeyInfo `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` 43 | CipherData *CipherData `xml:"http://www.w3.org/2001/04/xmlenc# CipherData"` 44 | } 45 | 46 | type X509Data struct { 47 | XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"` 48 | X509Certificate *X509Certificate 49 | } 50 | 51 | type X509Certificate struct { 52 | XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Certificate"` 53 | Data []byte `xml:",chardata"` 54 | } 55 | 56 | type CipherData struct { 57 | XMLName xml.Name `xml:"http://www.w3.org/2001/04/xmlenc# CipherData"` 58 | CipherValue *CipherValue 59 | } 60 | 61 | type CipherValue struct { 62 | XMLName xml.Name `xml:"http://www.w3.org/2001/04/xmlenc# CipherValue"` 63 | Data string `xml:",chardata"` 64 | } 65 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "strings" 7 | 8 | "github.com/crewjam/errset" 9 | ) 10 | 11 | // void captureXmlErrors(); 12 | import "C" 13 | 14 | var globalErrors = map[uintptr]errset.ErrSet{} 15 | 16 | type libraryError struct { 17 | FileName string 18 | Line int 19 | FuncName string 20 | Object string 21 | Subject string 22 | Reason int 23 | Message string 24 | } 25 | 26 | func (e libraryError) Error() string { 27 | return fmt.Sprintf( 28 | "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s", 29 | e.FuncName, 30 | e.FileName, 31 | e.Line, 32 | e.Object, 33 | e.Subject, 34 | e.Reason, 35 | e.Message) 36 | } 37 | 38 | //export onXmlsecError 39 | func onXmlsecError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, errorSubject *C.char, reason C.int, msg *C.char) { 40 | err := libraryError{ 41 | FuncName: C.GoString(funcName), 42 | FileName: C.GoString(file), 43 | Line: int(line), 44 | Object: C.GoString(errorObject), 45 | Subject: C.GoString(errorSubject), 46 | Reason: int(reason), 47 | Message: C.GoString(msg)} 48 | threadID := getThreadID() 49 | globalErrors[threadID] = append(globalErrors[threadID], err) 50 | } 51 | 52 | //export onXmlError 53 | func onXmlError(msg *C.char) { 54 | threadID := getThreadID() 55 | globalErrors[threadID] = append(globalErrors[threadID], 56 | fmt.Errorf("%s", strings.TrimSuffix(C.GoString(msg), "\n"))) 57 | } 58 | 59 | // startProcessingXML is called whenever we enter a function exported by this package. 60 | // It locks the current goroutine to the current thread and establishes a thread-local 61 | // error object. If the library later calls onError then the error will be appended 62 | // to the error object associated with the current thread. 63 | func startProcessingXML() { 64 | runtime.LockOSThread() 65 | globalErrors[getThreadID()] = errset.ErrSet{} 66 | C.captureXmlErrors() 67 | } 68 | 69 | // stopProcessingXML unlocks the goroutine-thread lock and deletes the current 70 | // error stack. 71 | func stopProcessingXML() { 72 | delete(globalErrors, getThreadID()) 73 | runtime.UnlockOSThread() 74 | } 75 | 76 | // popError returns the global error for the current thread and resets it to 77 | // an empty error. Returns nil if no errors have occurred. This function must be 78 | // called after startProcessingXML() and before stopProcessingXML(). All three 79 | // functions must be called on the same goroutine. 80 | func popError() error { 81 | threadID := getThreadID() 82 | rv := globalErrors[threadID].ReturnValue() 83 | globalErrors[threadID] = errset.ErrSet{} 84 | return rv 85 | } 86 | 87 | // mustPopError is like popError except that if there is no error on the stack 88 | // it returns a generic error. 89 | func mustPopError() error { 90 | err := popError() 91 | if err == nil { 92 | err = fmt.Errorf("libxmlsec: call failed") 93 | } 94 | return err 95 | } 96 | -------------------------------------------------------------------------------- /Dockerfile.build-static: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | RUN apt-get update -yy && \ 3 | apt-get install -yy git make curl pkg-config 4 | 5 | RUN curl -s https://storage.googleapis.com/golang/go1.7.linux-amd64.tar.gz | tar -C /usr/local -xzf - 6 | ENV GOPATH=/go 7 | ENV PATH=$PATH:/usr/local/go/bin:/go/bin 8 | RUN mkdir -p /go/bin 9 | 10 | RUN curl -sL ftp://xmlsoft.org/libxml2/libxml2-2.9.4.tar.gz | tar -xzf - && \ 11 | cd /libxml2-2.9.4 && \ 12 | ./configure \ 13 | --enable-static \ 14 | --disable-shared \ 15 | --without-gnu-ld \ 16 | --with-c14n \ 17 | --without-catalog \ 18 | --without-debug \ 19 | --without-docbook \ 20 | --without-fexceptions \ 21 | --without-ftp \ 22 | --without-history \ 23 | --without-html \ 24 | --without-http \ 25 | --without-iconv \ 26 | --without-icu \ 27 | --without-iso8859x \ 28 | --without-legacy \ 29 | --without-mem-debug \ 30 | --without-minimum \ 31 | --with-output \ 32 | --without-pattern \ 33 | --with-push \ 34 | --without-python \ 35 | --without-reader \ 36 | --without-readline \ 37 | --without-regexps \ 38 | --without-run-debug \ 39 | --with-sax1 \ 40 | --without-schemas \ 41 | --without-schematron \ 42 | --without-threads \ 43 | --without-thread-alloc \ 44 | --with-tree \ 45 | --without-valid \ 46 | --without-writer \ 47 | --without-xinclude \ 48 | --without-xpath \ 49 | --with-xptr \ 50 | --without-modules \ 51 | --without-zlib \ 52 | --without-lzma \ 53 | --without-coverage && \ 54 | make install 55 | 56 | RUN \ 57 | curl -sL ftp://ftp.openssl.org/source/openssl-1.0.2j.tar.gz | tar -xzf - && \ 58 | cd openssl-1.0.2j && \ 59 | ./config \ 60 | no-shared \ 61 | no-weak-ssl-ciphers \ 62 | no-ssl2 \ 63 | no-ssl3 \ 64 | no-comp \ 65 | no-idea \ 66 | no-dtls \ 67 | no-hw \ 68 | no-threads \ 69 | no-dso && \ 70 | make depend install 71 | 72 | RUN curl -sL http://www.aleksey.com/xmlsec/download/xmlsec1-1.2.22.tar.gz | tar -xzf - && \ 73 | cd xmlsec1-1.2.22 && \ 74 | ./configure \ 75 | --enable-static \ 76 | --disable-shared \ 77 | --disable-crypto-dl \ 78 | --disable-apps-crypto-dl \ 79 | --enable-static-linking \ 80 | --without-gnu-ld \ 81 | --with-default-crypto=openssl \ 82 | --with-openssl=/usr/local/ssl \ 83 | --with-libxml=/usr/local \ 84 | --without-nss \ 85 | --without-nspr \ 86 | --without-gcrypt \ 87 | --without-gnutls \ 88 | --without-libxslt && \ 89 | make -C src install && \ 90 | make -C include install && \ 91 | make install-pkgconfigDATA 92 | 93 | ADD . /go/src/github.com/crewjam/go-xmlsec 94 | WORKDIR /go/src/github.com/crewjam/go-xmlsec 95 | RUN go get github.com/crewjam/errset 96 | RUN go build -tags static -ldflags '-s -extldflags "-static"' -o /bin/xmldsig ./examples/xmldsig.go 97 | RUN ldd /bin/xmldsig || true 98 | RUN /bin/xmldsig --help || true 99 | -------------------------------------------------------------------------------- /xmlsec.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import "unsafe" 4 | 5 | // Note: on mac you need: 6 | // brew install libxmlsec1 libxml2 7 | // brew link libxml2 --force 8 | 9 | // #cgo CFLAGS: -DXMLSEC_CRYPTO_OPENSSL -UXMLSEC_CRYPTO_DYNAMIC_LOADING 10 | // #cgo LDFLAGS: -lxmlsec1-openssl 11 | // #include 12 | // #include 13 | // #include 14 | // #include 15 | // #include 16 | // #include 17 | import "C" 18 | 19 | // #include 20 | // #include 21 | // #include 22 | // 23 | // // xmlFree is a macro, so we need to wrap it in order to be able to call 24 | // // it from go code. 25 | // static inline void MY_xmlFree(void *p) { 26 | // xmlFree(p); 27 | // } 28 | import "C" 29 | 30 | func init() { 31 | C.xmlInitParser() 32 | 33 | if rv := C.xmlSecInit(); rv < 0 { 34 | panic("xmlsec failed to initialize") 35 | } 36 | if rv := C.xmlSecCryptoAppInit(nil); rv < 0 { 37 | panic("xmlsec crypto initialization failed.") 38 | } 39 | if rv := C.xmlSecCryptoInit(); rv < 0 { 40 | panic("xmlsec crypto initialization failed.") 41 | } 42 | } 43 | 44 | func newDoc(buf []byte, idattrs []XMLIDOption) (*C.xmlDoc, error) { 45 | ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])), 46 | C.int(len(buf))) 47 | if ctx == nil { 48 | return nil, mustPopError() 49 | } 50 | defer C.xmlFreeParserCtxt(ctx) 51 | 52 | C.xmlParseDocument(ctx) 53 | 54 | if ctx.wellFormed == C.int(0) { 55 | return nil, mustPopError() 56 | } 57 | 58 | doc := ctx.myDoc 59 | if doc == nil { 60 | return nil, mustPopError() 61 | } 62 | 63 | for _, idattr := range idattrs { 64 | addIDAttr(C.xmlDocGetRootElement(doc), 65 | idattr.AttributeName, idattr.ElementName, idattr.ElementNamespace) 66 | } 67 | return doc, nil 68 | } 69 | 70 | func addIDAttr(node *C.xmlNode, attrName, nodeName, nsHref string) { 71 | // process children first because it does not matter much but does simplify code 72 | cur := C.xmlSecGetNextElementNode(node.children) 73 | for { 74 | if cur == nil { 75 | break 76 | } 77 | addIDAttr(cur, attrName, nodeName, nsHref) 78 | cur = C.xmlSecGetNextElementNode(cur.next) 79 | } 80 | 81 | if C.GoString((*C.char)(unsafe.Pointer(node.name))) != nodeName { 82 | return 83 | } 84 | if nsHref != "" && node.ns != nil && C.GoString((*C.char)(unsafe.Pointer(node.ns.href))) != nsHref { 85 | return 86 | } 87 | 88 | // the attribute with name equal to attrName should exist 89 | for attr := node.properties; attr != nil; attr = attr.next { 90 | if C.GoString((*C.char)(unsafe.Pointer(attr.name))) == attrName { 91 | id := C.xmlNodeListGetString(node.doc, attr.children, 1) 92 | if id == nil { 93 | continue 94 | } 95 | C.xmlAddID(nil, node.doc, id, attr) 96 | } 97 | } 98 | 99 | return 100 | } 101 | func closeDoc(doc *C.xmlDoc) { 102 | C.xmlFreeDoc(doc) 103 | } 104 | 105 | func dumpDoc(doc *C.xmlDoc) []byte { 106 | var buffer *C.xmlChar 107 | var bufferSize C.int 108 | C.xmlDocDumpMemory(doc, &buffer, &bufferSize) 109 | defer C.MY_xmlFree(unsafe.Pointer(buffer)) 110 | 111 | return C.GoBytes(unsafe.Pointer(buffer), bufferSize) 112 | } 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-xmlsec 2 | 3 | [![](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) 4 | 5 | A partial wrapper for [xmlsec](https://www.aleksey.com/xmlsec). 6 | 7 | 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. 8 | 9 | # Examples 10 | 11 | ## Signing 12 | 13 | key, _ := ioutil.ReadFile("saml.key") 14 | doc, _ := ioutil.ReadAll(os.Stdin) 15 | signedDoc, err := Sign(key, doc, SignatureOptions{}) 16 | os.Stdout.Write(signedDoc) 17 | 18 | ## Verifying 19 | 20 | key, _ := ioutil.ReadFile("saml.crt") 21 | doc, _ := ioutil.ReadAll(os.Stdin) 22 | err := xmldsig.Verify(key, doc, SignatureOptions{}) 23 | if err == xmldsig.ErrVerificationFailed { 24 | os.Exit(1) 25 | } 26 | 27 | ## Decrypting 28 | 29 | key, _ := ioutil.ReadFile("saml.key") 30 | doc, _ := ioutil.ReadAll(os.Stdin) 31 | plaintextDoc, err := Decrypt(key, doc) 32 | os.Stdout.Write(plaintextDoc) 33 | 34 | ## Encrypting 35 | 36 | key, _ := ioutil.ReadFile("saml.crt") 37 | doc, _ := ioutil.ReadAll(os.Stdin) 38 | encryptedDoc, err := Encrypt(key, doc, EncryptOptions{}) 39 | os.Stdout.Write(encryptedDoc) 40 | 41 | # Install 42 | 43 | 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: 44 | 45 | $ apt-get install libxml2-dev libxmlsec1-dev pkg-config 46 | $ go get github.com/crewjam/go-xmlsec 47 | 48 | On Mac with homebrew, this might look like: 49 | 50 | $ brew install libxmlsec1 libxml2 pkg-config 51 | $ go get github.com/crewjam/go-xmlsec 52 | 53 | # Static Linking 54 | 55 | 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 56 | a static binary. See also `Dockerfile.build-static` which build the example 57 | program using this method. 58 | 59 | ## Compile libxml 60 | 61 | ``` 62 | curl -sL ftp://xmlsoft.org/libxml2/libxml2-2.9.4.tar.gz | tar -xzf - 63 | cd /libxml2-2.9.4 64 | ./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 65 | make install 66 | ``` 67 | 68 | ## Compile openssl 69 | 70 | ``` 71 | curl -sL ftp://ftp.openssl.org/source/openssl-1.0.2h.tar.gz | tar -xzf - 72 | cd openssl-1.0.2h 73 | ./config no-shared no-weak-ssl-ciphers no-ssl2 no-ssl3 no-comp no-idea no-dtls no-hw no-threads no-dso 74 | make install 75 | ``` 76 | 77 | ## Compile libxmlsec 78 | 79 | ``` 80 | curl -sL http://www.aleksey.com/xmlsec/download/xmlsec1-1.2.22.tar.gz | tar -xzf - 81 | ./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 82 | make -C src install 83 | make -C include install 84 | make install-pkgconfigDATA 85 | ``` 86 | 87 | ## Build with static tag 88 | 89 | ``` 90 | go build -tags static -ldflags '-s -extldflags "-static"' -o /bin/xmldsig-static.bin ./examples/xmldsig.go 91 | ``` 92 | 93 | Running `ldd` on the output should produce `not a dynamic executable`. 94 | 95 | 96 | -------------------------------------------------------------------------------- /xmlenc/decrypt.go: -------------------------------------------------------------------------------- 1 | package xmlenc 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/des" 8 | "crypto/rand" 9 | "crypto/rsa" 10 | "crypto/sha1" 11 | "crypto/sha256" 12 | "crypto/sha512" 13 | "crypto/x509" 14 | "encoding/base64" 15 | "encoding/pem" 16 | "encoding/xml" 17 | "fmt" 18 | "hash" 19 | "io" 20 | 21 | "github.com/pkg/errors" 22 | "golang.org/x/crypto/ripemd160" 23 | ) 24 | 25 | var ErrCannotFindEncryptedDataNode = errors.New("cannot find EncryptedData node") 26 | 27 | var ErrPublicKeyMismatch = errors.New("certificate public key does not match provided private key") 28 | 29 | type ErrUnsupportedAlgorithm struct { 30 | Algorithm string 31 | } 32 | 33 | func (e ErrUnsupportedAlgorithm) Error() string { 34 | return fmt.Sprintf("unsupported algorithm: %s", e.Algorithm) 35 | } 36 | 37 | func Decrypt(privateKey []byte, doc []byte) ([]byte, error) { 38 | decoder := xml.NewDecoder(bytes.NewReader(doc)) 39 | for { 40 | startOffset := decoder.InputOffset() 41 | token, err := decoder.Token() 42 | if err == io.EOF { 43 | return nil, ErrCannotFindEncryptedDataNode 44 | } 45 | if err != nil { 46 | return nil, err 47 | } 48 | 49 | if startElement, ok := token.(xml.StartElement); ok { 50 | if startElement.Name.Space == "http://www.w3.org/2001/04/xmlenc#" && startElement.Name.Local == "EncryptedData" { 51 | encryptedData := EncryptedData{} 52 | if err := decoder.DecodeElement(&encryptedData, &startElement); err != nil { 53 | return nil, err 54 | } 55 | plaintext, err := decrypt(privateKey, encryptedData) 56 | if err != nil { 57 | return nil, err 58 | } 59 | endOffset := decoder.InputOffset() 60 | 61 | rv := append(doc[:startOffset], append(plaintext, doc[endOffset:]...)...) 62 | return rv, nil 63 | } 64 | } 65 | } 66 | } 67 | 68 | func decrypt(privateKey []byte, encryptedData EncryptedData) ([]byte, error) { 69 | 70 | var key []byte 71 | if encryptedData.KeyInfo.EncryptedKey != nil { 72 | var err error 73 | key, err = decryptKey(privateKey, *encryptedData.KeyInfo.EncryptedKey) 74 | if err != nil { 75 | return nil, err 76 | } 77 | } 78 | 79 | ciphertext, err := base64.StdEncoding.DecodeString(encryptedData.CipherData.CipherValue.Data) 80 | if err != nil { 81 | return nil, errors.Wrap(err, "base64 decode ciphertext") 82 | } 83 | 84 | var block cipher.Block 85 | var iv []byte 86 | switch *encryptedData.EncryptionMethod.Algorithm { 87 | case "http://www.w3.org/2001/04/xmlenc#tripledes-cbc": 88 | block, err = des.NewCipher(key) 89 | if err != nil { 90 | return nil, errors.Wrap(err, "AES init") 91 | } 92 | iv = ciphertext[:des.BlockSize] 93 | ciphertext = ciphertext[des.BlockSize:] 94 | case "http://www.w3.org/2001/04/xmlenc#aes128-cbc": 95 | fallthrough 96 | case "http://www.w3.org/2001/04/xmlenc#aes256-cbc": 97 | fallthrough 98 | case "http://www.w3.org/2001/04/xmlenc#aes192-cbc": 99 | block, err = aes.NewCipher(key) 100 | if err != nil { 101 | return nil, errors.Wrap(err, "AES init") 102 | } 103 | iv = ciphertext[:aes.BlockSize] 104 | ciphertext = ciphertext[aes.BlockSize:] 105 | default: 106 | return nil, ErrUnsupportedAlgorithm{Algorithm: *encryptedData.EncryptionMethod.Algorithm} 107 | } 108 | 109 | if len(ciphertext)%aes.BlockSize != 0 { 110 | return nil, errors.Wrap(fmt.Errorf("ciphertext is not a multiple of the block size"), 111 | "invalid ciphertext") 112 | } 113 | 114 | mode := cipher.NewCBCDecrypter(block, iv) 115 | mode.CryptBlocks(ciphertext, ciphertext) 116 | 117 | // strip padding 118 | { 119 | paddingLen := int(ciphertext[len(ciphertext)-1]) 120 | ciphertext = ciphertext[:len(ciphertext)-paddingLen] 121 | } 122 | 123 | return ciphertext, nil 124 | } 125 | 126 | func rsaPublicKeyEquals(a rsa.PublicKey, b rsa.PublicKey) bool { 127 | return a.E == b.E && a.N.Cmp(b.N) == 0 128 | } 129 | 130 | func decryptKey(privateKey []byte, encryptedKey EncryptedKey) ([]byte, error) { 131 | cipherValue, err := base64.StdEncoding.DecodeString(string(encryptedKey.CipherData.CipherValue.Data)) 132 | if err != nil { 133 | return nil, errors.Wrap(err, "decode key base64") 134 | } 135 | 136 | // TODO(ross): add support for http://www.w3.org/2001/04/xmlenc#rsa-1_5 once we can 137 | // scrounge up some test vectors 138 | if *encryptedKey.EncryptionMethod.Algorithm != "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" { 139 | return nil, ErrUnsupportedAlgorithm{Algorithm: *encryptedKey.EncryptionMethod.Algorithm} 140 | } 141 | 142 | pemBlock, _ := pem.Decode(privateKey) 143 | if pemBlock == nil || pemBlock.Type != "RSA PRIVATE KEY" { 144 | return nil, errors.Wrap(fmt.Errorf("invalid private key"), "parse RSA private key") 145 | } 146 | rsaKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) 147 | if err != nil { 148 | return nil, errors.Wrap(err, "x509.ParsePKCS1PrivateKey") 149 | } 150 | 151 | { 152 | pemBlock, _ := pem.Decode([]byte(fmt.Sprintf( 153 | "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n", 154 | string(encryptedKey.KeyInfo.X509Data.X509Certificate.Data)))) 155 | if pemBlock == nil { 156 | return nil, errors.New("cannot parse certificate") 157 | } 158 | cert, err := x509.ParseCertificate(pemBlock.Bytes) 159 | if err != nil { 160 | return nil, errors.Wrap(err, "x509.ParseCertificate") 161 | } 162 | if !rsaPublicKeyEquals(*cert.PublicKey.(*rsa.PublicKey), rsaKey.PublicKey) { 163 | return nil, ErrPublicKeyMismatch 164 | } 165 | } 166 | 167 | label := []byte{} 168 | if encryptedKey.EncryptionMethod.OAEPparams != nil { 169 | label = encryptedKey.EncryptionMethod.OAEPparams.Data 170 | } 171 | 172 | var hashMethod hash.Hash 173 | switch encryptedKey.EncryptionMethod.DigestMethod.Algorithm { 174 | case "http://www.w3.org/2000/09/xmldsig#sha1": 175 | hashMethod = sha1.New() 176 | case "http://www.w3.org/2001/04/xmlenc#sha256": 177 | hashMethod = sha256.New() 178 | case "http://www.w3.org/2001/04/xmlenc#sha512": 179 | hashMethod = sha512.New() 180 | case "http://www.w3.org/2001/04/xmlenc#ripemd160": 181 | hashMethod = ripemd160.New() 182 | default: 183 | return nil, ErrUnsupportedAlgorithm{Algorithm: encryptedKey.EncryptionMethod.DigestMethod.Algorithm} 184 | } 185 | 186 | plaintext, err := rsa.DecryptOAEP(hashMethod, rand.Reader, rsaKey, cipherValue, label) 187 | if err != nil { 188 | return nil, err 189 | } 190 | 191 | return plaintext, nil 192 | } 193 | -------------------------------------------------------------------------------- /xmldsig.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "errors" 5 | "unsafe" 6 | ) 7 | 8 | // #include 9 | // #include 10 | // #include 11 | // #include 12 | // #include 13 | // #include 14 | import "C" 15 | 16 | // SignatureOptions represents additional, less commonly used, options for Sign and 17 | // Verify 18 | type SignatureOptions struct { 19 | // Specify the name of ID attributes for specific elements. This 20 | // may be required if the signed document contains Reference elements 21 | // that define which parts of the document are to be signed. 22 | // 23 | // https://www.aleksey.com/xmlsec/faq.html#section_3_2 24 | // http://www.w3.org/TR/xml-id/ 25 | // http://xmlsoft.org/html/libxml-valid.html#xmlAddID 26 | XMLID []XMLIDOption 27 | } 28 | 29 | // XMLIDOption represents the definition of an XML reference element 30 | // (See http://www.w3.org/TR/xml-id/) 31 | type XMLIDOption struct { 32 | ElementName string 33 | ElementNamespace string 34 | AttributeName string 35 | } 36 | 37 | // Sign returns a version of doc signed with key according to 38 | // the XMLDSIG standard. doc is a template document meaning 39 | // that it contains an `http://www.w3.org/2000/09/xmldsig#Signature` 40 | // element whose properties define how and what to sign. 41 | func Sign(key []byte, doc []byte, opts SignatureOptions) ([]byte, error) { 42 | startProcessingXML() 43 | defer stopProcessingXML() 44 | 45 | ctx := C.xmlSecDSigCtxCreate(nil) 46 | if ctx == nil { 47 | return nil, errors.New("failed to create signature context") 48 | } 49 | defer C.xmlSecDSigCtxDestroy(ctx) 50 | 51 | ctx.signKey = C.xmlSecCryptoAppKeyLoadMemory( 52 | (*C.xmlSecByte)(unsafe.Pointer(&key[0])), 53 | C.xmlSecSize(len(key)), 54 | C.xmlSecKeyDataFormatPem, 55 | nil, nil, nil) 56 | if ctx.signKey == nil { 57 | return nil, errors.New("failed to load pem key") 58 | } 59 | 60 | parsedDoc, err := newDoc(doc, opts.XMLID) 61 | if err != nil { 62 | return nil, err 63 | } 64 | defer closeDoc(parsedDoc) 65 | 66 | node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), 67 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), 68 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) 69 | if node == nil { 70 | return nil, errors.New("cannot find start node") 71 | } 72 | 73 | if rv := C.xmlSecDSigCtxSign(ctx, node); rv < 0 { 74 | return nil, errors.New("failed to sign") 75 | } 76 | 77 | return dumpDoc(parsedDoc), nil 78 | 79 | } 80 | 81 | // ErrVerificationFailed is returned from Verify when the signature is incorrect 82 | var ErrVerificationFailed = errors.New("signature verification failed") 83 | 84 | // values returned from xmlSecDSigCtxVerify 85 | const ( 86 | xmlSecDSigStatusUnknown = 0 87 | xmlSecDSigStatusSucceeded = 1 88 | xmlSecDSigStatusInvalid = 2 89 | ) 90 | 91 | // Verify checks that the signature in doc is valid according 92 | // to the XMLDSIG specification. publicKey is the public part of 93 | // the key used to sign doc. If the signature is not correct, 94 | // this function returns ErrVerificationFailed. 95 | func Verify(publicKey []byte, doc []byte, opts SignatureOptions) error { 96 | startProcessingXML() 97 | defer stopProcessingXML() 98 | 99 | keysMngr := C.xmlSecKeysMngrCreate() 100 | if keysMngr == nil { 101 | return mustPopError() 102 | } 103 | defer C.xmlSecKeysMngrDestroy(keysMngr) 104 | 105 | if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { 106 | return mustPopError() 107 | } 108 | 109 | key := C.xmlSecCryptoAppKeyLoadMemory( 110 | (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), 111 | C.xmlSecSize(len(publicKey)), 112 | C.xmlSecKeyDataFormatCertPem, 113 | nil, nil, nil) 114 | if key == nil { 115 | return mustPopError() 116 | } 117 | 118 | if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key, 119 | (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), 120 | C.xmlSecSize(len(publicKey)), 121 | C.xmlSecKeyDataFormatCertPem); rv < 0 { 122 | C.xmlSecKeyDestroy(key) 123 | return mustPopError() 124 | } 125 | 126 | if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 { 127 | return mustPopError() 128 | } 129 | 130 | dsigCtx := C.xmlSecDSigCtxCreate(keysMngr) 131 | if dsigCtx == nil { 132 | return mustPopError() 133 | } 134 | defer C.xmlSecDSigCtxDestroy(dsigCtx) 135 | 136 | parsedDoc, err := newDoc(doc, opts.XMLID) 137 | if err != nil { 138 | return err 139 | } 140 | defer closeDoc(parsedDoc) 141 | 142 | node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), 143 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), 144 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) 145 | if node == nil { 146 | return errors.New("cannot find start node") 147 | } 148 | 149 | if rv := C.xmlSecDSigCtxVerify(dsigCtx, node); rv < 0 { 150 | return ErrVerificationFailed 151 | } 152 | 153 | if dsigCtx.status != xmlSecDSigStatusSucceeded { 154 | return ErrVerificationFailed 155 | } 156 | return nil 157 | } 158 | 159 | // Verify checks that the signature in doc is valid according 160 | // to the XMLDSIG specification. certs is an array of trusted certificates. 161 | // If the signature is not correct, this function returns ErrVerificationFailed. 162 | func VerifyTrusted(certs [][]byte, doc []byte, opts SignatureOptions) error { 163 | startProcessingXML() 164 | defer stopProcessingXML() 165 | 166 | keysMngr := C.xmlSecKeysMngrCreate() 167 | if keysMngr == nil { 168 | return mustPopError() 169 | } 170 | defer C.xmlSecKeysMngrDestroy(keysMngr) 171 | 172 | if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { 173 | return mustPopError() 174 | } 175 | 176 | for _, cert := range certs { 177 | if rv := C.xmlSecCryptoAppKeysMngrCertLoadMemory( 178 | keysMngr, 179 | (*C.xmlSecByte)(unsafe.Pointer(&cert[0])), 180 | C.xmlSecSize(len(cert)), 181 | C.xmlSecKeyDataFormatCertPem, 182 | C.xmlSecKeyDataTypeTrusted); rv < 0 { 183 | return mustPopError() 184 | } 185 | } 186 | 187 | dsigCtx := C.xmlSecDSigCtxCreate(keysMngr) 188 | if dsigCtx == nil { 189 | return mustPopError() 190 | } 191 | defer C.xmlSecDSigCtxDestroy(dsigCtx) 192 | 193 | parsedDoc, err := newDoc(doc, opts.XMLID) 194 | if err != nil { 195 | return err 196 | } 197 | defer closeDoc(parsedDoc) 198 | 199 | node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), 200 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), 201 | (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) 202 | if node == nil { 203 | return errors.New("cannot find start node") 204 | } 205 | 206 | if rv := C.xmlSecDSigCtxVerify(dsigCtx, node); rv < 0 { 207 | return ErrVerificationFailed 208 | } 209 | 210 | if dsigCtx.status != xmlSecDSigStatusSucceeded { 211 | return ErrVerificationFailed 212 | } 213 | return nil 214 | } 215 | -------------------------------------------------------------------------------- /encrypt.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | // #include 4 | // #include 5 | // #include 6 | // #include 7 | // #include 8 | // 9 | // // Note: the xmlSecKeyData*Id itentifiers are macros, so we need to wrap them 10 | // // here to make them callable from go. 11 | // static inline xmlSecKeyDataId MY_xmlSecKeyDataAesId(void) { return xmlSecKeyDataAesId; } 12 | // static inline xmlSecKeyDataId MY_xmlSecKeyDataDesId(void) { return xmlSecKeyDataDesId; } 13 | // static inline xmlSecTransformId MY_xmlSecTransformAes128CbcId(void) { return xmlSecTransformAes128CbcId; } 14 | // static inline xmlSecTransformId MY_xmlSecTransformAes192CbcId(void) { return xmlSecTransformAes192CbcId; } 15 | // static inline xmlSecTransformId MY_xmlSecTransformAes256CbcId(void) { return xmlSecTransformAes256CbcId; } 16 | // static inline xmlSecTransformId MY_xmlSecTransformDes3CbcId(void) { return xmlSecTransformDes3CbcId; } 17 | // static inline xmlSecTransformId MY_xmlSecTransformRsaOaepId(void) { return xmlSecTransformRsaOaepId; } 18 | // static inline xmlSecTransformId MY_xmlSecTransformRsaPkcs1Id(void) { return xmlSecTransformRsaPkcs1Id; } 19 | // 20 | import "C" 21 | 22 | import ( 23 | "errors" 24 | "unsafe" 25 | ) 26 | 27 | // SessionCipherType represents which session cipher to use to encrypt the document. 28 | type SessionCipherType int 29 | 30 | const ( 31 | // DefaultSessionCipher (the zero value) represents the default session cipher, AES256-CBC 32 | DefaultSessionCipher SessionCipherType = iota 33 | 34 | // Aes128Cbc means the session cipher should be AES-128 in CBC mode. 35 | Aes128Cbc 36 | 37 | // Aes192Cbc means the session cipher should be AES-192 in CBC mode. 38 | Aes192Cbc 39 | 40 | // Aes256Cbc means the session cipher should be AES-256 in CBC mode. 41 | Aes256Cbc 42 | 43 | // Des3Cbc means the session cipher should be triple DES in CBC mode. 44 | Des3Cbc 45 | ) 46 | 47 | // CipherType represent which cipher to use to encrypt the document 48 | type CipherType int 49 | 50 | const ( 51 | // DefaultCipher (the zero value) represents the default cipher, RSA-OAEP 52 | DefaultCipher CipherType = iota 53 | 54 | // RsaOaep means the cipher should be RSA-OAEP 55 | RsaOaep 56 | 57 | // RsaPkcs1 means the cipher should be RSA-PKCS1 58 | RsaPkcs1 59 | ) 60 | 61 | // DigestAlgorithmType represent which digest algorithm to use when encrypting the document. 62 | type DigestAlgorithmType int 63 | 64 | const ( 65 | // DefaultDigestAlgorithm (the zero value) represents the default cipher, SHA1 66 | DefaultDigestAlgorithm DigestAlgorithmType = iota 67 | 68 | // Sha1 means the digest algorithm should be SHA-1 69 | Sha1 70 | 71 | // Sha256 means the digest algorithm should be SHA-256 72 | Sha256 73 | 74 | // Sha384 means the digest algorithm should be SHA-384 75 | Sha384 76 | 77 | // Sha512 means the digest algorithm should be SHA-512 78 | Sha512 79 | ) 80 | 81 | // EncryptOptions specifies the ciphers to use to encrypt the document. 82 | type EncryptOptions struct { 83 | SessionCipher SessionCipherType 84 | Cipher CipherType 85 | DigestAlgorithm DigestAlgorithmType 86 | } 87 | 88 | var errInvalidAlgorithm = errors.New("invalid algorithm") 89 | 90 | // global string constants 91 | // Note: the invocations of C.CString() here return a pointer to a string 92 | // allocated from the C heap that would normally need to freed by calling 93 | // C.free, but because these are global, we can just leak them. 94 | var ( 95 | constDsigNamespace = (*C.xmlChar)(unsafe.Pointer(C.CString("http://www.w3.org/2000/09/xmldsig#"))) 96 | constDigestMethod = (*C.xmlChar)(unsafe.Pointer(C.CString("DigestMethod"))) 97 | constAlgorithm = (*C.xmlChar)(unsafe.Pointer(C.CString("Algorithm"))) 98 | constSha512 = (*C.xmlChar)(unsafe.Pointer(C.CString("http://www.w3.org/2001/04/xmlenc#sha512"))) 99 | constSha384 = (*C.xmlChar)(unsafe.Pointer(C.CString("http://www.w3.org/2001/04/xmldsig-more#sha384"))) 100 | constSha256 = (*C.xmlChar)(unsafe.Pointer(C.CString("http://www.w3.org/2001/04/xmlenc#sha256"))) 101 | constSha1 = (*C.xmlChar)(unsafe.Pointer(C.CString("http://www.w3.org/2000/09/xmldsig#sha1"))) 102 | ) 103 | 104 | // Encrypt encrypts the XML document to publicKey and returns the encrypted 105 | // document. 106 | func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) { 107 | startProcessingXML() 108 | defer stopProcessingXML() 109 | 110 | keysMngr := C.xmlSecKeysMngrCreate() 111 | if keysMngr == nil { 112 | return nil, mustPopError() 113 | } 114 | defer C.xmlSecKeysMngrDestroy(keysMngr) 115 | 116 | if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { 117 | return nil, mustPopError() 118 | } 119 | 120 | key := C.xmlSecCryptoAppKeyLoadMemory( 121 | (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), 122 | C.xmlSecSize(len(publicKey)), 123 | C.xmlSecKeyDataFormatCertPem, 124 | nil, nil, nil) 125 | if key == nil { 126 | return nil, mustPopError() 127 | } 128 | 129 | if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key, 130 | (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), 131 | C.xmlSecSize(len(publicKey)), 132 | C.xmlSecKeyDataFormatCertPem); rv < 0 { 133 | C.xmlSecKeyDestroy(key) 134 | return nil, mustPopError() 135 | } 136 | 137 | if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 { 138 | return nil, mustPopError() 139 | } 140 | 141 | parsedDoc, err := newDoc(doc, nil) 142 | if err != nil { 143 | return nil, err 144 | } 145 | defer closeDoc(parsedDoc) 146 | 147 | var sessionCipherTransform C.xmlSecTransformId 148 | switch opts.SessionCipher { 149 | case DefaultSessionCipher: 150 | sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId() 151 | case Aes256Cbc: 152 | sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId() 153 | case Aes192Cbc: 154 | sessionCipherTransform = C.MY_xmlSecTransformAes192CbcId() 155 | case Aes128Cbc: 156 | sessionCipherTransform = C.MY_xmlSecTransformAes128CbcId() 157 | case Des3Cbc: 158 | sessionCipherTransform = C.MY_xmlSecTransformDes3CbcId() 159 | default: 160 | return nil, errInvalidAlgorithm 161 | } 162 | 163 | // create encryption template to encrypt XML file and replace 164 | // its content with encryption result 165 | encDataNode := C.xmlSecTmplEncDataCreate(parsedDoc, sessionCipherTransform, 166 | nil, (*C.xmlChar)(unsafe.Pointer(&C.xmlSecTypeEncElement)), nil, nil) 167 | if encDataNode == nil { 168 | return nil, mustPopError() 169 | } 170 | defer func() { 171 | if encDataNode != nil { 172 | C.xmlFreeNode(encDataNode) 173 | encDataNode = nil 174 | } 175 | }() 176 | 177 | // we want to put encrypted data in the node 178 | if C.xmlSecTmplEncDataEnsureCipherValue(encDataNode) == nil { 179 | return nil, mustPopError() 180 | } 181 | 182 | // add 183 | keyInfoNode := C.xmlSecTmplEncDataEnsureKeyInfo(encDataNode, nil) 184 | if keyInfoNode == nil { 185 | return nil, mustPopError() 186 | } 187 | 188 | // add to store the encrypted session key 189 | var cipherTransform C.xmlSecTransformId 190 | switch opts.Cipher { 191 | case DefaultCipher: 192 | cipherTransform = C.MY_xmlSecTransformRsaOaepId() 193 | case RsaOaep: 194 | cipherTransform = C.MY_xmlSecTransformRsaOaepId() 195 | case RsaPkcs1: 196 | cipherTransform = C.MY_xmlSecTransformRsaPkcs1Id() 197 | } 198 | encKeyNode := C.xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, cipherTransform, nil, nil, nil) 199 | if encKeyNode == nil { 200 | return nil, mustPopError() 201 | } 202 | 203 | // we want to put encrypted key in the node 204 | if C.xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == nil { 205 | return nil, mustPopError() 206 | } 207 | 208 | // add and nodes to 209 | keyInfoNode2 := C.xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, nil) 210 | if keyInfoNode2 == nil { 211 | return nil, mustPopError() 212 | } 213 | 214 | // Add a DigestMethod element to the encryption method node 215 | { 216 | encKeyMethod := C.xmlSecTmplEncDataGetEncMethodNode(encKeyNode) 217 | var algorithm *C.xmlChar 218 | switch opts.DigestAlgorithm { 219 | case Sha512: 220 | algorithm = constSha512 221 | case Sha384: 222 | algorithm = constSha384 223 | case Sha256: 224 | algorithm = constSha256 225 | case Sha1: 226 | algorithm = constSha1 227 | case DefaultDigestAlgorithm: 228 | algorithm = constSha1 229 | default: 230 | return nil, errInvalidAlgorithm 231 | } 232 | node := C.xmlSecAddChild(encKeyMethod, constDigestMethod, constDsigNamespace) 233 | C.xmlSetProp(node, constAlgorithm, algorithm) 234 | } 235 | 236 | // add our certificate to KeyInfoNode 237 | x509dataNode := C.xmlSecTmplKeyInfoAddX509Data(keyInfoNode2) 238 | if x509dataNode == nil { 239 | return nil, mustPopError() 240 | } 241 | if dataNode := C.xmlSecTmplX509DataAddCertificate(x509dataNode); dataNode == nil { 242 | return nil, mustPopError() 243 | } 244 | 245 | // create encryption context 246 | var encCtx = C.xmlSecEncCtxCreate(keysMngr) 247 | if encCtx == nil { 248 | return nil, mustPopError() 249 | } 250 | defer C.xmlSecEncCtxDestroy(encCtx) 251 | 252 | // generate a key of the appropriate type 253 | switch opts.SessionCipher { 254 | case DefaultSessionCipher: 255 | encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 256, 256 | C.xmlSecKeyDataTypeSession) 257 | case Aes128Cbc: 258 | encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 128, 259 | C.xmlSecKeyDataTypeSession) 260 | case Aes192Cbc: 261 | encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 192, 262 | C.xmlSecKeyDataTypeSession) 263 | case Aes256Cbc: 264 | encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 256, 265 | C.xmlSecKeyDataTypeSession) 266 | case Des3Cbc: 267 | encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataDesId(), 192, 268 | C.xmlSecKeyDataTypeSession) 269 | default: 270 | return nil, errInvalidAlgorithm 271 | } 272 | if encCtx.encKey == nil { 273 | return nil, mustPopError() 274 | } 275 | 276 | // encrypt the data 277 | if rv := C.xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, C.xmlDocGetRootElement(parsedDoc)); rv < 0 { 278 | return nil, mustPopError() 279 | } 280 | encDataNode = nil // the template is inserted in the doc, so we don't own it 281 | 282 | return dumpDoc(parsedDoc), nil 283 | } 284 | -------------------------------------------------------------------------------- /xmldsig_test.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "encoding/xml" 5 | "strings" 6 | 7 | . "gopkg.in/check.v1" 8 | ) 9 | 10 | type Envelope struct { 11 | Data string 12 | Signature Signature `xml:"http://www.w3.org/2000/09/xmldsig# Signature"` 13 | } 14 | 15 | type XMLDSigTest struct { 16 | Key []byte 17 | Cert []byte 18 | DocStr []byte 19 | } 20 | 21 | var _ = Suite(&XMLDSigTest{}) 22 | 23 | func (testSuite *XMLDSigTest) SetUpTest(c *C) { 24 | testSuite.Key = []byte(`-----BEGIN RSA PRIVATE KEY----- 25 | MIIBPAIBAAJBANPQbQ92nlbeg1Q5JNHSO1Yey46nZ7GJltLWw1ccSvp7pnvmfUm+ 26 | M521CpFpfr4EAE3UVBMoU9j/hqq3dFAc2H0CAwEAAQJBALFVCjmsAZyQ5jqZLO5N 27 | qEfNuHZSSUol+xPBogFIOq3BWa269eNNcAK5or5g0XWWon7EPdyGT4qyDVH9KzXK 28 | RLECIQDzm/Nj0epUGN51/rKJgRXWkXW/nfSCMO9fvQR6Ujoq3wIhAN6WeHK9vgWg 29 | wBWqMdq5sR211+LlDH7rOUQ6rBpbsoQjAiEA7jzpfglgPPZFOOfo+oh/LuP6X3a+ 30 | FER/FQXpRyb7M8kCIETUrwZ8WkiPPxbz/Fqw1W5kjw/g2I5e2uSYaCP2eyuVAiEA 31 | mOI6RhRyMqgxQyy0plJVjG1s4fdu92AWYy9AwYeyd/8= 32 | -----END RSA PRIVATE KEY----- 33 | `) 34 | testSuite.Cert = []byte(`-----BEGIN CERTIFICATE----- 35 | MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD 36 | VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy 37 | aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG 38 | A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz 39 | ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG 40 | A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 41 | cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn 42 | BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD 43 | Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j 44 | b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn 45 | sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB 46 | o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH 47 | ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM 48 | QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu 49 | MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M 50 | IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj 51 | KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G 52 | CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI 53 | hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ 54 | fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga 55 | -----END CERTIFICATE----- 56 | `) 57 | testSuite.DocStr = []byte(` 58 | 61 | 62 | 63 | Hello, World! 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 9H/rQr2Axe9hYTV2n/tCp+3UIQQ= 75 | 76 | 77 | 78 | 79 | 80 | MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD 81 | VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy 82 | aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG 83 | A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz 84 | ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG 85 | A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 86 | cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn 87 | BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD 88 | Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j 89 | b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn 90 | sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB 91 | o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH 92 | ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM 93 | QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu 94 | MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M 95 | IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj 96 | KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G 97 | CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI 98 | hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ 99 | fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga 100 | 101 | 102 | 103 | 104 | `) 105 | 106 | } 107 | 108 | func (testSuite *XMLDSigTest) TestSignAndVerify(c *C) { 109 | expectedSignedString := ` 110 | 113 | 114 | 115 | Hello, World! 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 9H/rQr2Axe9hYTV2n/tCp+3UIQQ= 127 | 128 | 129 | fDKK0so/zFcmmq2X+BaVFmS0t8KB7tyW53YN6n221OArzGCs4OyWsAjj/BUR+wNF 130 | elOnt4fo2gPK1a3IVEhMGg== 131 | 132 | 133 | MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD 134 | VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy 135 | aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG 136 | A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz 137 | ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG 138 | A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 139 | cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn 140 | BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD 141 | Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j 142 | b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn 143 | sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB 144 | o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH 145 | ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM 146 | QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu 147 | MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M 148 | IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj 149 | KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G 150 | CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI 151 | hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ 152 | fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga 153 | 154 | 155 | 156 | 157 | ` 158 | actualSignedString, err := Sign(testSuite.Key, testSuite.DocStr, SignatureOptions{}) 159 | c.Assert(err, IsNil) 160 | c.Assert(string(actualSignedString), Equals, expectedSignedString) 161 | 162 | err = Verify(testSuite.Cert, actualSignedString, SignatureOptions{}) 163 | c.Assert(err, IsNil) 164 | } 165 | 166 | func (testSuite *XMLDSigTest) TestConstructFromSignature(c *C) { 167 | // Try again but this time construct the message from a struct having a Signature member 168 | doc := Envelope{Data: "Hello, World!"} 169 | doc.Signature = DefaultSignature(testSuite.Cert) 170 | docStr, err := xml.MarshalIndent(doc, "", " ") 171 | c.Assert(err, IsNil) 172 | actualSignedString, err := Sign(testSuite.Key, docStr, SignatureOptions{}) 173 | c.Assert(err, IsNil) 174 | 175 | expectedSignedString := ` 176 | 177 | Hello, World! 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | sEenIPkW9ssFSB9t4UU6VUrytqc= 188 | 189 | 190 | chSWfpQBIQraySsUHzs5N51+ruelu2HMHh5Mnd3EjcLqFBVD0f23kmXUp7zVhCVD 191 | vCfqu9yXDYKVOBI57F0Efg== 192 | 193 | 194 | MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAnBgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQDEw1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7LjqdnsYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQABo4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTMQygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGuMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZIhvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJfBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga 195 | 196 | 197 | 198 | 199 | ` 200 | c.Assert(string(actualSignedString), Equals, expectedSignedString) 201 | 202 | err = Verify(testSuite.Cert, actualSignedString, SignatureOptions{}) 203 | c.Assert(err, IsNil) 204 | } 205 | 206 | func (testSuite *XMLDSigTest) TestVerifyFailsWhenMessageModified(c *C) { 207 | // break the document and notice that the signature is invalid 208 | signedStr, err := Sign(testSuite.Key, testSuite.DocStr, SignatureOptions{}) 209 | c.Assert(err, IsNil) 210 | 211 | err = Verify(testSuite.Cert, signedStr, SignatureOptions{}) 212 | c.Assert(err, IsNil) 213 | 214 | signedStr = []byte(strings.Replace(string(signedStr), "Hello", "Goodbye", 1)) 215 | err = Verify(testSuite.Cert, []byte(signedStr), SignatureOptions{}) 216 | c.Assert(err, Equals, ErrVerificationFailed) 217 | } 218 | 219 | func (testSuite *XMLDSigTest) TestInvalidXML(c *C) { 220 | _, err := Sign(testSuite.Key, []byte(""), SignatureOptions{}) 224 | c.Assert(err, ErrorMatches, "cannot find start node") 225 | 226 | _, err = Sign([]byte("XXX"), testSuite.DocStr, SignatureOptions{}) 227 | c.Assert(err, ErrorMatches, "failed to load pem key") 228 | 229 | err = Verify(testSuite.Cert, []byte(""), SignatureOptions{}) 233 | c.Assert(err, ErrorMatches, "cannot find start node") 234 | 235 | err = Verify([]byte("XXX"), testSuite.DocStr, SignatureOptions{}) 236 | c.Assert(err, ErrorMatches, ".*xmlSecOpenSSLAppKeyLoadMemory.*") 237 | 238 | err = Verify(testSuite.Key, testSuite.DocStr, SignatureOptions{}) 239 | c.Assert(err, ErrorMatches, ".*xmlSecOpenSSLAppKeyLoadMemory.*") 240 | 241 | err = Verify(testSuite.Cert, testSuite.DocStr, SignatureOptions{}) 242 | c.Assert(err, ErrorMatches, "signature verification failed") 243 | } 244 | 245 | func (testSuite *XMLDSigTest) TestVerifySAMLSignature(c *C) { 246 | cert := []byte(`-----BEGIN CERTIFICATE----- 247 | MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEV 248 | MBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYD 249 | VQQKEwhUZXN0U2hpYjEZMBcGA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4 250 | MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcxCzAJBgNVBAYTAlVTMRUwEwYDVQQI 251 | EwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gxETAPBgNVBAoTCFRl 252 | c3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0B 253 | AQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7C 254 | yVTDClcpu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe 255 | 3OQ01Ow3yT4I+Wdg1tsTpSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aT 256 | NPFmDixzUjoYzbGDrtAyCqA8f9CN2txIfJnpHE6q6CmKcoLADS4UrNPlhHSzd614 257 | kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB5/9nb0yh/ojRuJGmgMWH 258 | gWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HEMIHBMB0G 259 | A1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ86 260 | 9nh83KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBl 261 | bm5zeWx2YW5pYTETMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNo 262 | aWIxGTAXBgNVBAMTEGlkcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zAN 263 | BgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5MFfSVk98t3CT9jHZoYxd8QMRL 264 | I4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpkOAvZZUosVkUo 265 | 93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4 266 | /SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAj 267 | Geka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr 268 | 8K/qhmFT2nIQi538n6rVYLeWj8Bbnl+ev0peYzxFyF5sQA== 269 | -----END CERTIFICATE-----`) 270 | doc := []byte("https://idp.testshib.org/idp/shibbolethVwEKsGObmOM6y22Nstadwz1fq6dnQ2aDmERPMuEteds=gcROTzJ7HgTu/LQprki8v9J5y4et2np48hYspgmygZRvRawzxfQDgB0MBvDIBG78J5XSd401g7E999JUEh4JtSMAig1THbeWhyITGHU1Vpl2xAR5Ma0vCMLjVIleeuFHhStFBNqKirNfulfhEa7Q5THVGKrVsNuIaP/yc10Gf8AyHfCIOf/ZQGiU3Srp/pKZLXPkSKTEZIq5tAOl+pA0maFBvb4+EkMPB6E66HiXknHL9KdNh8bPcq+EkqjhtHWOy341F8W9iy6MJYGuO9ksxdiY6FK5SqmPHlgoJqXx7Et2vYME6opIgFYB6m1KW6kWgVcF0VyIzJbkXq3yTi0b5g==MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM\nUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG\nA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx\nCzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx\nETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp\nu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT\npSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI\nfJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB\n5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE\nMIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8\n3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET\nMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0\nc2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M\nFfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk\nOAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4\n/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx\npUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW\nj8Bbnl+ev0peYzxFyF5sQA==_5c425656721b41a6cfa4a9c96225e082https://15661444.ngrok.io/saml2/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportmyselfMemberStaffmyself@testshib.orgAnd IMember@testshib.orgStaff@testshib.orgMe Myselfurn:mace:dir:entitlement:common-lib-termsMe Myself And I8F+M9ovyaYNwCId0pVkVsnZYRDo=555-5555") 271 | 272 | err := Verify(cert, doc, SignatureOptions{ 273 | XMLID: []XMLIDOption{{ 274 | ElementName: "Assertion", 275 | ElementNamespace: "urn:oasis:names:tc:SAML:2.0:assertion", 276 | AttributeName: "ID", 277 | }}, 278 | }) 279 | c.Assert(err, IsNil) 280 | } 281 | -------------------------------------------------------------------------------- /encrypt_test.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | 7 | . "gopkg.in/check.v1" 8 | ) 9 | 10 | type EncryptTest struct { 11 | Cert []byte 12 | Key []byte 13 | DocStr []byte 14 | Plaintext []byte 15 | } 16 | 17 | var _ = Suite(&EncryptTest{}) 18 | 19 | func (testSuite *EncryptTest) SetUpTest(c *C) { 20 | testSuite.Cert = []byte(`-----BEGIN CERTIFICATE----- 21 | MIIDBzCCAe+gAwIBAgIJAPrpnE7Ma4MHMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV 22 | BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTExMzAxODI5MzBaFw0yNTExMjcxODI5 23 | MzBaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB 24 | BQADggEPADCCAQoCggEBAKrAQs0tOjepxXBO+dl/c++Z1xrYR0A8pxXvxMSuPs33 25 | vuBORk/9dCWBw7t3th1nL5mBUQ/xeo9iq03q8M4r8g4Ss2yaALJJmGstdy4OK0py 26 | k48vIsizl6FysheRdGz3tDLbe7QAjFa+0R1mYY/4BUeVkMRcSZyIz0kj/8fZJGpN 27 | Qx4HdeYGGLIpUzr4mgB2UHCdFbuM4WP6GiYYiWrK0YM940ggwNzwJB2czqTmUiv0 28 | 95rDbxxyReIcLEUW/4CTSIEzcBdCY1d0OeWFSjeh52IRgp4i7Ke2zx36hu0Ud/Ay 29 | q99kh0SW2VY4Ae5xnTGoUiy2j8/ZbGv/MVFIqx4fH9cCAwEAAaNQME4wHQYDVR0O 30 | BBYEFJAij0ochuBor7BmW10nwfUf6OyRMB8GA1UdIwQYMBaAFJAij0ochuBor7Bm 31 | W10nwfUf6OyRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAD8EzA5E 32 | XJ6UYeN5DDBonHcBdctT0QFYUElILuk9YYIAIT9s2B0UrrXEZhJUfbgafGRbPdkm 33 | E9T21b7fFXDSnATEMkvmht1KR0Sc5eZzeuM+lwDvKNU6dd1QAJmb7e/eqH+B/TYc 34 | FYpIzQjjgwk7mQcY7glj7xEXmixGVJfeTmfMlFvLVIfNlbFZZJdNjnb05Y0sj2nJ 35 | v6dwXjYoePZeR/AyGnxmi8Q5seDaGFO9MuIMJ4hTIjfxtDbl54ImrFhgC4tMEzhY 36 | YTIJIHVc/aQ5GeBKl510iLhzEyxLWD/QidZggjoUStapa6OA/2G8NlAkwfr8sG6W 37 | 6u/QvhuSe36BPJk= 38 | -----END CERTIFICATE-----`) 39 | 40 | testSuite.Key = []byte(`-----BEGIN RSA PRIVATE KEY----- 41 | MIIEpAIBAAKCAQEAqsBCzS06N6nFcE752X9z75nXGthHQDynFe/ExK4+zfe+4E5G 42 | T/10JYHDu3e2HWcvmYFRD/F6j2KrTerwzivyDhKzbJoAskmYay13Lg4rSnKTjy8i 43 | yLOXoXKyF5F0bPe0Mtt7tACMVr7RHWZhj/gFR5WQxFxJnIjPSSP/x9kkak1DHgd1 44 | 5gYYsilTOviaAHZQcJ0Vu4zhY/oaJhiJasrRgz3jSCDA3PAkHZzOpOZSK/T3msNv 45 | HHJF4hwsRRb/gJNIgTNwF0JjV3Q55YVKN6HnYhGCniLsp7bPHfqG7RR38DKr32SH 46 | RJbZVjgB7nGdMahSLLaPz9lsa/8xUUirHh8f1wIDAQABAoIBAC3GRuI8Kqw7bfuS 47 | oHZHLaxg4IKI0mkNGXnPAj/7ukh7DweQ1FajSpy3ceJy0DaHsAIF4dZVVRbVS7ki 48 | r5WFwGk3aDRIAMHK6vpogNeu4rodhyNObpPBWXfliIq66qw/p2Yu4rW5o+WpV+P6 49 | y1LOGZQ8K0gIuY8mOfOQnARWWOXKClM3bccnFCbvvLRCNf3QkEh8JA1lCwJ5dvcs 50 | l7SjkD9p7HJxJNo/xahWlWgLILzSZs7VWAUHpF1qShT6RcdGqN33MmU+D7fvc5Tr 51 | u3AskEaclxwMeTIhrTJ3N/4zRnZbBNwJIGAgWak/JlRNMaFwglTgXlj4lAAjIa3I 52 | XJcEThkCgYEA3iVh04GdvNvfw4hbGyVcwTKlQuJafrDKYdZA3q2lDPvSKzJCAh5N 53 | C3OqYZcYsRX80dEh+bmye4CrDS/aSxwtMA1EOqKlQjzgdxm5eGPyHWP/AdGcrFbf 54 | fzrqRBj8r0Cqroslmey90D1x6nshIu/er5zdupAlFSRkmVfFOMJQwS0CgYEAxMXM 55 | IZ5nHaH6iGXMKcZT8dCigHwSR4vhlU2AwIE2bJP6hKEllekhx22iM30l4AimODd3 56 | MJrHsmkJ2UEXTdyeZXADi3odcXLy1Hcl4OUR60F68DrC0d9ZNXPwJ3junGFZor1Y 57 | 9bBQJJktYLySAT/KE1J6UksSLeqb7BwL4p+i35MCgYEAiTcr+vpIFZz21Y+HPvhQ 58 | F+IRpIOuhCzthYtTHHjDx4ZQpm/vx+Exk85JQuiSzueW938nblpevdyXS5jwTI7F 59 | 9rVrHJDUZVq3B7ozDwMlTTQ0EsqH7QfoG22nwJJymknmY9P9UNujz1n04HJX4H2r 60 | 3muVpiRdU3bcUL+fSdT1Dq0CgYEAqF6LTZTprKxl4AIi0Pf36ijYc1I2neuuKX+4 61 | lH+7nup76LKuo3hpQ+imaqJCH1GnUOD85qT6DMnd+Hy+wQvuqONQ1S63NNTjvTL6 62 | QVYgoAlWdWoCO2x+O8OpkUzj9wFBnoOgNBIacUZ0Uprn35PCiAgBzJqZwppFsqFI 63 | 9jAcQGsCgYAVu+DfUw2xaF72CFxiu/cpfcK9qrLfbC6gOLMIzibZAX9IOcx/3btU 64 | baiFZmT48BdiGH0anFypLetKiSB76XH4khB98dxs3SvLdj/CBxztOto23GNsxC37 65 | KXAfFMiA9duVQ1jSPfku3g5oBdHucFeZKYYmoDl698laWJUzOzzGYA== 66 | -----END RSA PRIVATE KEY----- 67 | `) 68 | 69 | // This is an actual encrypted SAML response we got from testshib.org 70 | testSuite.DocStr = []byte(`https://idp.testshib.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 79 | `) 80 | 81 | testSuite.Plaintext = []byte("https://idp.testshib.org/idp/shibbolethVwEKsGObmOM6y22Nstadwz1fq6dnQ2aDmERPMuEteds=gcROTzJ7HgTu/LQprki8v9J5y4et2np48hYspgmygZRvRawzxfQDgB0MBvDIBG78J5XSd401g7E999JUEh4JtSMAig1THbeWhyITGHU1Vpl2xAR5Ma0vCMLjVIleeuFHhStFBNqKirNfulfhEa7Q5THVGKrVsNuIaP/yc10Gf8AyHfCIOf/ZQGiU3Srp/pKZLXPkSKTEZIq5tAOl+pA0maFBvb4+EkMPB6E66HiXknHL9KdNh8bPcq+EkqjhtHWOy341F8W9iy6MJYGuO9ksxdiY6FK5SqmPHlgoJqXx7Et2vYME6opIgFYB6m1KW6kWgVcF0VyIzJbkXq3yTi0b5g==MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM\nUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG\nA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx\nCzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx\nETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp\nu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT\npSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI\nfJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB\n5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE\nMIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8\n3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET\nMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0\nc2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M\nFfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk\nOAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4\n/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx\npUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW\nj8Bbnl+ev0peYzxFyF5sQA==_5c425656721b41a6cfa4a9c96225e082https://15661444.ngrok.io/saml2/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportmyselfMemberStaffmyself@testshib.orgAnd IMember@testshib.orgStaff@testshib.orgMe Myselfurn:mace:dir:entitlement:common-lib-termsMe Myself And I8F+M9ovyaYNwCId0pVkVsnZYRDo=555-5555") 82 | } 83 | 84 | func (testSuite *EncryptTest) TestEncrypt(c *C) { 85 | encryptedString, err := Encrypt(testSuite.Cert, testSuite.Plaintext, EncryptOptions{}) 86 | c.Assert(err, IsNil) 87 | 88 | actualPlaintext, err := Decrypt(testSuite.Key, encryptedString) 89 | c.Assert(err, IsNil) 90 | 91 | plaintextDoc, _ := newDoc(testSuite.Plaintext, nil) 92 | expectedPlaintext := dumpDoc(plaintextDoc) 93 | 94 | // Big blobs of XML are hard to debug. They are easier to handle when 95 | // each tag is on a line 96 | if false { 97 | actualPlaintext = bytes.Replace(actualPlaintext, []byte("<"), []byte("\n<"), -1) 98 | expectedPlaintext = bytes.Replace(expectedPlaintext, []byte("<"), []byte("\n<"), -1) 99 | ioutil.WriteFile("actual", actualPlaintext, 0644) 100 | ioutil.WriteFile("expected", expectedPlaintext, 0644) 101 | } 102 | 103 | c.Assert(string(expectedPlaintext), Equals, string(actualPlaintext)) 104 | } 105 | -------------------------------------------------------------------------------- /encrypt_realworld_test.go: -------------------------------------------------------------------------------- 1 | package xmlsec 2 | 3 | import ( 4 | "strings" 5 | 6 | . "gopkg.in/check.v1" 7 | ) 8 | 9 | // XmlencRealWorldTest is a test suite that verifies that xmlenc works in 10 | // a real-world scenario where we decrypt real SAML assertions. 11 | type XmlencRealWorldTest struct { 12 | Key []byte 13 | DocStr []byte 14 | ExpectedPlaintext []byte 15 | } 16 | 17 | var _ = Suite(&XmlencRealWorldTest{}) 18 | 19 | func (testSuite *XmlencRealWorldTest) SetUpTest(c *C) { 20 | testSuite.Key = []byte(`-----BEGIN RSA PRIVATE KEY----- 21 | MIICXgIBAAKBgQDU8wdiaFmPfTyRYuFlVPi866WrH/2JubkHzp89bBQopDaLXYxi 22 | 3PTu3O6Q/KaKxMOFBqrInwqpv/omOGZ4ycQ51O9I+Yc7ybVlW94lTo2gpGf+Y/8E 23 | PsVbnZaFutRctJ4dVIp9aQ2TpLiGT0xX1OzBO/JEgq9GzDRf+B+eqSuglwIDAQAB 24 | AoGBAMuy1eN6cgFiCOgBsB3gVDdTKpww87Qk5ivjqEt28SmXO13A1KNVPS6oQ8SJ 25 | CT5Azc6X/BIAoJCURVL+LHdqebogKljhH/3yIel1kH19vr4E2kTM/tYH+qj8afUS 26 | JEmArUzsmmK8ccuNqBcllqdwCZjxL4CHDUmyRudFcHVX9oyhAkEA/OV1OkjM3CLU 27 | N3sqELdMmHq5QZCUihBmk3/N5OvGdqAFGBlEeewlepEVxkh7JnaNXAXrKHRVu/f/ 28 | fbCQxH+qrwJBANeQERF97b9Sibp9xgolb749UWNlAdqmEpmlvmS202TdcaaT1msU 29 | 4rRLiQN3X9O9mq4LZMSVethrQAdX1whawpkCQQDk1yGf7xZpMJ8F4U5sN+F4rLyM 30 | Rq8Sy8p2OBTwzCUXXK+fYeXjybsUUMr6VMYTRP2fQr/LKJIX+E5ZxvcIyFmDAkEA 31 | yfjNVUNVaIbQTzEbRlRvT6MqR+PTCefC072NF9aJWR93JimspGZMR7viY6IM4lrr 32 | vBkm0F5yXKaYtoiiDMzlOQJADqmEwXl0D72ZG/2KDg8b4QZEmC9i5gidpQwJXUc6 33 | hU+IVQoLxRq0fBib/36K9tcrrO5Ba4iEvDcNY+D8yGbUtA== 34 | -----END RSA PRIVATE KEY----- 35 | `) 36 | 37 | // This is an actual encrypted SAML response we got from testshib.org 38 | testSuite.DocStr = []byte(`https://idp.testshib.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 47 | `) 48 | testSuite.ExpectedPlaintext = []byte("" + 49 | "\n" + 50 | "https://idp.testshib.org/idp/shibbolethhttps://idp.testshib.org/idp/shibbolethVwEKsGObmOM6y22Nstadwz1fq6dnQ2aDmERPMuEteds=gcROTzJ7HgTu/LQprki8v9J5y4et2np48hYspgmygZRvRawzxfQDgB0MBvDIBG78J5XSd401g7E999JUEh4JtSMAig1THbeWhyITGHU1Vpl2xAR5Ma0vCMLjVIleeuFHhStFBNqKirNfulfhEa7Q5THVGKrVsNuIaP/yc10Gf8AyHfCIOf/ZQGiU3Srp/pKZLXPkSKTEZIq5tAOl+pA0maFBvb4+EkMPB6E66HiXknHL9KdNh8bPcq+EkqjhtHWOy341F8W9iy6MJYGuO9ksxdiY6FK5SqmPHlgoJqXx7Et2vYME6opIgFYB6m1KW6kWgVcF0VyIzJbkXq3yTi0b5g==MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM\n" + 51 | "UGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG\n" + 52 | "A1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx\n" + 53 | "CzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx\n" + 54 | "ETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG\n" + 55 | "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp\n" + 56 | "u93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT\n" + 57 | "pSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI\n" + 58 | "fJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB\n" + 59 | "5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE\n" + 60 | "MIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8\n" + 61 | "3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET\n" + 62 | "MBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0\n" + 63 | "c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M\n" + 64 | "FfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk\n" + 65 | "OAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4\n" + 66 | "/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx\n" + 67 | "pUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW\n" + 68 | "j8Bbnl+ev0peYzxFyF5sQA==_5c425656721b41a6cfa4a9c96225e082https://15661444.ngrok.io/saml2/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportmyselfMemberStaffmyself@testshib.orgAnd IMember@testshib.orgStaff@testshib.orgMe Myselfurn:mace:dir:entitlement:common-lib-termsMe Myself And I8F+M9ovyaYNwCId0pVkVsnZYRDo=555-5555\n") 69 | } 70 | 71 | func (testSuite *XmlencRealWorldTest) TestDecrypt(c *C) { 72 | actualPlaintextString, err := Decrypt(testSuite.Key, testSuite.DocStr) 73 | c.Assert(err, IsNil) 74 | c.Assert(string(actualPlaintextString), Equals, string(testSuite.ExpectedPlaintext)) 75 | } 76 | 77 | func (testSuite *XmlencRealWorldTest) TestDecryptWithPadding(c *C) { 78 | // This docStr has two bytes of padding, make sure they are removed off 79 | docStr := []byte(`https://idp.testshib.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`) 88 | actualPlaintextString, err := Decrypt(testSuite.Key, docStr) 89 | c.Assert(err, IsNil) 90 | c.Assert(strings.HasSuffix(string(actualPlaintextString), "\n"), Equals, true) 91 | } 92 | 93 | func (testSuite *XmlencRealWorldTest) TestInvalid(c *C) { 94 | _, err := Decrypt(testSuite.Key, testSuite.DocStr) 95 | c.Assert(err, IsNil) 96 | 97 | _, err = Decrypt(testSuite.Key, []byte("")) 101 | c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node") 102 | 103 | _, err = Decrypt([]byte("XXX"), testSuite.DocStr) 104 | c.Assert(err, ErrorMatches, "func=xmlSecOpenSSLAppKeyLoadBIO:.*") 105 | 106 | docStr := []byte(`https://idp.testshib.org/idp/shibbolethinvalid<`) 107 | _, err = Decrypt(testSuite.Key, docStr) 108 | c.Assert(err, ErrorMatches, ".*Premature end of data in tag.*") 109 | 110 | docStr = []byte(` 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | MIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzELMAkGA1UECAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTEzMTAwMjAwMDg1MVoXDTE0MTAwMjAwMDg1MVowPDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkdBMQwwCgYDVQQKDANmb28xEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1PMHYmhZj308kWLhZVT4vOulqx/9ibm5B86fPWwUKKQ2i12MYtz07tzukPymisTDhQaqyJ8Kqb/6JjhmeMnEOdTvSPmHO8m1ZVveJU6NoKRn/mP/BD7FW52WhbrUXLSeHVSKfWkNk6S4hk9MV9TswTvyRIKvRsw0X/gfnqkroJcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCMMlIO+GNcGekevKgkakpMdAqJfs24maGb90DvTLbRZRD7Xvn1MnVBBS9hzlXiFLYOInXACMW5gcoRFfeTQLSouMM8o57h0uKjfTmuoWHLQLi6hnF+cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvnOwJlNCASPZRH/JmF8tX0hoHuAQ== 122 | 123 | 124 | 125 | 0grSplyWOao1tEshQRtSsQqcl8lKTOqg/AR+U2Dh/1ACl0nZcv18De8U0iySrKSHQNaWcm2YpvBGUMddf4yKn40eVvmNoqElJVgOIhc5rPykua2AEyt2ShXOpFaCtXindqyax1IxxyJi+6o62swx+Q5pIy3YDaFN6/lNCgSdLak= 126 | 127 | 128 | 129 | 130 | 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 131 | 132 | 133 | 134 | `) 135 | _, err = Decrypt(testSuite.Key, docStr) 136 | c.Assert(err, IsNil) 137 | 138 | docStr = []byte(` 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | ??MIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzELMAkGA1UECAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTEzMTAwMjAwMDg1MVoXDTE0MTAwMjAwMDg1MVowPDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkdBMQwwCgYDVQQKDANmb28xEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1PMHYmhZj308kWLhZVT4vOulqx/9ibm5B86fPWwUKKQ2i12MYtz07tzukPymisTDhQaqyJ8Kqb/6JjhmeMnEOdTvSPmHO8m1ZVveJU6NoKRn/mP/BD7FW52WhbrUXLSeHVSKfWkNk6S4hk9MV9TswTvyRIKvRsw0X/gfnqkroJcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCMMlIO+GNcGekevKgkakpMdAqJfs24maGb90DvTLbRZRD7Xvn1MnVBBS9hzlXiFLYOInXACMW5gcoRFfeTQLSouMM8o57h0uKjfTmuoWHLQLi6hnF+cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvnOwJlNCASPZRH/JmF8tX0hoHuAQ== 150 | 151 | 152 | 153 | 0g??rSplyWOao1tEshQRtSsQqcl8lKTOqg/AR+U2Dh/1ACl0nZcv18De8U0iySrKSHQNaWcm2YpvBGUMddf4yKn40eVvmNoqElJVgOIhc5rPykua2AEyt2ShXOpFaCtXindqyax1IxxyJi+6o62swx+Q5pIy3YDaFN6/lNCgSdLak= 154 | 155 | 156 | 157 | 158 | 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 159 | 160 | 161 | 162 | `) 163 | _, err = Decrypt(testSuite.Key, docStr) 164 | c.Assert(err, ErrorMatches, "func=xmlSecBase64CtxDecodeByte.*") 165 | 166 | docStr = []byte(` 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | MIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzELMAkGA1UECAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTEzMTAwMjAwMDg1MVoXDTE0MTAwMjAwMDg1MVowPDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkdBMQwwCgYDVQQKDANmb28xEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1PMHYmhZj308kWLhZVT4vOulqx/9ibm5B86fPWwUKKQ2i12MYtz07tzukPymisTDhQaqyJ8Kqb/6JjhmeMnEOdTvSPmHO8m1ZVveJU6NoKRn/mP/BD7FW52WhbrUXLSeHVSKfWkNk6S4hk9MV9TswTvyRIKvRsw0X/gfnqkroJcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCMMlIO+GNcGekevKgkakpMdAqJfs24maGb90DvTLbRZRD7Xvn1MnVBBS9hzlXiFLYOInXACMW5gcoRFfeTQLSouMM8o57h0uKjfTmuoWHLQLi6hnF+cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvnOwJlNCASPZRH/JmF8tX0hoHuAQ== 178 | 179 | 180 | 181 | 0grSplyWOao1tEshQRtSsQqcl8lKTOqg/AR+U2Dh/1ACl0nZcv18De8U0iySrKSHQNaWcm2YpvBGUMddf4yKn40eVvmNoqElJVgOIhc5rPykua2AEyt2ShXOpFaCtXindqyax1IxxyJi+6o62swx+Q5pIy3YDaFN6/lNCgSdLak= 182 | 183 | 184 | 185 | 186 | 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 187 | 188 | 189 | 190 | `) 191 | _, err = Decrypt(testSuite.Key, docStr) 192 | c.Assert(err, ErrorMatches, ".*name=EncryptionMethod.*") 193 | } 194 | --------------------------------------------------------------------------------