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 (document *XmlDocument) Root() (element *ElementNode) { nodePtr := C.xmlDocGetRootElement(document.Ptr) if nodePtr != nil { element = NewNode(unsafe.Pointer(nodePtr), document).(*ElementNode) } return }
func ParseHTMLString(content string) (*Document, error) { d := htmlReadDoc(content, "", "", DefaultHtmlParseFlags) root, err := C.xmlDocGetRootElement(d) if err != nil || root == nil { C.xmlFreeDoc(d) return nil, err } return &Document{ptr: d, root: root}, nil }
// 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() defer stopProcessingXML() keysMngr := C.xmlSecKeysMngrCreate() if keysMngr == nil { return nil, popError() } defer C.xmlSecKeysMngrDestroy(keysMngr) if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { return nil, popError() } key := C.xmlSecCryptoAppKeyLoadMemory( (*C.xmlSecByte)(unsafe.Pointer(&privateKey[0])), C.xmlSecSize(len(privateKey)), C.xmlSecKeyDataFormatPem, nil, nil, nil) if key == nil { return nil, popError() } if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 { return nil, popError() } parsedDoc, err := newDoc(doc, nil) if err != nil { return nil, err } defer closeDoc(parsedDoc) // create encryption context encCtx := C.xmlSecEncCtxCreate(keysMngr) if encCtx == nil { return nil, popError() } defer C.xmlSecEncCtxDestroy(encCtx) encDataNode := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeEncryptedData)), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecEncNs))) if encDataNode == nil { return nil, fmt.Errorf("xmlSecFindNode cannot find EncryptedData node") } // decrypt the data if rv := C.xmlSecEncCtxDecrypt(encCtx, encDataNode); rv < 0 { return nil, popError() } encDataNode = nil // the template is inserted in the doc, so we don't own it return dumpDoc(parsedDoc), nil }
// xmlXPathEvalExpression shim around the libxml2 function of the same name func (xp *Xp) xmlXPathEvalExpression(context *C.xmlNode, path string) (xmlXPathObject *C.xmlXPathObject) { if context == nil { context = C.xmlDocGetRootElement(xp.doc) } C.xmlXPathSetContextNode(context, xp.xpathCtx) Cpath := unsafe.Pointer(C.CString(path)) defer C.free(Cpath) xmlXPathObject = C.xmlXPathEvalExpression((*C.xmlChar)(Cpath), xp.xpathCtx) return }
func (d *Document) DocumentElement() Node { if d.ptr == nil { return nil } if d.root == nil { n := C.xmlDocGetRootElement(d.ptr) if n == nil { return nil } d.root = n } return wrapToNode(d.root) }
// CreateElementNS Create an element with the given namespace func (xp *Xp) createElementNS(prefix, element string, context *C.xmlNode, before *C.xmlNode) (newcontext *C.xmlNode) { ns := C.xmlNewNs(nil, namespaces[prefix].ns_uri, namespaces[prefix].prefix) // candidate for cache ... if ns == nil { panic("ns is nil") } celement := unsafe.Pointer(C.CString(element)) newelement := C.xmlNewDocNode(xp.doc, ns, (*C.xmlChar)(celement), nil) C.free(celement) if before != nil { newcontext = C.xmlAddPrevSibling(before, newelement) } else { if context == nil { context = C.xmlDocGetRootElement(xp.doc) } newcontext = C.xmlAddChild(context, newelement) } return }
// Sign returns a version of doc signed with key according to // the XMLDSIG standard. doc is a template document meaning // that it contains an `http://www.w3.org/2000/09/xmldsig#Signature` // element whose properties define how and what to sign. func Sign(key []byte, doc []byte, opts SignatureOptions) ([]byte, error) { startProcessingXML() defer stopProcessingXML() ctx := C.xmlSecDSigCtxCreate(nil) if ctx == nil { return nil, errors.New("failed to create signature context") } defer C.xmlSecDSigCtxDestroy(ctx) ctx.signKey = C.xmlSecCryptoAppKeyLoadMemory( (*C.xmlSecByte)(unsafe.Pointer(&key[0])), C.xmlSecSize(len(key)), C.xmlSecKeyDataFormatPem, nil, nil, nil) if ctx.signKey == nil { return nil, errors.New("failed to load pem key") } parsedDoc, err := newDoc(doc, opts.XMLID) if err != nil { return nil, err } defer closeDoc(parsedDoc) node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) if node == nil { return nil, errors.New("cannot find start node") } if rv := C.xmlSecDSigCtxSign(ctx, node); rv < 0 { return nil, errors.New("failed to sign") } return dumpDoc(parsedDoc), nil }
func wrapDocument(n *C.xmlDoc) *Document { r := C.xmlDocGetRootElement(n) // XXX Should check for n == nil return &Document{ptr: n, root: r} }
// Encrypt encrypts the XML document to publicKey and returns the encrypted // document. func Encrypt(publicKey, doc []byte, opts EncryptOptions) ([]byte, error) { startProcessingXML() defer stopProcessingXML() keysMngr := C.xmlSecKeysMngrCreate() if keysMngr == nil { return nil, mustPopError() } defer C.xmlSecKeysMngrDestroy(keysMngr) if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { return nil, mustPopError() } key := C.xmlSecCryptoAppKeyLoadMemory( (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), C.xmlSecSize(len(publicKey)), C.xmlSecKeyDataFormatCertPem, nil, nil, nil) if key == nil { return nil, mustPopError() } if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key, (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), C.xmlSecSize(len(publicKey)), C.xmlSecKeyDataFormatCertPem); rv < 0 { C.xmlSecKeyDestroy(key) return nil, mustPopError() } if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 { return nil, mustPopError() } parsedDoc, err := newDoc(doc, nil) if err != nil { return nil, err } defer closeDoc(parsedDoc) var sessionCipherTransform C.xmlSecTransformId switch opts.SessionCipher { case DefaultSessionCipher: sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId() case Aes256Cbc: sessionCipherTransform = C.MY_xmlSecTransformAes256CbcId() case Aes192Cbc: sessionCipherTransform = C.MY_xmlSecTransformAes192CbcId() case Aes128Cbc: sessionCipherTransform = C.MY_xmlSecTransformAes128CbcId() case Des3Cbc: sessionCipherTransform = C.MY_xmlSecTransformDes3CbcId() default: return nil, errInvalidAlgorithm } // create encryption template to encrypt XML file and replace // its content with encryption result encDataNode := C.xmlSecTmplEncDataCreate(parsedDoc, sessionCipherTransform, nil, (*C.xmlChar)(unsafe.Pointer(&C.xmlSecTypeEncElement)), nil, nil) if encDataNode == nil { return nil, mustPopError() } defer func() { if encDataNode != nil { C.xmlFreeNode(encDataNode) encDataNode = nil } }() // we want to put encrypted data in the <enc:CipherValue/> node if C.xmlSecTmplEncDataEnsureCipherValue(encDataNode) == nil { return nil, mustPopError() } // add <dsig:KeyInfo/> keyInfoNode := C.xmlSecTmplEncDataEnsureKeyInfo(encDataNode, nil) if keyInfoNode == nil { return nil, mustPopError() } // add <enc:EncryptedKey/> to store the encrypted session key var cipherTransform C.xmlSecTransformId switch opts.Cipher { case DefaultCipher: cipherTransform = C.MY_xmlSecTransformRsaOaepId() case RsaOaep: cipherTransform = C.MY_xmlSecTransformRsaOaepId() case RsaPkcs1: cipherTransform = C.MY_xmlSecTransformRsaPkcs1Id() } encKeyNode := C.xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, cipherTransform, nil, nil, nil) if encKeyNode == nil { return nil, mustPopError() } // we want to put encrypted key in the <enc:CipherValue/> node if C.xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == nil { return nil, mustPopError() } // add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/> keyInfoNode2 := C.xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, nil) if keyInfoNode2 == nil { return nil, mustPopError() } // Add a DigestMethod element to the encryption method node { encKeyMethod := C.xmlSecTmplEncDataGetEncMethodNode(encKeyNode) var algorithm *C.xmlChar switch opts.DigestAlgorithm { case Sha512: algorithm = constSha512 case Sha384: algorithm = constSha384 case Sha256: algorithm = constSha256 case Sha1: algorithm = constSha1 case DefaultDigestAlgorithm: algorithm = constSha1 default: return nil, errInvalidAlgorithm } node := C.xmlSecAddChild(encKeyMethod, constDigestMethod, constDsigNamespace) C.xmlSetProp(node, constAlgorithm, algorithm) } // add our certificate to KeyInfoNode x509dataNode := C.xmlSecTmplKeyInfoAddX509Data(keyInfoNode2) if x509dataNode == nil { return nil, mustPopError() } if dataNode := C.xmlSecTmplX509DataAddCertificate(x509dataNode); dataNode == nil { return nil, mustPopError() } // create encryption context var encCtx = C.xmlSecEncCtxCreate(keysMngr) if encCtx == nil { return nil, mustPopError() } defer C.xmlSecEncCtxDestroy(encCtx) // generate a key of the appropriate type switch opts.SessionCipher { case DefaultSessionCipher: encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 256, C.xmlSecKeyDataTypeSession) case Aes128Cbc: encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 128, C.xmlSecKeyDataTypeSession) case Aes192Cbc: encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 192, C.xmlSecKeyDataTypeSession) case Aes256Cbc: encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataAesId(), 256, C.xmlSecKeyDataTypeSession) case Des3Cbc: encCtx.encKey = C.xmlSecKeyGenerate(C.MY_xmlSecKeyDataDesId(), 192, C.xmlSecKeyDataTypeSession) default: return nil, errInvalidAlgorithm } if encCtx.encKey == nil { return nil, mustPopError() } // encrypt the data if rv := C.xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, C.xmlDocGetRootElement(parsedDoc)); rv < 0 { return nil, mustPopError() } encDataNode = nil // the template is inserted in the doc, so we don't own it return dumpDoc(parsedDoc), nil }
// Verify checks that the signature in doc is valid according // to the XMLDSIG specification. publicKey is the public part of // the key used to sign doc. If the signature is not correct, // this function returns ErrVerificationFailed. func Verify(publicKey []byte, doc []byte, opts SignatureOptions) error { startProcessingXML() defer stopProcessingXML() keysMngr := C.xmlSecKeysMngrCreate() if keysMngr == nil { return mustPopError() } defer C.xmlSecKeysMngrDestroy(keysMngr) if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { return mustPopError() } key := C.xmlSecCryptoAppKeyLoadMemory( (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), C.xmlSecSize(len(publicKey)), C.xmlSecKeyDataFormatCertPem, nil, nil, nil) if key == nil { return mustPopError() } if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key, (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), C.xmlSecSize(len(publicKey)), C.xmlSecKeyDataFormatCertPem); rv < 0 { C.xmlSecKeyDestroy(key) return mustPopError() } if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 { return mustPopError() } dsigCtx := C.xmlSecDSigCtxCreate(keysMngr) if dsigCtx == nil { return mustPopError() } defer C.xmlSecDSigCtxDestroy(dsigCtx) parsedDoc, err := newDoc(doc, opts.XMLID) if err != nil { return err } defer closeDoc(parsedDoc) node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) if node == nil { return errors.New("cannot find start node") } if rv := C.xmlSecDSigCtxVerify(dsigCtx, node); rv < 0 { return ErrVerificationFailed } if dsigCtx.status != xmlSecDSigStatusSucceeded { return ErrVerificationFailed } return nil }
func XmlDocGetRootElement(d *C.xmlDoc) *C.xmlNode { return C.xmlDocGetRootElement(d) }
// xmlDocGetRootElement func (doc *Document) Root() *Node { cnode := C.xmlDocGetRootElement(doc.Ptr) return makeNode(cnode) }
func (xp *Xp) DocGetRootElement() (res *C.xmlNode) { return C.xmlDocGetRootElement(xp.doc) }
func XmlDocGetRootElement(doc unsafe.Pointer) unsafe.Pointer { cnode := C.xmlDocGetRootElement(C.xmlDocPtr(doc)) return unsafe.Pointer(cnode) }