clean up, add documentation, fix lint errors
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
coverage.html
|
||||||
|
coverage.out
|
||||||
@@ -8,3 +8,8 @@ addons:
|
|||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.5
|
- 1.5
|
||||||
|
|
||||||
|
script:
|
||||||
|
- golint *.go
|
||||||
|
- go vet ./...
|
||||||
|
- go test -v ./...
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ import "C"
|
|||||||
// #include <libxml/xmlmemory.h>
|
// #include <libxml/xmlmemory.h>
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func DecryptXML(privateKey []byte, doc []byte) ([]byte, error) {
|
// Decrypt finds the first encrypted part of doc, decrypts it using
|
||||||
|
// privateKey and returns the plaintext of the embedded document.
|
||||||
|
func Decrypt(privateKey []byte, doc []byte) ([]byte, error) {
|
||||||
startProcessingXML()
|
startProcessingXML()
|
||||||
defer stopProcessingXML()
|
defer stopProcessingXML()
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
131
encrypt.go
131
encrypt.go
@@ -21,44 +21,87 @@ package xmlsec
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SessionCipherType represents which session cipher to use to encrypt the document.
|
||||||
|
type SessionCipherType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultAlgorithm = iota
|
// DefaultSessionCipher (the zero value) represents the default session cipher, AES256-CBC
|
||||||
|
DefaultSessionCipher SessionCipherType = iota
|
||||||
|
|
||||||
|
// Aes128Cbc means the session cipher should be AES-128 in CBC mode.
|
||||||
Aes128Cbc
|
Aes128Cbc
|
||||||
|
|
||||||
|
// Aes192Cbc means the session cipher should be AES-192 in CBC mode.
|
||||||
Aes192Cbc
|
Aes192Cbc
|
||||||
|
|
||||||
|
// Aes256Cbc means the session cipher should be AES-256 in CBC mode.
|
||||||
Aes256Cbc
|
Aes256Cbc
|
||||||
|
|
||||||
|
// Des3Cbc means the session cipher should be triple DES in CBC mode.
|
||||||
Des3Cbc
|
Des3Cbc
|
||||||
DsaSha1
|
)
|
||||||
Sha1
|
|
||||||
Sha256
|
// CipherType represent which cipher to use to encrypt the document
|
||||||
Sha384
|
type CipherType int
|
||||||
Sha512
|
|
||||||
|
const (
|
||||||
|
// DefaultCipher (the zero value) represents the default cipher, RSA-OAEP
|
||||||
|
DefaultCipher CipherType = iota
|
||||||
|
|
||||||
|
// RsaOaep means the cipher should be RSA-OAEP
|
||||||
RsaOaep
|
RsaOaep
|
||||||
|
|
||||||
|
// RsaPkcs1 means the cipher should be RSA-PKCS1
|
||||||
RsaPkcs1
|
RsaPkcs1
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
// DigestAlgorithmType represent which digest algorithm to use when encrypting the document.
|
||||||
SessionCipher int
|
type DigestAlgorithmType int
|
||||||
Cipher int
|
|
||||||
DigestAlgorithm int
|
const (
|
||||||
|
// DefaultDigestAlgorithm (the zero value) represents the default cipher, SHA1
|
||||||
|
DefaultDigestAlgorithm DigestAlgorithmType = iota
|
||||||
|
|
||||||
|
// Sha1 means the digest algorithm should be SHA-1
|
||||||
|
Sha1
|
||||||
|
|
||||||
|
// Sha256 means the digest algorithm should be SHA-256
|
||||||
|
Sha256
|
||||||
|
|
||||||
|
// Sha384 means the digest algorithm should be SHA-384
|
||||||
|
Sha384
|
||||||
|
|
||||||
|
// Sha512 means the digest algorithm should be SHA-512
|
||||||
|
Sha512
|
||||||
|
)
|
||||||
|
|
||||||
|
// EncryptOptions specifies the ciphers to use to encrypt the document.
|
||||||
|
type EncryptOptions struct {
|
||||||
|
SessionCipher SessionCipherType
|
||||||
|
Cipher CipherType
|
||||||
|
DigestAlgorithm DigestAlgorithmType
|
||||||
}
|
}
|
||||||
|
|
||||||
// XmlEncrypt encrypts the XML document to publicKey.
|
var errInvalidAlgorithm = errors.New("invalid algorithm")
|
||||||
func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|
||||||
|
// Encrypt encrypts the XML document to publicKey and returns the encrypted
|
||||||
|
// document.
|
||||||
|
func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) {
|
||||||
startProcessingXML()
|
startProcessingXML()
|
||||||
defer stopProcessingXML()
|
defer stopProcessingXML()
|
||||||
|
|
||||||
keysMngr := C.xmlSecKeysMngrCreate()
|
keysMngr := C.xmlSecKeysMngrCreate()
|
||||||
if keysMngr == nil {
|
if keysMngr == nil {
|
||||||
return nil, fmt.Errorf("xmlSecKeysMngrCreate failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
defer C.xmlSecKeysMngrDestroy(keysMngr)
|
defer C.xmlSecKeysMngrDestroy(keysMngr)
|
||||||
|
|
||||||
if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 {
|
if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 {
|
||||||
return nil, fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrInit failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
key := C.xmlSecCryptoAppKeyLoadMemory(
|
key := C.xmlSecCryptoAppKeyLoadMemory(
|
||||||
@@ -67,7 +110,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
C.xmlSecKeyDataFormatCertPem,
|
C.xmlSecKeyDataFormatCertPem,
|
||||||
nil, nil, nil)
|
nil, nil, nil)
|
||||||
if key == nil {
|
if key == nil {
|
||||||
return nil, fmt.Errorf("xmlSecCryptoAppKeyLoadMemory failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key,
|
if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key,
|
||||||
@@ -75,11 +118,11 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
C.xmlSecSize(len(publicKey)),
|
C.xmlSecSize(len(publicKey)),
|
||||||
C.xmlSecKeyDataFormatCertPem); rv < 0 {
|
C.xmlSecKeyDataFormatCertPem); rv < 0 {
|
||||||
C.xmlSecKeyDestroy(key)
|
C.xmlSecKeyDestroy(key)
|
||||||
return nil, fmt.Errorf("xmlSecCryptoAppKeyCertLoad failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 {
|
if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 {
|
||||||
return nil, fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrAdoptKey failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedDoc, err := newDoc(doc)
|
parsedDoc, err := newDoc(doc)
|
||||||
@@ -90,7 +133,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
|
|
||||||
var sessionCipherTransform C.xmlSecTransformId
|
var sessionCipherTransform C.xmlSecTransformId
|
||||||
switch opts.SessionCipher {
|
switch opts.SessionCipher {
|
||||||
case DefaultAlgorithm:
|
case DefaultSessionCipher:
|
||||||
sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId()
|
sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId()
|
||||||
case Aes256Cbc:
|
case Aes256Cbc:
|
||||||
sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId()
|
sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId()
|
||||||
@@ -101,7 +144,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
case Des3Cbc:
|
case Des3Cbc:
|
||||||
sessionCipherTransform = C.MY_xmlSecTransformDes3CbcId()
|
sessionCipherTransform = C.MY_xmlSecTransformDes3CbcId()
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("XXX")
|
return nil, errInvalidAlgorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
// create encryption template to encrypt XML file and replace
|
// create encryption template to encrypt XML file and replace
|
||||||
@@ -109,7 +152,7 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
encDataNode := C.xmlSecTmplEncDataCreate(parsedDoc, sessionCipherTransform,
|
encDataNode := C.xmlSecTmplEncDataCreate(parsedDoc, sessionCipherTransform,
|
||||||
nil, (*C.xmlChar)(unsafe.Pointer(&C.xmlSecTypeEncElement)), nil, nil)
|
nil, (*C.xmlChar)(unsafe.Pointer(&C.xmlSecTypeEncElement)), nil, nil)
|
||||||
if encDataNode == nil {
|
if encDataNode == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplEncDataCreate failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if encDataNode != nil {
|
if encDataNode != nil {
|
||||||
@@ -120,19 +163,19 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
|
|
||||||
// we want to put encrypted data in the <enc:CipherValue/> node
|
// we want to put encrypted data in the <enc:CipherValue/> node
|
||||||
if C.xmlSecTmplEncDataEnsureCipherValue(encDataNode) == nil {
|
if C.xmlSecTmplEncDataEnsureCipherValue(encDataNode) == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureCipherValue failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// add <dsig:KeyInfo/>
|
// add <dsig:KeyInfo/>
|
||||||
keyInfoNode := C.xmlSecTmplEncDataEnsureKeyInfo(encDataNode, nil)
|
keyInfoNode := C.xmlSecTmplEncDataEnsureKeyInfo(encDataNode, nil)
|
||||||
if keyInfoNode == nil {
|
if keyInfoNode == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureKeyInfo failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// add <enc:EncryptedKey/> to store the encrypted session key
|
// add <enc:EncryptedKey/> to store the encrypted session key
|
||||||
var cipherTransform C.xmlSecTransformId
|
var cipherTransform C.xmlSecTransformId
|
||||||
switch opts.Cipher {
|
switch opts.Cipher {
|
||||||
case DefaultAlgorithm:
|
case DefaultCipher:
|
||||||
cipherTransform = C.MY_xmlSecTransformRsaOaepId()
|
cipherTransform = C.MY_xmlSecTransformRsaOaepId()
|
||||||
case RsaOaep:
|
case RsaOaep:
|
||||||
cipherTransform = C.MY_xmlSecTransformRsaOaepId()
|
cipherTransform = C.MY_xmlSecTransformRsaOaepId()
|
||||||
@@ -141,39 +184,39 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
encKeyNode := C.xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, cipherTransform, nil, nil, nil)
|
encKeyNode := C.xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, cipherTransform, nil, nil, nil)
|
||||||
if encKeyNode == nil {
|
if encKeyNode == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplKeyInfoAddEncryptedKey failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// we want to put encrypted key in the <enc:CipherValue/> node
|
// we want to put encrypted key in the <enc:CipherValue/> node
|
||||||
if C.xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == nil {
|
if C.xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureCipherValue failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/>
|
// add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/>
|
||||||
keyInfoNode2 := C.xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, nil)
|
keyInfoNode2 := C.xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, nil)
|
||||||
if keyInfoNode2 == nil {
|
if keyInfoNode2 == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplEncDataEnsureKeyInfo failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
// Add a DigestMethod element to the encryption method node
|
// Add a DigestMethod element to the encryption method node
|
||||||
{
|
{
|
||||||
encKeyMethod := C.xmlSecTmplEncDataGetEncMethodNode(encKeyNode)
|
encKeyMethod := C.xmlSecTmplEncDataGetEncMethodNode(encKeyNode)
|
||||||
var ns = constXmlChar("http://www.w3.org/2000/09/xmldsig#")
|
var ns = constXMLChar("http://www.w3.org/2000/09/xmldsig#")
|
||||||
var strDigestMethod = constXmlChar("DigestMethod")
|
var strDigestMethod = constXMLChar("DigestMethod")
|
||||||
var strAlgorithm = constXmlChar("Algorithm")
|
var strAlgorithm = constXMLChar("Algorithm")
|
||||||
var algorithm *C.xmlChar
|
var algorithm *C.xmlChar
|
||||||
switch opts.DigestAlgorithm {
|
switch opts.DigestAlgorithm {
|
||||||
case Sha512:
|
case Sha512:
|
||||||
algorithm = constXmlChar("http://www.w3.org/2001/04/xmlenc#sha512")
|
algorithm = constXMLChar("http://www.w3.org/2001/04/xmlenc#sha512")
|
||||||
case Sha384:
|
case Sha384:
|
||||||
algorithm = constXmlChar("http://www.w3.org/2001/04/xmldsig-more#sha384")
|
algorithm = constXMLChar("http://www.w3.org/2001/04/xmldsig-more#sha384")
|
||||||
case Sha256:
|
case Sha256:
|
||||||
algorithm = constXmlChar("http://www.w3.org/2001/04/xmlenc#sha256")
|
algorithm = constXMLChar("http://www.w3.org/2001/04/xmlenc#sha256")
|
||||||
case Sha1:
|
case Sha1:
|
||||||
algorithm = constXmlChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
algorithm = constXMLChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
||||||
case DefaultAlgorithm:
|
case DefaultDigestAlgorithm:
|
||||||
algorithm = constXmlChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
algorithm = constXMLChar("http://www.w3.org/2000/09/xmldsig#sha1")
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown digest algorithm %d", opts.DigestAlgorithm)
|
return nil, errInvalidAlgorithm
|
||||||
}
|
}
|
||||||
node := C.xmlSecAddChild(encKeyMethod, strDigestMethod, ns)
|
node := C.xmlSecAddChild(encKeyMethod, strDigestMethod, ns)
|
||||||
C.xmlSetProp(node, strAlgorithm, algorithm)
|
C.xmlSetProp(node, strAlgorithm, algorithm)
|
||||||
@@ -182,22 +225,22 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
// add our certificate to KeyInfoNode
|
// add our certificate to KeyInfoNode
|
||||||
x509dataNode := C.xmlSecTmplKeyInfoAddX509Data(keyInfoNode2)
|
x509dataNode := C.xmlSecTmplKeyInfoAddX509Data(keyInfoNode2)
|
||||||
if x509dataNode == nil {
|
if x509dataNode == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplKeyInfoAddX509Data failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
if dataNode := C.xmlSecTmplX509DataAddCertificate(x509dataNode); dataNode == nil {
|
if dataNode := C.xmlSecTmplX509DataAddCertificate(x509dataNode); dataNode == nil {
|
||||||
return nil, fmt.Errorf("xmlSecTmplX509DataAddCertificate failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// create encryption context
|
// create encryption context
|
||||||
var encCtx = C.xmlSecEncCtxCreate(keysMngr)
|
var encCtx = C.xmlSecEncCtxCreate(keysMngr)
|
||||||
if encCtx == nil {
|
if encCtx == nil {
|
||||||
return nil, fmt.Errorf("xmlSecEncCtxCreate failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
defer C.xmlSecEncCtxDestroy(encCtx)
|
defer C.xmlSecEncCtxDestroy(encCtx)
|
||||||
|
|
||||||
// generate a key of the appropriate type
|
// generate a key of the appropriate type
|
||||||
switch opts.SessionCipher {
|
switch opts.SessionCipher {
|
||||||
case DefaultAlgorithm:
|
case DefaultSessionCipher:
|
||||||
encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 256,
|
encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 256,
|
||||||
C.xmlSecKeyDataTypeSession)
|
C.xmlSecKeyDataTypeSession)
|
||||||
case Aes128Cbc:
|
case Aes128Cbc:
|
||||||
@@ -213,15 +256,15 @@ func XmlEncrypt(publicKey, doc []byte, opts Options) ([]byte, error) {
|
|||||||
encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataDesId(), 192,
|
encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataDesId(), 192,
|
||||||
C.xmlSecKeyDataTypeSession)
|
C.xmlSecKeyDataTypeSession)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown cipher type %d", opts.SessionCipher)
|
return nil, errInvalidAlgorithm
|
||||||
}
|
}
|
||||||
if encCtx.encKey == nil {
|
if encCtx.encKey == nil {
|
||||||
return nil, fmt.Errorf("xmlSecKeyGenerate failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// encrypt the data
|
// encrypt the data
|
||||||
if rv := C.xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, C.xmlDocGetRootElement(parsedDoc)); rv < 0 {
|
if rv := C.xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, C.xmlDocGetRootElement(parsedDoc)); rv < 0 {
|
||||||
return nil, fmt.Errorf("xmlSecEncCtxXmlEncrypt failed")
|
return nil, mustPopError()
|
||||||
}
|
}
|
||||||
encDataNode = nil // the template is inserted in the doc, so we don't own it
|
encDataNode = nil // the template is inserted in the doc, so we don't own it
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -82,10 +82,10 @@ cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvnOwJlNCASPZRH/JmF8tX0hoHuAQ==</ds:X509Certificate
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (testSuite *EncryptTest) TestEncrypt(c *C) {
|
func (testSuite *EncryptTest) TestEncrypt(c *C) {
|
||||||
encryptedString, err := XmlEncrypt(testSuite.Cert, testSuite.Plaintext, Options{})
|
encryptedString, err := Encrypt(testSuite.Cert, testSuite.Plaintext, EncryptOptions{})
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
actualPlaintext, err := DecryptXML(testSuite.Key, encryptedString)
|
actualPlaintext, err := Decrypt(testSuite.Key, encryptedString)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
plaintextDoc, _ := newDoc(testSuite.Plaintext)
|
plaintextDoc, _ := newDoc(testSuite.Plaintext)
|
||||||
|
|||||||
24
error.go
24
error.go
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
var globalErrors = map[uintptr]errset.ErrSet{}
|
var globalErrors = map[uintptr]errset.ErrSet{}
|
||||||
|
|
||||||
type Error struct {
|
type libraryError struct {
|
||||||
FileName string
|
FileName string
|
||||||
Line int
|
Line int
|
||||||
FuncName string
|
FuncName string
|
||||||
@@ -20,7 +20,7 @@ type Error struct {
|
|||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Error) Error() string {
|
func (e libraryError) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s",
|
"func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s",
|
||||||
e.FuncName,
|
e.FuncName,
|
||||||
@@ -34,7 +34,7 @@ func (e Error) Error() string {
|
|||||||
|
|
||||||
//export onError
|
//export onError
|
||||||
func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, errorSubject *C.char, reason C.int, msg *C.char) {
|
func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, errorSubject *C.char, reason C.int, msg *C.char) {
|
||||||
err := Error{
|
err := libraryError{
|
||||||
FuncName: C.GoString(funcName),
|
FuncName: C.GoString(funcName),
|
||||||
FileName: C.GoString(file),
|
FileName: C.GoString(file),
|
||||||
Line: int(line),
|
Line: int(line),
|
||||||
@@ -42,7 +42,7 @@ func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, er
|
|||||||
Subject: C.GoString(errorSubject),
|
Subject: C.GoString(errorSubject),
|
||||||
Reason: int(reason),
|
Reason: int(reason),
|
||||||
Message: C.GoString(msg)}
|
Message: C.GoString(msg)}
|
||||||
threadID := getThreadId()
|
threadID := getThreadID()
|
||||||
globalErrors[threadID] = append(globalErrors[threadID], err)
|
globalErrors[threadID] = append(globalErrors[threadID], err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,21 +51,31 @@ func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, er
|
|||||||
// error object.
|
// error object.
|
||||||
func startProcessingXML() {
|
func startProcessingXML() {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
globalErrors[getThreadId()] = errset.ErrSet{}
|
globalErrors[getThreadID()] = errset.ErrSet{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopProcessingXML unlocks the goroutine-thread lock and deletes the current
|
// stopProcessingXML unlocks the goroutine-thread lock and deletes the current
|
||||||
// error stack.
|
// error stack.
|
||||||
func stopProcessingXML() {
|
func stopProcessingXML() {
|
||||||
runtime.UnlockOSThread()
|
runtime.UnlockOSThread()
|
||||||
delete(globalErrors, getThreadId())
|
delete(globalErrors, getThreadID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// popError returns the global error for the current thread and resets it to
|
// popError returns the global error for the current thread and resets it to
|
||||||
// an empty error. Returns nil if no errors have occurred.
|
// an empty error. Returns nil if no errors have occurred.
|
||||||
func popError() error {
|
func popError() error {
|
||||||
threadID := getThreadId()
|
threadID := getThreadID()
|
||||||
rv := globalErrors[threadID].ReturnValue()
|
rv := globalErrors[threadID].ReturnValue()
|
||||||
globalErrors[threadID] = errset.ErrSet{}
|
globalErrors[threadID] = errset.ErrSet{}
|
||||||
return rv
|
return rv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mustPopError is like popError except that if there is no error on the stack
|
||||||
|
// it returns a generic error.
|
||||||
|
func mustPopError() error {
|
||||||
|
err := popError()
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("libxmlsec: call failed")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func main() {
|
|||||||
buf, err := ioutil.ReadAll(os.Stdin)
|
buf, err := ioutil.ReadAll(os.Stdin)
|
||||||
|
|
||||||
if *doSign {
|
if *doSign {
|
||||||
signedBuf, err := xmlsec.Sign(key, buf, xmlsec.DsigOptions{})
|
signedBuf, err := xmlsec.Sign(key, buf, xmlsec.SignatureOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s\n", err)
|
fmt.Printf("%s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@@ -42,7 +42,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *doVerify {
|
if *doVerify {
|
||||||
err := xmlsec.Verify(key, buf, xmlsec.DsigOptions{})
|
err := xmlsec.Verify(key, buf, xmlsec.SignatureOptions{})
|
||||||
if err == xmlsec.ErrVerificationFailed {
|
if err == xmlsec.ErrVerificationFailed {
|
||||||
fmt.Println("signature is not correct")
|
fmt.Println("signature is not correct")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -37,11 +37,12 @@ type Signature struct {
|
|||||||
X509Certificate *SignatureX509Data `xml:"KeyInfo>X509Data,omitempty"`
|
X509Certificate *SignatureX509Data `xml:"KeyInfo>X509Data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignatureX509Data represents the <X509Data> element of <Signature>
|
||||||
type SignatureX509Data struct {
|
type SignatureX509Data struct {
|
||||||
X509Certificate string `xml:"X509Certificate,omitempty"`
|
X509Certificate string `xml:"X509Certificate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultSignature populates a default Signature that uses c14n and SHA1.
|
// DefaultSignature returns a Signature struct that uses the default c14n and SHA1 settings.
|
||||||
func DefaultSignature(pemEncodedPublicKey []byte) Signature {
|
func DefaultSignature(pemEncodedPublicKey []byte) Signature {
|
||||||
// xmlsec wants the key to be base64-encoded but *not* wrapped with the
|
// xmlsec wants the key to be base64-encoded but *not* wrapped with the
|
||||||
// PEM flags
|
// PEM flags
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ import "unsafe"
|
|||||||
// #include <pthread.h>
|
// #include <pthread.h>
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func getThreadId() uintptr {
|
func getThreadID() uintptr {
|
||||||
return uintptr(unsafe.Pointer(C.pthread_self()))
|
return uintptr(unsafe.Pointer(C.pthread_self()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ package xmlsec
|
|||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
||||||
func getThreadId() uintptr {
|
func getThreadID() uintptr {
|
||||||
return uintptr(syscall.Gettid())
|
return uintptr(syscall.Gettid())
|
||||||
}
|
}
|
||||||
|
|||||||
36
xmldsig.go
36
xmldsig.go
@@ -2,7 +2,6 @@ package xmlsec
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,9 +14,9 @@ import (
|
|||||||
// #include <xmlsec/crypto.h>
|
// #include <xmlsec/crypto.h>
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// DsigOptions represents additional, less commonly used, options for Sign and
|
// SignatureOptions represents additional, less commonly used, options for Sign and
|
||||||
// Verify
|
// Verify
|
||||||
type DsigOptions struct {
|
type SignatureOptions struct {
|
||||||
// Specify the name of ID attributes for specific elements. This
|
// Specify the name of ID attributes for specific elements. This
|
||||||
// may be required if the signed document contains Reference elements
|
// may be required if the signed document contains Reference elements
|
||||||
// that define which parts of the document are to be signed.
|
// that define which parts of the document are to be signed.
|
||||||
@@ -28,18 +27,19 @@ type DsigOptions struct {
|
|||||||
XMLID []XMLIDOption
|
XMLID []XMLIDOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XMLIDOption represents the definition of an XML reference element
|
||||||
|
// (See http://www.w3.org/TR/xml-id/)
|
||||||
type XMLIDOption struct {
|
type XMLIDOption struct {
|
||||||
ElementName string
|
ElementName string
|
||||||
ElementNamespace string
|
ElementNamespace string
|
||||||
AttributeName string
|
AttributeName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign returns a version of docStr signed with key according to
|
// Sign returns a version of doc signed with key according to
|
||||||
// the XML-DSIG standard. docStr is a template document meaning
|
// the XML-DSIG standard. doc is a template document meaning
|
||||||
// that it contains a `Signature` element in the
|
// that it contains an `http://www.w3.org/2000/09/xmldsig#Signature`
|
||||||
// http://www.w3.org/2000/09/xmldsig# namespace.
|
// element whose properties define how and what to sign.
|
||||||
func Sign(key []byte, doc []byte, opts DsigOptions) ([]byte, error) {
|
func Sign(key []byte, doc []byte, opts SignatureOptions) ([]byte, error) {
|
||||||
|
|
||||||
startProcessingXML()
|
startProcessingXML()
|
||||||
defer stopProcessingXML()
|
defer stopProcessingXML()
|
||||||
|
|
||||||
@@ -88,22 +88,22 @@ const (
|
|||||||
xmlSecDSigStatusInvalid = 2
|
xmlSecDSigStatusInvalid = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// Verify checks that the signature in docStr is valid according
|
// Verify checks that the signature in doc is valid according
|
||||||
// to the XML-DSIG specification. publicKey is the public part of
|
// to the XML-DSIG specification. publicKey is the public part of
|
||||||
// the key used to sign docStr. If the signature is not correct,
|
// the key used to sign doc. If the signature is not correct,
|
||||||
// this function returns ErrVerificationFailed.
|
// this function returns ErrVerificationFailed.
|
||||||
func Verify(publicKey []byte, doc []byte, opts DsigOptions) error {
|
func Verify(publicKey []byte, doc []byte, opts SignatureOptions) error {
|
||||||
startProcessingXML()
|
startProcessingXML()
|
||||||
defer stopProcessingXML()
|
defer stopProcessingXML()
|
||||||
|
|
||||||
keysMngr := C.xmlSecKeysMngrCreate()
|
keysMngr := C.xmlSecKeysMngrCreate()
|
||||||
if keysMngr == nil {
|
if keysMngr == nil {
|
||||||
return fmt.Errorf("xmlSecKeysMngrCreate failed")
|
return mustPopError()
|
||||||
}
|
}
|
||||||
defer C.xmlSecKeysMngrDestroy(keysMngr)
|
defer C.xmlSecKeysMngrDestroy(keysMngr)
|
||||||
|
|
||||||
if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 {
|
if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 {
|
||||||
return fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrInit failed")
|
return mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
key := C.xmlSecCryptoAppKeyLoadMemory(
|
key := C.xmlSecCryptoAppKeyLoadMemory(
|
||||||
@@ -112,7 +112,7 @@ func Verify(publicKey []byte, doc []byte, opts DsigOptions) error {
|
|||||||
C.xmlSecKeyDataFormatCertPem,
|
C.xmlSecKeyDataFormatCertPem,
|
||||||
nil, nil, nil)
|
nil, nil, nil)
|
||||||
if key == nil {
|
if key == nil {
|
||||||
return fmt.Errorf("xmlSecCryptoAppKeyLoadMemory failed")
|
return mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key,
|
if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key,
|
||||||
@@ -120,16 +120,16 @@ func Verify(publicKey []byte, doc []byte, opts DsigOptions) error {
|
|||||||
C.xmlSecSize(len(publicKey)),
|
C.xmlSecSize(len(publicKey)),
|
||||||
C.xmlSecKeyDataFormatCertPem); rv < 0 {
|
C.xmlSecKeyDataFormatCertPem); rv < 0 {
|
||||||
C.xmlSecKeyDestroy(key)
|
C.xmlSecKeyDestroy(key)
|
||||||
return fmt.Errorf("xmlSecCryptoAppKeyCertLoad failed")
|
return mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 {
|
if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 {
|
||||||
return fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrAdoptKey failed")
|
return mustPopError()
|
||||||
}
|
}
|
||||||
|
|
||||||
dsigCtx := C.xmlSecDSigCtxCreate(keysMngr)
|
dsigCtx := C.xmlSecDSigCtxCreate(keysMngr)
|
||||||
if dsigCtx == nil {
|
if dsigCtx == nil {
|
||||||
return fmt.Errorf("xmlSecDSigCtxCreate failed")
|
return mustPopError()
|
||||||
}
|
}
|
||||||
defer C.xmlSecDSigCtxDestroy(dsigCtx)
|
defer C.xmlSecDSigCtxDestroy(dsigCtx)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -57,7 +57,6 @@ func newDoc(buf []byte) (*C.xmlDoc, error) {
|
|||||||
}
|
}
|
||||||
defer C.xmlFreeParserCtxt(ctx)
|
defer C.xmlFreeParserCtxt(ctx)
|
||||||
|
|
||||||
//C.xmlCtxtUseOptions(ctx, C.int(p.Options))
|
|
||||||
C.xmlParseDocument(ctx)
|
C.xmlParseDocument(ctx)
|
||||||
|
|
||||||
if ctx.wellFormed == C.int(0) {
|
if ctx.wellFormed == C.int(0) {
|
||||||
@@ -72,7 +71,7 @@ func newDoc(buf []byte) (*C.xmlDoc, error) {
|
|||||||
return doc, nil
|
return doc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDoc2(buf []byte, opts DsigOptions) (*C.xmlDoc, error) {
|
func newDoc2(buf []byte, opts SignatureOptions) (*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 {
|
||||||
@@ -80,7 +79,6 @@ func newDoc2(buf []byte, opts DsigOptions) (*C.xmlDoc, error) {
|
|||||||
}
|
}
|
||||||
defer C.xmlFreeParserCtxt(ctx)
|
defer C.xmlFreeParserCtxt(ctx)
|
||||||
|
|
||||||
//C.xmlCtxtUseDsigOptions(ctx, C.int(p.DsigOptions))
|
|
||||||
C.xmlParseDocument(ctx)
|
C.xmlParseDocument(ctx)
|
||||||
|
|
||||||
if ctx.wellFormed == C.int(0) {
|
if ctx.wellFormed == C.int(0) {
|
||||||
@@ -146,6 +144,6 @@ func dumpDoc(doc *C.xmlDoc) []byte {
|
|||||||
return []byte(rv)
|
return []byte(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func constXmlChar(s string) *C.xmlChar {
|
func constXMLChar(s string) *C.xmlChar {
|
||||||
return (*C.xmlChar)(unsafe.Pointer(C.CString(s)))
|
return (*C.xmlChar)(unsafe.Pointer(C.CString(s)))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user