capture errors from libxml2

fixes #4
This commit is contained in:
Ross Kinder
2015-12-23 17:17:48 -05:00
parent c095422255
commit dc37ddb368
6 changed files with 48 additions and 25 deletions

View File

@@ -139,7 +139,7 @@ func (testSuite *DecryptTest) TestInvalid(c *C) {
c.Assert(err, IsNil) c.Assert(err, IsNil)
_, err = Decrypt(testSuite.Key, []byte("<invalid xml")) _, err = Decrypt(testSuite.Key, []byte("<invalid xml"))
c.Assert(err, ErrorMatches, "malformed XML") c.Assert(err, ErrorMatches, ".*Couldn't find end of Start Tag.*")
_, err = Decrypt(testSuite.Key, []byte("<invalid></invalid>")) _, err = Decrypt(testSuite.Key, []byte("<invalid></invalid>"))
c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node") c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node")
@@ -149,7 +149,7 @@ func (testSuite *DecryptTest) TestInvalid(c *C) {
docStr = []byte(`<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://15661444.ngrok.io/saml2/acs" ID="_59c2431b4916af2018984213940ee675" InResponseTo="id-3d21faf29a101222d740735fa512f161" IssueInstant="2015-11-29T21:29:09.991Z" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://idp.testshib.org/idp/shibboleth</saml2:Issuer><saml2p:Status><saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_62d64ca491a287a346272669fbe93191" Type="http://www.w3.org/2001/04/xmlenc#Element">invalid<`) docStr = []byte(`<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://15661444.ngrok.io/saml2/acs" ID="_59c2431b4916af2018984213940ee675" InResponseTo="id-3d21faf29a101222d740735fa512f161" IssueInstant="2015-11-29T21:29:09.991Z" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://idp.testshib.org/idp/shibboleth</saml2:Issuer><saml2p:Status><saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_62d64ca491a287a346272669fbe93191" Type="http://www.w3.org/2001/04/xmlenc#Element">invalid<`)
_, err = Decrypt(testSuite.Key, docStr) _, err = Decrypt(testSuite.Key, docStr)
c.Assert(err, ErrorMatches, "malformed XML") c.Assert(err, ErrorMatches, ".*Premature end of data in tag.*")
docStr = []byte(`<?xml version="1.0" encoding="UTF-8"?> docStr = []byte(`<?xml version="1.0" encoding="UTF-8"?>
<X> <X>

View File

@@ -95,7 +95,7 @@ func (testSuite *XmlencRealWorldTest) TestInvalid(c *C) {
c.Assert(err, IsNil) c.Assert(err, IsNil)
_, err = Decrypt(testSuite.Key, []byte("<invalid xml")) _, err = Decrypt(testSuite.Key, []byte("<invalid xml"))
c.Assert(err, ErrorMatches, "malformed XML") c.Assert(err, ErrorMatches, ".*Couldn't find end of Start Tag.*")
_, err = Decrypt(testSuite.Key, []byte("<invalid></invalid>")) _, err = Decrypt(testSuite.Key, []byte("<invalid></invalid>"))
c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node") c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node")
@@ -105,7 +105,7 @@ func (testSuite *XmlencRealWorldTest) TestInvalid(c *C) {
docStr := []byte(`<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://15661444.ngrok.io/saml2/acs" ID="_59c2431b4916af2018984213940ee675" InResponseTo="id-3d21faf29a101222d740735fa512f161" IssueInstant="2015-11-29T21:29:09.991Z" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://idp.testshib.org/idp/shibboleth</saml2:Issuer><saml2p:Status><saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_62d64ca491a287a346272669fbe93191" Type="http://www.w3.org/2001/04/xmlenc#Element">invalid<`) docStr := []byte(`<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://15661444.ngrok.io/saml2/acs" ID="_59c2431b4916af2018984213940ee675" InResponseTo="id-3d21faf29a101222d740735fa512f161" IssueInstant="2015-11-29T21:29:09.991Z" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://idp.testshib.org/idp/shibboleth</saml2:Issuer><saml2p:Status><saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_62d64ca491a287a346272669fbe93191" Type="http://www.w3.org/2001/04/xmlenc#Element">invalid<`)
_, err = Decrypt(testSuite.Key, docStr) _, err = Decrypt(testSuite.Key, docStr)
c.Assert(err, ErrorMatches, "malformed XML") c.Assert(err, ErrorMatches, ".*Premature end of data in tag.*")
docStr = []byte(`<?xml version="1.0" encoding="UTF-8"?> docStr = []byte(`<?xml version="1.0" encoding="UTF-8"?>
<X> <X>

View File

@@ -4,6 +4,7 @@ import (
"C" "C"
"fmt" "fmt"
"runtime" "runtime"
"strings"
"github.com/crewjam/errset" "github.com/crewjam/errset"
) )
@@ -32,8 +33,8 @@ func (e libraryError) Error() string {
e.Message) e.Message)
} }
//export onError //export onXmlsecError
func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, errorSubject *C.char, reason C.int, msg *C.char) { func onXmlsecError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, errorSubject *C.char, reason C.int, msg *C.char) {
err := libraryError{ err := libraryError{
FuncName: C.GoString(funcName), FuncName: C.GoString(funcName),
FileName: C.GoString(file), FileName: C.GoString(file),
@@ -46,6 +47,13 @@ func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, er
globalErrors[threadID] = append(globalErrors[threadID], err) globalErrors[threadID] = append(globalErrors[threadID], err)
} }
//export onXmlError
func onXmlError(msg *C.char) {
threadID := getThreadID()
globalErrors[threadID] = append(globalErrors[threadID],
fmt.Errorf("%s", strings.TrimSuffix(C.GoString(msg), "\n")))
}
// startProcessingXML is called whenever we enter a function exported by this package. // startProcessingXML is called whenever we enter a function exported by this package.
// It locks the current goroutine to the current thread and establishes a thread-local // It locks the current goroutine to the current thread and establishes a thread-local
// error object. If the library later calls onError then the error will be appended // error object. If the library later calls onError then the error will be appended

View File

@@ -1,13 +1,31 @@
package xmlsec package xmlsec
// onError_cgo is a C function that can be passed to xmlSecErrorsSetCallback which // #include <stdio.h>
// in turn invokes the go function onError which captures errors generated by // #include <stdarg.h>
// libxmlsec. // #include <libxml/parser.h>
// #include <libxml/parserInternals.h>
// #include <libxml/xmlmemory.h>
// #include <xmlsec/xmlsec.h>
// #include <xmlsec/errors.h>
// //
// For reasons I do not completely understand, it must be defined in a different // void onXmlError(const char *msg); // implemented in go
// file from onError. // void onXmlsecError(const char *file, int line, const char *funcName, const char *errorObject, const char *errorSubject, int reason, const char *msg); // implemented in go
//
// void onError_cgo(char *file, int line, char *funcName, char *errorObject, char *errorSubject, int reason, char *msg) { // static void onXmlGenericError_cgo(void *ctx, const char *format, ...) {
// onError(file, line, funcName, errorObject, errorSubject, reason, msg); // char buffer[256];
// va_list args;
// va_start(args, format);
// vsnprintf(buffer, 256, format, args);
// va_end (args);
// 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) {
// onXmlsecError(file, line, funcName, errorObject, errorSubject, reason, msg);
// }
//
// void captureXmlErrors() {
// xmlSecErrorsSetCallback(onXmlsecError_cgo);
// xmlSetGenericErrorFunc(NULL, onXmlGenericError_cgo);
// } // }
import "C" import "C"

View File

@@ -218,7 +218,7 @@ func (testSuite *XMLDSigTest) TestVerifyFailsWhenMessageModified(c *C) {
func (testSuite *XMLDSigTest) TestInvalidXML(c *C) { func (testSuite *XMLDSigTest) TestInvalidXML(c *C) {
_, err := Sign(testSuite.Key, []byte("<invalid xml"), SignatureOptions{}) _, err := Sign(testSuite.Key, []byte("<invalid xml"), SignatureOptions{})
c.Assert(err, ErrorMatches, "malformed XML") c.Assert(err, ErrorMatches, ".*Couldn't find end of Start Tag.*")
_, err = Sign(testSuite.Key, []byte("<invalid></invalid>"), SignatureOptions{}) _, err = Sign(testSuite.Key, []byte("<invalid></invalid>"), SignatureOptions{})
c.Assert(err, ErrorMatches, "cannot find start node") c.Assert(err, ErrorMatches, "cannot find start node")
@@ -227,7 +227,7 @@ func (testSuite *XMLDSigTest) TestInvalidXML(c *C) {
c.Assert(err, ErrorMatches, "failed to load pem key") c.Assert(err, ErrorMatches, "failed to load pem key")
err = Verify(testSuite.Cert, []byte("<invalid xml"), SignatureOptions{}) err = Verify(testSuite.Cert, []byte("<invalid xml"), SignatureOptions{})
c.Assert(err, ErrorMatches, "malformed XML") c.Assert(err, ErrorMatches, ".*Couldn't find end of Start Tag.*")
err = Verify(testSuite.Cert, []byte("<invalid></invalid>"), SignatureOptions{}) err = Verify(testSuite.Cert, []byte("<invalid></invalid>"), SignatureOptions{})
c.Assert(err, ErrorMatches, "cannot find start node") c.Assert(err, ErrorMatches, "cannot find start node")

View File

@@ -1,9 +1,6 @@
package xmlsec package xmlsec
import ( import "unsafe"
"errors"
"unsafe"
)
// Note: on mac you need: // Note: on mac you need:
// brew install libxmlsec1 libxml2 // brew install libxmlsec1 libxml2
@@ -30,7 +27,7 @@ import "C"
// } // }
import "C" import "C"
// void onError_cgo(char *file, int line, char *funcName, char *errorObject, char *errorSubject, int reason, char *msg); // void captureXmlErrors();
import "C" import "C"
func init() { func init() {
@@ -46,26 +43,26 @@ func init() {
panic("xmlsec crypto initialization failed.") panic("xmlsec crypto initialization failed.")
} }
C.xmlSecErrorsSetCallback((C.xmlSecErrorsCallback)(unsafe.Pointer(C.onError_cgo))) C.captureXmlErrors()
} }
func newDoc(buf []byte, idattrs []XMLIDOption) (*C.xmlDoc, error) { func newDoc(buf []byte, idattrs []XMLIDOption) (*C.xmlDoc, error) {
ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])), ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])),
C.int(len(buf))) C.int(len(buf)))
if ctx == nil { if ctx == nil {
return nil, errors.New("error creating parser") return nil, mustPopError()
} }
defer C.xmlFreeParserCtxt(ctx) defer C.xmlFreeParserCtxt(ctx)
C.xmlParseDocument(ctx) C.xmlParseDocument(ctx)
if ctx.wellFormed == C.int(0) { if ctx.wellFormed == C.int(0) {
return nil, errors.New("malformed XML") return nil, mustPopError()
} }
doc := ctx.myDoc doc := ctx.myDoc
if doc == nil { if doc == nil {
return nil, errors.New("parse failed") return nil, mustPopError()
} }
for _, idattr := range idattrs { for _, idattr := range idattrs {