xmlsec is a Go binding for XML Security Library (https://www.aleksey.com/xmlsec/index.html)
- API still unstable.
- There's enough code to generate signatures for a libxml2 Document, and to verify it, but not much else.
- PRs, suggestions for more coverage welcome.
import (
"crypto/rand""crypto/rsa""crypto/x509""encoding/pem""io/ioutil""log""os""github.com/lestrrat-go/libxml2/parser""github.com/lestrrat-go/xmlsec""github.com/lestrrat-go/xmlsec/crypto""github.com/lestrrat-go/xmlsec/dsig"
)
funcExampleSignature_Sign() {
xmlsec.Init()
deferxmlsec.Shutdown()
p:=parser.New(parser.XMLParseDTDLoad|parser.XMLParseDTDAttr|parser.XMLParseNoEnt)
doc, err:=p.ParseString(`<?xml version="1.0" encoding="UTF-8"?><Message><Data>Hello, World!</Data></Message>`)
n, err:=doc.DocumentElement()
iferr!=nil {
log.Printf("DocumentElement failed: %s", err)
return
}
// n is the node where you want your signature to be// generated undersig, err:=dsig.NewSignature(n, dsig.ExclC14N, dsig.RsaSha1, "")
iferr!=nil {
log.Printf("failed to create signature: %s", err)
return
}
sig.AddReference(dsig.Sha1, "", "", "")
sig.AddTransform(dsig.Enveloped)
key, err:=rsa.GenerateKey(rand.Reader, 2048)
iferr!=nil {
log.Printf("failed to generate key: %s", err)
return
}
iferr:=sig.Sign(key); err!=nil {
log.Printf("failed to sign: %s", err)
return
}
log.Printf("%s", doc.Dump(true))
}
funcExampleDSigCtx_Sign() {
xmlsec.Init()
deferxmlsec.Shutdown()
ctx, err:=dsig.NewCtx()
iferr!=nil {
log.Printf("Failed to create signature context: %s", err)
return
}
deferctx.Free()
// This stuff isn't necessary if you already have a key fileprivkey, err:=rsa.GenerateKey(rand.Reader, 2048)
iferr!=nil {
log.Printf("Failed to generate private key: %s", err)
return
}
varpemkey=&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privkey),
}
pemfile, err:=ioutil.TempFile("", "xmlsec-test-")
iferr!=nil {
log.Printf("Failed to create temporary pemfile")
return
}
deferos.Remove(pemfile.Name())
deferpemfile.Close()
iferr:=pem.Encode(pemfile, pemkey); err!=nil {
log.Printf("Failed to write to pemfile: %s", err)
return
}
iferr:=pemfile.Sync(); err!=nil {
log.Printf("Failed to sync pemfile: %s", err)
return
}
key, err:=crypto.LoadKeyFromFile(pemfile.Name(), crypto.KeyDataFormatPem)
iferr!=nil {
log.Printf("Faild to load key: %s", err)
return
}
ctx.SetKey(key)
p:=parser.New(parser.XMLParseDTDLoad|parser.XMLParseDTDAttr|parser.XMLParseNoEnt)
doc, err:=p.ParseString(`<?xml version="1.0" encoding="UTF-8"?><!-- XML Security Library example: Simple signature template file for sign1 example. --><Envelope xmlns="urn:envelope"> <Data> Hello, World! </Data> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <Reference URI=""> <Transforms> <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <DigestValue></DigestValue> </Reference> </SignedInfo> <SignatureValue/> <KeyInfo> <KeyName/> </KeyInfo> </Signature></Envelope>`)
iferr!=nil {
log.Printf("Failed to parse source XML: %s", err)
return
}
deferdoc.Free()
iferr:=ctx.Sign(doc); err!=nil {
log.Printf("Failed to sign document: %s", err)
return
}
log.Printf("%s", doc.Dump(true))
}cgo and pkg-config sometimes have problems with quoting. For example, on my local machine (OS X 10.10.5 + go 1.5.1), I get this:
shoebill% go test .
# github.com/lestrrat-go/xmlsec
In file included from <built-in>:326:
<command line>:1:24: warning: missing terminating '"' character [-Winvalid-pp-token]
If it annoys you, explicitly specifying #cgo CFLAGS: and #cgo LDFLAGS: may help,
but we don't do that in this library because it makes it unportable.
- Work on this library was generously sponsored by HDE Inc (https://www.hde.co.jp)