// xmlSetProp func (node *Node) SetAttribute(name string, value string) *Attribute { ptrn := C.CString(name) defer C.free_string(ptrn) ptrv := C.CString(value) defer C.free_string(ptrv) cattr := C.xmlSetProp(node.Ptr, C.to_xmlcharptr(ptrn), C.to_xmlcharptr(ptrv)) return makeAttribute(cattr) }
// SetAttr sets the value of the non-namespaced attribute attr func (node *C.xmlNode) SetAttr(attr, value string) { Cattr := (*C.xmlChar)(unsafe.Pointer(C.CString(attr))) Cvalue := (*C.xmlChar)(unsafe.Pointer(C.CString(value))) C.xmlSetProp(node, Cattr, Cvalue) C.free(unsafe.Pointer(Cattr)) C.free(unsafe.Pointer(Cvalue)) return }
// Attributes such as "xml:lang" or "xml:space" are not is a formal namespace // and should be set by calling SetAttr with the prefix as part of the name. func (xmlNode *XmlNode) SetAttr(name, value string) (val string) { val = value if xmlNode.NodeType() != XML_ELEMENT_NODE { return } nameBytes := GetCString([]byte(name)) namePtr := unsafe.Pointer(&nameBytes[0]) valueBytes := GetCString([]byte(value)) valuePtr := unsafe.Pointer(&valueBytes[0]) C.xmlSetProp(xmlNode.Ptr, (*C.xmlChar)(namePtr), (*C.xmlChar)(valuePtr)) return }
// 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 }
// QueryDashP generative xpath query - ie. mkdir -p for xpath ... // Understands simple xpath expressions including indexes and attribute values func (xp *Xp) QueryDashP(context *C.xmlNode, query string, data string, before *C.xmlNode) *C.xmlNode { // $query always starts with / ie. is alwayf 'absolute' in relation to the $context // split in path elements, an element might include an attribute expression incl. value eg. // /md:EntitiesDescriptor/md:EntityDescriptor[@entityID="https://wayf.wayf.dk"]/md:SPSSODescriptor re := regexp.MustCompile(`\/?([^\/"]*("[^"]*")?[^\/"]*)`) // slashes inside " is the problem re2 := regexp.MustCompile(`^(?:(\w+):?)?([^\[@]*)(?:\[(\d+)\])?(?:\[?@([^=]+)(?:="([^"]*)"])?)?()$`) path := re.FindAllStringSubmatch(query, -1) if query[0] == '/' { var buffer bytes.Buffer //buffer.WriteString("/") buffer.WriteString(path[0][1]) path[0][1] = buffer.String() } for _, elements := range path { element := elements[1] nodes := xp.Query(context, element) if len(nodes) > 0 { context = nodes[0] continue } else { d := re2.FindAllStringSubmatch(element, -1) if len(d) == 0 { panic("QueryDashP problem") } dn := d[0] ns, element, position_s, attribute, value := dn[1], dn[2], dn[3], dn[4], dn[5] if element != "" { if position_s != "" { position, _ := strconv.ParseInt(position_s, 10, 0) originalcontext := context for i := 1; i <= int(position); i++ { existingelement := xp.Query(originalcontext, ns+":"+element+"["+strconv.Itoa(i)+"]") if len(existingelement) > 0 { context = existingelement[0] } else { context = xp.createElementNS(ns, element, originalcontext, before) } } } else { context = xp.createElementNS(ns, element, context, before) } before = nil } if attribute != "" { Cattribute := unsafe.Pointer(C.CString(attribute)) Cvalue := unsafe.Pointer(C.CString(value)) context = (*C.xmlNode)(unsafe.Pointer(C.xmlSetProp(context, (*C.xmlChar)(Cattribute), (*C.xmlChar)(Cvalue)))) C.free(Cattribute) C.free(Cvalue) } } } // adding the provided value always at end .. if data != "" { xp.NodeSetContent(context, html.EscapeString(data)) } return context }