francosy
francosy

Reputation: 153

Encrypt SOAP XML message with X509SubjectKeyIdentifier in Python

I want to encrypt the body of the SOAP XML document. It works perfectly fine with SoapUI, where I use certificate, Subject Key Identifier as Key Identifier Type, AES256-CBC encoding and RSA 1_5 encryption algorithm. I also checked the box to create encrypted key. I want to recreate there settings with python code, using the following code:

from zeep.wsse.utils
import base64

from zeep.wsse.utils import get_security_header
import xmlsec 
from lxml import etree

def encrypt(envelope, certfile):
    """Encrypt body contents of given SOAP envelope using given X509 cert."""
    doc = etree.fromstring(envelope)

    security = get_security_header(doc)

    # Create a keys manager and load the cert into it.
    manager = xmlsec.KeysManager()
    key = xmlsec.Key.from_file(certfile, xmlsec.KeyFormat.CERT_PEM, None)
    manager.add_key(key)

    body = doc.find(ns(SOAP_NS, 'Body'))

    enc_data = xmlsec.template.encrypted_data_create(
        body,
        xmlsec.constants.TransformAes256Cbc,
        type=xmlsec.EncryptionType.CONTENT,
        ns='xenc',
    )
    xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
    key_info = xmlsec.template.encrypted_data_ensure_key_info(
        enc_data, ns='ds')

    enc_key = xmlsec.template.add_encrypted_key(
        key_info, xmlsec.constants.TransformRsaPkcs1)
    #enc_key.append(create_key_info_ski(certfile))
    xmlsec.template.encrypted_data_ensure_cipher_value(enc_key)

    enc_ctx = xmlsec.EncryptionContext(manager)
    # Generate a per-session AES key (will be encrypted using the cert).
    enc_ctx.key = xmlsec.Key.generate(
        xmlsec.constants.KeyDataAes, 256, xmlsec.constants.KeyDataTypeSession)

    # Ask XMLSec to actually do the encryption.
    enc_data = enc_ctx.encrypt_xml(enc_data, body)


    # Move the EncryptedKey node up into the wsse:Security header.
    security.append(enc_key)
    
    # Create DataReference element
    add_data_reference(enc_key, enc_data)

    enc_data.remove(key_info)
    return doc

def create_key_info_ski(certfile):
    key_info = etree.Element(f"{{{DS_NS}}}KeyInfo", nsmap=namespaces)
    security_token_reference = etree.Element(f"{{{WSSE_NS}}}SecurityTokenReference")

    key_identifier = etree.Element(f"{{{WSSE_NS}}}KeyIdentifier",
                                   ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier",
                                   EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary")
    key_identifier.text = extract_ski(certfile)
    security_token_reference.append(key_identifier)
    key_info.append(security_token_reference)
    return key_info

Everything seems ok if I don't use X509SubjectKeyIdentifier. So if I comment out line

#enc_key.append(create_key_info_ski(certfile))

I get the following error:

xmlsec.Error: (1, 'failed to encrypt xml')

Are keys correctly used? What am I missing?

EDIT:

Input envelope example:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wse="http://.../wse">
   <soap:Header/>
   <soap:Body>
      <wse:GetDateTime/>
   </soap:Body>
</soap:Envelope>

Expected output:

<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:wse="http://.../wse">
<soap:Header>
    <wsse:Security
        xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <xenc:EncryptedKey Id="EK-ADF72CB9C6AC5D5A531716899228423321"
            xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
            <ds:KeyInfo
                xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <wsse:SecurityTokenReference>
                    <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">...</wsse:KeyIdentifier>
                </wsse:SecurityTokenReference>
            </ds:KeyInfo>
            <xenc:CipherData>
                <xenc:CipherValue>...</xenc:CipherValue>
            </xenc:CipherData>
            <xenc:ReferenceList>
                <xenc:DataReference URI="#ED-ADF72CB9C6AC5D5A531716899228424322"/>
            </xenc:ReferenceList>
        </xenc:EncryptedKey>
    </wsse:Security>
</soap:Header>
<soap:Body>
    <xenc:EncryptedData Id="ED-ADF72CB9C6AC5D5A531716899228424322" Type="http://www.w3.org/2001/04/xmlenc#Content"
        xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
        <ds:KeyInfo
            xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <wsse:SecurityTokenReference wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"
                xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
                <wsse:Reference URI="#EK-ADF72CB9C6AC5D5A531716899228423321"/>
            </wsse:SecurityTokenReference>
        </ds:KeyInfo>
        <xenc:CipherData>
            <xenc:CipherValue>...</xenc:CipherValue>
        </xenc:CipherData>
    </xenc:EncryptedData>
</soap:Body>
</soap:Envelope>

Upvotes: 2

Views: 192

Answers (0)

Related Questions