// Sign the given context with the given private key - which is a PEM or hsm: key // A hsm: key is a urn 'key' that points to a specific key/action in a goeleven interface to a HSM // See https://github.com/wayf-dk/goeleven func (xp *Xp) Sign(context *C.xmlNode, privatekey, pw, cert, algo string) (err error) { contextHash := Hash(algos[algo].algo, xp.C14n(context)) contextDigest := base64.StdEncoding.EncodeToString(contextHash) signaturexml := `<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm=""/> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm=""/> <ds:DigestValue></ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue></ds:SignatureValue> </ds:Signature>` signature := C.xmlNewDocFragment(xp.doc) var res C.xmlNodePtr buf := ([]byte)(signaturexml) C.xmlParseBalancedChunkMemory(xp.doc, nil, nil, 0, (*C.xmlChar)(&buf[0]), &res) C.xmlAddChildList(signature, res) C.xmlAddNextSibling(C.xmlFirstElementChild(context), signature) id := xp.Query1(context, "@ID") signedInfo := xp.QueryDashP(signature, `ds:Signature/ds:SignedInfo[1]`, "", nil) xp.QueryDashP(signedInfo, `ds:SignatureMethod[1]/@Algorithm`, algos[algo].signature, nil) xp.QueryDashP(signedInfo, `ds:Reference/@URI`, "#"+id, nil) xp.QueryDashP(signedInfo, `ds:Reference/ds:DigestMethod[1]/@Algorithm`, algos[algo].digest, nil) xp.QueryDashP(signedInfo, `ds:Reference/ds:DigestValue[1]`, contextDigest, nil) signedInfoC14n := xp.C14n(signedInfo) digest := Hash(algos[algo].algo, signedInfoC14n) var signaturevalue []byte if strings.HasPrefix(privatekey, "hsm:") { signaturevalue, err = signGoEleven(digest, privatekey, algo) } else { signaturevalue, err = signGo(digest, privatekey, pw, algo) } signatureval := base64.StdEncoding.EncodeToString(signaturevalue) xp.QueryDashP(signature, `ds:Signature/ds:SignatureValue`, signatureval, nil) xp.QueryDashP(signature, `ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate`, cert, nil) // log.Println(xp.Pp()) return }
// Decrypt decrypts the context using the given privatekey func (xp *Xp) Decrypt(context *C.xmlNode, privatekey *rsa.PrivateKey) (decryptedAssertion *C.xmlNode) { // for now just use what we send ourselves ... encryptedkey := xp.Query1(context, "./xenc:EncryptedData/ds:KeyInfo/xenc:EncryptedKey/xenc:CipherData/xenc:CipherValue") encryptedkeybyte, _ := base64.StdEncoding.DecodeString(encryptedkey) sessionkey, _ := rsa.DecryptOAEP(sha1.New(), rand.Reader, privatekey, encryptedkeybyte, nil) encryptedassertion := xp.Query1(context, "./xenc:EncryptedData/xenc:CipherData/xenc:CipherValue") encryptedassertionbyte, _ := base64.StdEncoding.DecodeString(encryptedassertion) assertion := decryptAES([]byte(sessionkey), encryptedassertionbyte) assertion = append(assertion, 0) var res C.xmlNodePtr decryptedAssertion = C.xmlNewDocFragment(xp.doc) C.xmlParseBalancedChunkMemory(xp.doc, nil, nil, 0, (*C.xmlChar)(&assertion[0]), &res) C.xmlAddChildList(decryptedAssertion, res) C.xmlReplaceNode(context, decryptedAssertion) C.xmlReconciliateNs(xp.doc, decryptedAssertion) return }
// Encrypt the context with the given publickey // Hardcoded to aes256-cbc for the symetric part and // rsa-oaep-mgf1p and sha1 for the rsa part func (xp *Xp) Encrypt(context *C.xmlNode, publickey *rsa.PublicKey) { template := []byte(`<saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"> <xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /> <ds:KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <xenc:EncryptedKey > <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> </xenc:EncryptionMethod> <xenc:CipherData> <xenc:CipherValue>encryptedsessionkey</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedKey> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>encryptedassertion</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </saml:EncryptedAssertion>`) var res C.xmlNodePtr encryptedAssertion := C.xmlNewDocFragment(xp.doc) C.xmlParseBalancedChunkMemory(xp.doc, nil, nil, 0, (*C.xmlChar)(&template[0]), &res) C.xmlAddChildList(encryptedAssertion, res) //sessionkey, ciphertext := encryptAES([]byte(xp.C14n(context))) sessionkey, ciphertext := encryptAES([]byte(xp.Dump2(context))) sessionkey, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, publickey, sessionkey, nil) if err != nil { panic(err) } ec := xp.QueryDashP(encryptedAssertion, `saml:EncryptedAssertion/xenc:EncryptedData`, "", nil) xp.QueryDashP(ec, `ds:KeyInfo/xenc:EncryptedKey/xenc:CipherData/xenc:CipherValue`, base64.StdEncoding.EncodeToString(sessionkey), nil) xp.QueryDashP(ec, `xenc:CipherData/xenc:CipherValue`, base64.StdEncoding.EncodeToString(ciphertext), nil) C.xmlReplaceNode(context, encryptedAssertion) }
// xmlNewDocFragment func (doc *Document) NewFragment() *Node { return makeNode(C.xmlNewDocFragment(doc.Ptr)) }