On Fedora 25, tests fail with error func=xmlSecCryptoAppInit:file=app.c:line=1423: obj=unknown:subj=cryptoAppInit:error=9: feature is not implemented: panic: xmlsec crypto initialization failed. This appears to be because the pkg-config files set the wrong CFLAGS defines for cgo, which results in runtime breakage beacuse OpenSSL isn't properly loaded. In order to fix how Fedora sets up these packages we want defines XMLSEC_CRYPTO_OPENSSL set, XMLSEC_CRYPTO_DYNAMIC_LOADING unset and we want to force linking with xmlsec1-openssl. This change puts these in cgo directives. We also fix a test which now has some off-by-one line number changes in the error message.
113 lines
2.7 KiB
Go
113 lines
2.7 KiB
Go
package xmlsec
|
|
|
|
import "unsafe"
|
|
|
|
// Note: on mac you need:
|
|
// brew install libxmlsec1 libxml2
|
|
// brew link libxml2 --force
|
|
|
|
// #cgo CFLAGS: -DXMLSEC_CRYPTO_OPENSSL -UXMLSEC_CRYPTO_DYNAMIC_LOADING
|
|
// #cgo LDFLAGS: -lxmlsec1-openssl
|
|
// #include <xmlsec/xmlsec.h>
|
|
// #include <xmlsec/xmltree.h>
|
|
// #include <xmlsec/xmlenc.h>
|
|
// #include <xmlsec/errors.h>
|
|
// #include <xmlsec/templates.h>
|
|
// #include <xmlsec/crypto.h>
|
|
import "C"
|
|
|
|
// #include <libxml/parser.h>
|
|
// #include <libxml/parserInternals.h>
|
|
// #include <libxml/xmlmemory.h>
|
|
//
|
|
// // xmlFree is a macro, so we need to wrap it in order to be able to call
|
|
// // it from go code.
|
|
// static inline void MY_xmlFree(void *p) {
|
|
// xmlFree(p);
|
|
// }
|
|
import "C"
|
|
|
|
func init() {
|
|
C.xmlInitParser()
|
|
|
|
if rv := C.xmlSecInit(); rv < 0 {
|
|
panic("xmlsec failed to initialize")
|
|
}
|
|
if rv := C.xmlSecCryptoAppInit(nil); rv < 0 {
|
|
panic("xmlsec crypto initialization failed.")
|
|
}
|
|
if rv := C.xmlSecCryptoInit(); rv < 0 {
|
|
panic("xmlsec crypto initialization failed.")
|
|
}
|
|
}
|
|
|
|
func newDoc(buf []byte, idattrs []XMLIDOption) (*C.xmlDoc, error) {
|
|
ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])),
|
|
C.int(len(buf)))
|
|
if ctx == nil {
|
|
return nil, mustPopError()
|
|
}
|
|
defer C.xmlFreeParserCtxt(ctx)
|
|
|
|
C.xmlParseDocument(ctx)
|
|
|
|
if ctx.wellFormed == C.int(0) {
|
|
return nil, mustPopError()
|
|
}
|
|
|
|
doc := ctx.myDoc
|
|
if doc == nil {
|
|
return nil, mustPopError()
|
|
}
|
|
|
|
for _, idattr := range idattrs {
|
|
addIDAttr(C.xmlDocGetRootElement(doc),
|
|
idattr.AttributeName, idattr.ElementName, idattr.ElementNamespace)
|
|
}
|
|
return doc, nil
|
|
}
|
|
|
|
func addIDAttr(node *C.xmlNode, attrName, nodeName, nsHref string) {
|
|
// process children first because it does not matter much but does simplify code
|
|
cur := C.xmlSecGetNextElementNode(node.children)
|
|
for {
|
|
if cur == nil {
|
|
break
|
|
}
|
|
addIDAttr(cur, attrName, nodeName, nsHref)
|
|
cur = C.xmlSecGetNextElementNode(cur.next)
|
|
}
|
|
|
|
if C.GoString((*C.char)(unsafe.Pointer(node.name))) != nodeName {
|
|
return
|
|
}
|
|
if nsHref != "" && node.ns != nil && C.GoString((*C.char)(unsafe.Pointer(node.ns.href))) != nsHref {
|
|
return
|
|
}
|
|
|
|
// the attribute with name equal to attrName should exist
|
|
for attr := node.properties; attr != nil; attr = attr.next {
|
|
if C.GoString((*C.char)(unsafe.Pointer(attr.name))) == attrName {
|
|
id := C.xmlNodeListGetString(node.doc, attr.children, 1)
|
|
if id == nil {
|
|
continue
|
|
}
|
|
C.xmlAddID(nil, node.doc, id, attr)
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
func closeDoc(doc *C.xmlDoc) {
|
|
C.xmlFreeDoc(doc)
|
|
}
|
|
|
|
func dumpDoc(doc *C.xmlDoc) []byte {
|
|
var buffer *C.xmlChar
|
|
var bufferSize C.int
|
|
C.xmlDocDumpMemory(doc, &buffer, &bufferSize)
|
|
defer C.MY_xmlFree(unsafe.Pointer(buffer))
|
|
|
|
return C.GoBytes(unsafe.Pointer(buffer), bufferSize)
|
|
}
|