-
Notifications
You must be signed in to change notification settings - Fork 108
Closed
Description
With xmlsec==1.0.9, this function uses ~1MB of memory for xmlsec.KeysManager()
on each call, that is never freed. With xmlsec==0.6.1, the memory seems to be freed when exiting the function.
def _encrypt_usernametoken(self, envelope):
"""Encrypt the ``UsernameToken`` element in the ``envelope``."""
header = envelope.find(ns(SOAP_NS, 'Header'))
security = header.find(ns(WSSE_NS, 'Security'))
# Create a keys manager and load the cert into it.
manager = xmlsec.KeysManager()
key = xmlsec.Key.from_file(self.recipient_cert, xmlsec.KeyFormat.CERT_PEM)
manager.add_key(key)
# Encrypt the UsernameToken
target = security.find(ns(WSSE_NS, 'UsernameToken'))
# Create the EncryptedData node we will replace the target node with,
# and make sure it has the contents XMLSec expects (a CipherValue node,
# a KeyInfo node, and an EncryptedKey node within the KeyInfo which
# itself has a CipherValue).
enc_data = xmlsec.template.encrypted_data_create(
envelope,
xmlsec.Transform.DES3,
type=xmlsec.EncryptionType.ELEMENT,
ns='xenc',
)
xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
key_info = xmlsec.template.encrypted_data_ensure_key_info(
enc_data, ns='dsig')
enc_key = xmlsec.template.add_encrypted_key(
key_info,
# Service requires RSA 1.5 encryption, which is the same as RSA
# PKCS1.
xmlsec.Transform.RSA_PKCS1,
)
xmlsec.template.encrypted_data_ensure_cipher_value(enc_key)
enc_ctx = xmlsec.EncryptionContext(manager)
# Generate a per-session DES key (will be encrypted using the cert).
enc_ctx.key = xmlsec.Key.generate(
xmlsec.KeyData.DES, 192, xmlsec.KeyDataType.SESSION)
# Ask XMLSec to actually do the encryption.
enc_data = enc_ctx.encrypt_xml(enc_data, target)
# XMLSec inserts the EncryptedKey node directly within EncryptedData,
# but WSSE wants it in the Security header instead, and referencing the
# EncryptedData as well as the actual cert in a BinarySecurityToken.
# Move the EncryptedKey node up into the wsse:Security header.
security.insert(0, enc_key)
# Create a wsse:BinarySecurityToken node containing the cert and add it
# to the Security header.
cert_bst = create_binary_security_token(self.recipient_cert)
security.insert(0, cert_bst)
# Create a ds:KeyInfo node referencing the BinarySecurityToken we just
# created, and insert it into the EncryptedKey node.
enc_key.insert(1, create_key_info_bst(cert_bst))
# Add a DataReference from the EncryptedKey node to the EncryptedData.
add_data_reference(enc_key, enc_data)
# Remove the now-empty KeyInfo node from EncryptedData (it used to
# contain EncryptedKey, but we moved that up into the Security header).
enc_data.remove(key_info)
It also looks like our signing function leaks ~0.1MB/call with xmlsec==1.0.9:
def _sign(self, envelope):
"""Sign the ``soap:Body`` and ``wsu:Timestamp`` of ``envelope``."""
# Insert the Signature node in the wsse:Security header.
header = envelope.find(ns(SOAP_NS, 'Header'))
security = header.find(ns(WSSE_NS, 'Security'))
cert_bst = create_binary_security_token(self.sender_cert)
security.append(cert_bst)
# Create the Signature node.
signature = xmlsec.template.create(
envelope,
xmlsec.Transform.EXCL_C14N,
xmlsec.Transform.RSA_SHA1,
)
key_info = create_key_info_bst(cert_bst)
signature.append(key_info)
security.append(signature)
# Perform the actual signing.
ctx = xmlsec.SignatureContext()
ctx.key = xmlsec.Key.from_file(self.sender_key, xmlsec.KeyFormat.PEM)
_sign_node(ctx, signature, envelope.find(ns(SOAP_NS, 'Body')))
_sign_node(ctx, signature, security.find(ns(WSU_NS, 'Timestamp')))
ctx.sign(signature)
Metadata
Metadata
Assignees
Labels
No labels