Exemple #1
0
    def _verify_signature_with_pubkey(self, signed_info_c14n, raw_signature, key_value, signature_alg):
        if "ecdsa-" in signature_alg:
            ec_key_value = self._find(key_value, "ECKeyValue", namespace="dsig11")
            named_curve = self._find(ec_key_value, "NamedCurve", namespace="dsig11")
            public_key = self._find(ec_key_value, "PublicKey", namespace="dsig11")
            key_data = b64decode(public_key.text)[1:]
            x = bytes_to_long(key_data[:len(key_data)//2])
            y = bytes_to_long(key_data[len(key_data)//2:])
            curve_class = self.known_ecdsa_curves[named_curve.get("URI")]
            key = ec.EllipticCurvePublicNumbers(x=x, y=y, curve=curve_class()).public_key(backend=default_backend())
            verifier = key.verifier(raw_signature, ec.ECDSA(self._get_signature_digest_method(signature_alg)))
        elif "dsa-" in signature_alg:
            dsa_key_value = self._find(key_value, "DSAKeyValue")
            p = self._get_long(dsa_key_value, "P")
            q = self._get_long(dsa_key_value, "Q")
            g = self._get_long(dsa_key_value, "G", require=False)
            y = self._get_long(dsa_key_value, "Y")
            pn = dsa.DSAPublicNumbers(y=y, parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g))
            key = pn.public_key(backend=default_backend())
            from asn1crypto.algos import DSASignature
            sig_as_der_seq = DSASignature.from_p1363(raw_signature).dump()
            verifier = key.verifier(sig_as_der_seq, self._get_signature_digest_method(signature_alg))
        elif "rsa-" in signature_alg:
            rsa_key_value = self._find(key_value, "RSAKeyValue")
            modulus = self._get_long(rsa_key_value, "Modulus")
            exponent = self._get_long(rsa_key_value, "Exponent")
            key = rsa.RSAPublicNumbers(e=exponent, n=modulus).public_key(backend=default_backend())
            verifier = key.verifier(raw_signature, padding=PKCS1v15(),
                                    algorithm=self._get_signature_digest_method(signature_alg))
        else:
            raise NotImplementedError()

        verifier.update(signed_info_c14n)
        verifier.verify()
Exemple #2
0
def encode_dss_signature(r, s):
    if (
            not isinstance(r, six.integer_types) or
            not isinstance(s, six.integer_types)
    ):
        raise ValueError("Both r and s must be integers")

    return DSASignature({'r': r, 's': s}).dump()
Exemple #3
0
def encode_ecdsa_signature(signature):
    """
    Encode a signature (generated by :meth:`pkcs11.SignMixin.sign`) into
    DER-encoded ASN.1 (ECDSA_Sig_Value) format.

    :param bytes signature: signature as bytes
    :rtype: bytes
    """

    return DSASignature.from_p1363(signature).dump()
Exemple #4
0
def decode_ecdsa_signature(der):
    """
    Decode a DER-encoded ASN.1 (ECDSA_Sig_Value) signature (as generated by
    OpenSSL/X.509) into PKCS #11 format.

    :param bytes der: DER-encoded signature
    :rtype bytes:
    """

    asn1 = DSASignature.load(der)
    return asn1.to_p1363()
Exemple #5
0
    def __init__(
        self,
        key: EccPublicKey,
        meta: EcdsaSignatureMetadata,
        r: Optional[int] = None,
        s: Optional[int] = None,
        der: Optional[ByteString] = None,
    ) -> None:
        self.key = key
        self.meta = meta

        if not r and not s and der:
            val = DSASignature.load(der)
            self.r = val["r"].native
            self.s = val["s"].native
            self.der = bytes(der)
        elif r and s and not der:
            self.r = r
            self.s = s
            self.der = DSASignature({"r": self.r, "s": self.s}).dump()
        else:
            raise ValueError("Bad parameters")
Exemple #6
0
 def _verify_signature_with_pubkey(self, signed_info_c14n, raw_signature, key_value, signature_alg):
     if "ecdsa-" in signature_alg:
         ec_key_value = self._find(key_value, "ECKeyValue", namespace="dsig11")
         named_curve = self._find(ec_key_value, "NamedCurve", namespace="dsig11")
         public_key = self._find(ec_key_value, "PublicKey", namespace="dsig11")
         key_data = b64decode(public_key.text)[1:]
         x = bytes_to_long(key_data[:len(key_data)//2])
         y = bytes_to_long(key_data[len(key_data)//2:])
         curve_class = self.known_ecdsa_curves[named_curve.get("URI")]
         key = ec.EllipticCurvePublicNumbers(x=x, y=y, curve=curve_class()).public_key(backend=default_backend())
         key.verify(raw_signature,
                    data=signed_info_c14n,
                    signature_algorithm=ec.ECDSA(self._get_signature_digest_method(signature_alg)))
     elif "dsa-" in signature_alg:
         dsa_key_value = self._find(key_value, "DSAKeyValue")
         p = self._get_long(dsa_key_value, "P")
         q = self._get_long(dsa_key_value, "Q")
         g = self._get_long(dsa_key_value, "G", require=False)
         y = self._get_long(dsa_key_value, "Y")
         pn = dsa.DSAPublicNumbers(y=y, parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g))
         key = pn.public_key(backend=default_backend())
         from asn1crypto.algos import DSASignature
         sig_as_der_seq = DSASignature.from_p1363(raw_signature).dump()
         key.verify(sig_as_der_seq,
                    data=signed_info_c14n,
                    algorithm=self._get_signature_digest_method(signature_alg))
     elif "rsa-" in signature_alg:
         rsa_key_value = self._find(key_value, "RSAKeyValue")
         modulus = self._get_long(rsa_key_value, "Modulus")
         exponent = self._get_long(rsa_key_value, "Exponent")
         key = rsa.RSAPublicNumbers(e=exponent, n=modulus).public_key(backend=default_backend())
         key.verify(raw_signature,
                    data=signed_info_c14n,
                    padding=PKCS1v15(),
                    algorithm=self._get_signature_digest_method(signature_alg))
     else:
         raise NotImplementedError()
Exemple #7
0
def decode_dss_signature(signature):
    data = DSASignature.load(signature, strict=True).native
    return data['r'], data['s']
Exemple #8
0
    def sign(self, data, key=None, passphrase=None, cert=None, reference_uri=None, key_name=None, key_info=None,
             id_attribute=None, always_add_key_value=False):
        """
        Sign the data and return the root element of the resulting XML tree.

        :param data: Data to sign
        :type data: String, file-like object, or XML ElementTree Element API compatible object
        :param key:
            Key to be used for signing. When signing with a certificate or RSA/DSA/ECDSA key, this can be a string/bytes
            containing a PEM-formatted key, or a :py:class:`cryptography.hazmat.primitives.interfaces.RSAPrivateKey`,
            :py:class:`cryptography.hazmat.primitives.interfaces.DSAPrivateKey`, or
            :py:class:`cryptography.hazmat.primitives.interfaces.EllipticCurvePrivateKey` object. When signing with a
            HMAC, this should be a string containing the shared secret.
        :type key:
            string, bytes, :py:class:`cryptography.hazmat.primitives.interfaces.RSAPrivateKey`,
            :py:class:`cryptography.hazmat.primitives.interfaces.DSAPrivateKey`, or
            :py:class:`cryptography.hazmat.primitives.interfaces.EllipticCurvePrivateKey` object
        :param passphrase: Passphrase to use to decrypt the key, if any.
        :type passphrase: string
        :param cert:
            X.509 certificate to use for signing. This should be a string containing a PEM-formatted certificate, or an
            array of strings or OpenSSL.crypto.X509 objects containing the certificate and a chain of intermediate
            certificates.
        :type cert: string, array of strings, or array of OpenSSL.crypto.X509 objects
        :param reference_uri:
            Custom reference URI or list of reference URIs to incorporate into the signature. When ``method`` is set to
            ``detached`` or ``enveloped``, reference URIs are set to this value and only the referenced elements are
            signed.
        :type reference_uri: string or list
        :param key_name: Add a KeyName element in the KeyInfo element that may be used by the signer to communicate a
            key identifier to the recipient. Typically, KeyName contains an identifier related to the key pair used to
            sign the message.
        :type key_name: string
        :param key_info:
            A custom KeyInfo element to insert in the signature. Use this to supply ``<wsse:SecurityTokenReference>``
            or other custom key references. An example value can be found here:
            https://github.com/XML-Security/signxml/blob/master/test/wsse_keyinfo.xml
        :type key_info: :py:class:`lxml.etree.Element`
        :param id_attribute:
            Name of the attribute whose value ``URI`` refers to. By default, SignXML will search for "Id", then "ID".
        :type id_attribute: string
        :param always_add_key_value:
            Write the key value to the KeyInfo element even if a X509 certificate is present. Use of this parameter
            is discouraged, as it introduces an ambiguity and a security hazard. The public key used to sign the
            document is already encoded in the certificate (which is in X509Data), so the verifier must either ignore
            KeyValue or make sure it matches what's in the certificate. This parameter is provided for compatibility
            purposes only.
        :type always_add_key_value: boolean

        :returns:
            A :py:class:`lxml.etree.Element` object representing the root of the XML tree containing the signature and
            the payload data.

        To specify the location of an enveloped signature within **data**, insert a
        ``<ds:Signature Id="placeholder"></ds:Signature>`` element in **data** (where
        "ds" is the "http://www.w3.org/2000/09/xmldsig#" namespace). This element will
        be replaced by the generated signature, and excised when generating the digest.
        """
        if id_attribute is not None:
            self.id_attributes = (id_attribute, )

        if isinstance(cert, (str, bytes)):
            cert_chain = list(iterate_pem(cert))
        else:
            cert_chain = cert

        if isinstance(reference_uri, (str, bytes)):
            reference_uris = [reference_uri]
        else:
            reference_uris = reference_uri

        sig_root, doc_root, c14n_inputs, reference_uris = self._unpack(data, reference_uris)
        signed_info_element, signature_value_element = self._build_sig(sig_root, reference_uris, c14n_inputs)

        if key is None:
            raise InvalidInput('Parameter "key" is required')

        signed_info_c14n = self._c14n(signed_info_element, algorithm=self.c14n_alg)
        if self.sign_alg.startswith("hmac-"):
            from cryptography.hazmat.primitives.hmac import HMAC
            signer = HMAC(key=key,
                          algorithm=self._get_hmac_digest_method_by_tag(self.sign_alg),
                          backend=default_backend())
            signer.update(signed_info_c14n)
            signature_value_element.text = ensure_str(b64encode(signer.finalize()))
            sig_root.append(signature_value_element)
        elif any(self.sign_alg.startswith(i) for i in ["dsa-", "rsa-", "ecdsa-"]):
            if isinstance(key, (str, bytes)):
                from cryptography.hazmat.primitives.serialization import load_pem_private_key
                key = load_pem_private_key(ensure_bytes(key), password=passphrase, backend=default_backend())

            hash_alg = self._get_signature_digest_method_by_tag(self.sign_alg)
            if self.sign_alg.startswith("dsa-"):
                signature = key.sign(signed_info_c14n, algorithm=hash_alg)
            elif self.sign_alg.startswith("ecdsa-"):
                signature = key.sign(signed_info_c14n, signature_algorithm=ec.ECDSA(algorithm=hash_alg))
            elif self.sign_alg.startswith("rsa-"):
                signature = key.sign(signed_info_c14n, padding=PKCS1v15(), algorithm=hash_alg)
            else:
                raise NotImplementedError()
            if self.sign_alg.startswith("dsa-"):
                # Note: The output of the DSA signer is a DER-encoded ASN.1 sequence of two DER integers.
                from asn1crypto.algos import DSASignature
                decoded_signature = DSASignature.load(signature).native
                r = decoded_signature['r']
                s = decoded_signature['s']
                signature = long_to_bytes(r).rjust(32, b"\0") + long_to_bytes(s).rjust(32, b"\0")

            signature_value_element.text = ensure_str(b64encode(signature))

            if key_info is None:
                key_info = SubElement(sig_root, ds_tag("KeyInfo"))
                if key_name is not None:
                    keyname = SubElement(key_info, ds_tag("KeyName"))
                    keyname.text = key_name

                if cert_chain is None or always_add_key_value:
                    self._serialize_key_value(key, key_info)

                if cert_chain is not None:
                    x509_data = SubElement(key_info, ds_tag("X509Data"))
                    for cert in cert_chain:
                        x509_certificate = SubElement(x509_data, ds_tag("X509Certificate"))
                        if isinstance(cert, (str, bytes)):
                            x509_certificate.text = strip_pem_header(cert)
                        else:
                            from OpenSSL.crypto import dump_certificate, FILETYPE_PEM
                            x509_certificate.text = strip_pem_header(dump_certificate(FILETYPE_PEM, cert))
            else:
                sig_root.append(key_info)
        else:
            raise NotImplementedError()

        if self.method == methods.enveloping:
            for c14n_input in c14n_inputs:
                doc_root.append(c14n_input)
        return doc_root if self.method == methods.enveloped else sig_root
Exemple #9
0
def decode_dss_signature(signature):
    data = DSASignature.load(signature, strict=True).native
    return data['r'], data['s']
Exemple #10
0
def ecdsa_verify(certificate_or_public_key, signature, data, hash_algorithm):
    """
    Verifies an ECDSA signature in pure Python (thus slow)

    :param certificate_or_public_key:
        A Certificate or PublicKey instance to verify the signature with

    :param signature:
        A byte string of the signature to verify

    :param data:
        A byte string of the data the signature is for

    :param hash_algorithm:
        A unicode string of "md5", "sha1", "sha256", "sha384" or "sha512"

    :raises:
        oscrypto.errors.SignatureError - when the signature is determined to be invalid
        ValueError - when any of the parameters contain an invalid value
        TypeError - when any of the parameters are of the wrong type
        OSError - when an error is returned by the OS crypto library
    """

    has_asn1 = hasattr(certificate_or_public_key, 'asn1')
    if not has_asn1 or not isinstance(certificate_or_public_key.asn1, (keys.PublicKeyInfo, Certificate)):
        raise TypeError(pretty_message(
            '''
            certificate_or_public_key must be an instance of the
            oscrypto.asymmetric.PublicKey or oscrypto.asymmetric.Certificate
            classes, not %s
            ''',
            type_name(certificate_or_public_key)
        ))

    curve_name = certificate_or_public_key.curve
    if curve_name not in set(['secp256r1', 'secp384r1', 'secp521r1']):
        raise ValueError(pretty_message(
            '''
            certificate_or_public_key does not use one of the named curves
            secp256r1, secp384r1 or secp521r1
            '''
        ))

    if not isinstance(signature, byte_cls):
        raise TypeError(pretty_message(
            '''
            signature must be a byte string, not %s
            ''',
            type_name(signature)
        ))

    if not isinstance(data, byte_cls):
        raise TypeError(pretty_message(
            '''
            data must be a byte string, not %s
            ''',
            type_name(data)
        ))

    if hash_algorithm not in set(['sha1', 'sha224', 'sha256', 'sha384', 'sha512']):
        raise ValueError(pretty_message(
            '''
            hash_algorithm must be one of "sha1", "sha224", "sha256", "sha384",
            "sha512", not %s
            ''',
            repr(hash_algorithm)
        ))

    asn1 = certificate_or_public_key.asn1
    if isinstance(asn1, Certificate):
        asn1 = asn1.public_key

    curve_base_point = {
        'secp256r1': SECP256R1_BASE_POINT,
        'secp384r1': SECP384R1_BASE_POINT,
        'secp521r1': SECP521R1_BASE_POINT,
    }[curve_name]

    x, y = asn1['public_key'].to_coords()
    n = curve_base_point.order

    # Validates that the point is valid
    public_key_point = PrimePoint(curve_base_point.curve, x, y, n)

    try:
        signature = DSASignature.load(signature)
        r = signature['r'].native
        s = signature['s'].native
    except (ValueError):
        raise SignatureError('Signature is invalid')

    invalid = 0

    # Check r is valid
    invalid |= r < 1
    invalid |= r >= n

    # Check s is valid
    invalid |= s < 1
    invalid |= s >= n

    if invalid:
        raise SignatureError('Signature is invalid')

    hash_func = getattr(hashlib, hash_algorithm)

    digest = hash_func(data).digest()

    z = int_from_bytes(digest, signed=False) % n
    w = inverse_mod(s, n)
    u1 = (z * w) % n
    u2 = (r * w) % n
    hash_point = (curve_base_point * u1) + (public_key_point * u2)
    if r != (hash_point.x % n):
        raise SignatureError('Signature is invalid')
Exemple #11
0
def ecdsa_sign(private_key, data, hash_algorithm):
    """
    Generates an ECDSA signature in pure Python (thus slow)

    :param private_key:
        The PrivateKey to generate the signature with

    :param data:
        A byte string of the data the signature is for

    :param hash_algorithm:
        A unicode string of "sha1", "sha256", "sha384" or "sha512"

    :raises:
        ValueError - when any of the parameters contain an invalid value
        TypeError - when any of the parameters are of the wrong type
        OSError - when an error is returned by the OS crypto library

    :return:
        A byte string of the signature
    """

    if not hasattr(private_key, 'asn1') or not isinstance(private_key.asn1, keys.PrivateKeyInfo):
        raise TypeError(pretty_message(
            '''
            private_key must be an instance of the
            oscrypto.asymmetric.PrivateKey class, not %s
            ''',
            type_name(private_key)
        ))

    curve_name = private_key.curve
    if curve_name not in set(['secp256r1', 'secp384r1', 'secp521r1']):
        raise ValueError(pretty_message(
            '''
            private_key does not use one of the named curves secp256r1,
            secp384r1 or secp521r1
            '''
        ))

    if not isinstance(data, byte_cls):
        raise TypeError(pretty_message(
            '''
            data must be a byte string, not %s
            ''',
            type_name(data)
        ))

    if hash_algorithm not in set(['sha1', 'sha224', 'sha256', 'sha384', 'sha512']):
        raise ValueError(pretty_message(
            '''
            hash_algorithm must be one of "sha1", "sha224", "sha256", "sha384",
            "sha512", not %s
            ''',
            repr(hash_algorithm)
        ))

    hash_func = getattr(hashlib, hash_algorithm)

    ec_private_key = private_key.asn1['private_key'].parsed
    private_key_bytes = ec_private_key['private_key'].contents
    private_key_int = ec_private_key['private_key'].native

    curve_num_bytes = CURVE_BYTES[curve_name]
    curve_base_point = {
        'secp256r1': SECP256R1_BASE_POINT,
        'secp384r1': SECP384R1_BASE_POINT,
        'secp521r1': SECP521R1_BASE_POINT,
    }[curve_name]

    n = curve_base_point.order

    # RFC 6979 section 3.2

    # a.
    digest = hash_func(data).digest()
    hash_length = len(digest)

    h = int_from_bytes(digest, signed=False) % n

    # b.
    V = b'\x01' * hash_length

    # c.
    K = b'\x00' * hash_length

    # d.
    K = hmac.new(K, V + b'\x00' + private_key_bytes + digest, hash_func).digest()

    # e.
    V = hmac.new(K, V, hash_func).digest()

    # f.
    K = hmac.new(K, V + b'\x01' + private_key_bytes + digest, hash_func).digest()

    # g.
    V = hmac.new(K, V, hash_func).digest()

    # h.
    r = 0
    s = 0
    while True:
        # h. 1
        T = b''

        # h. 2
        while len(T) < curve_num_bytes:
            V = hmac.new(K, V, hash_func).digest()
            T += V

        # h. 3
        k = int_from_bytes(T[0:curve_num_bytes], signed=False)
        if k == 0 or k >= n:
            continue

        # Calculate the signature in the loop in case we need a new k
        r = (curve_base_point * k).x % n
        if r == 0:
            continue

        s = (inverse_mod(k, n) * (h + (private_key_int * r) % n)) % n
        if s == 0:
            continue

        break

    return DSASignature({'r': r, 's': s}).dump()
Exemple #12
0
    def sign(self, data, key=None, passphrase=None, cert=None, reference_uri=None, key_name=None, key_info=None,
             id_attribute=None):
        """
        Sign the data and return the root element of the resulting XML tree.

        :param data: Data to sign
        :type data: String, file-like object, or XML ElementTree Element API compatible object
        :param key:
            Key to be used for signing. When signing with a certificate or RSA/DSA/ECDSA key, this can be a string
            containing a PEM-formatted key, or a :py:class:`cryptography.hazmat.primitives.interfaces.RSAPublicKey`,
            :py:class:`cryptography.hazmat.primitives.interfaces.DSAPublicKey`, or
            :py:class:`cryptography.hazmat.primitives.interfaces.EllipticCurvePublicKey` object. When signing with a
            HMAC, this should be a string containing the shared secret.
        :type key:
            string, :py:class:`cryptography.hazmat.primitives.interfaces.RSAPublicKey`,
            :py:class:`cryptography.hazmat.primitives.interfaces.DSAPublicKey`, or
            :py:class:`cryptography.hazmat.primitives.interfaces.EllipticCurvePublicKey` object
        :param passphrase: Passphrase to use to decrypt the key, if any.
        :type passphrase: string
        :param cert:
            X.509 certificate to use for signing. This should be a string containing a PEM-formatted certificate, or an
            array of strings or OpenSSL.crypto.X509 objects containing the certificate and a chain of intermediate
            certificates.
        :type cert: string, array of strings, or array of OpenSSL.crypto.X509 objects
        :param reference_uri:
            Custom reference URI or list of reference URIs to incorporate into the signature. When ``method`` is set to
            ``detached`` or ``enveloped``, reference URIs are set to this value and only the referenced elements are
            signed.
        :type reference_uri: string or list
        :param key_name: Add a KeyName element in the KeyInfo element that may be used by the signer to communicate a
            key identifier to the recipient. Typically, KeyName contains an identifier related to the key pair used to
            sign the message.
        :type key_name: string
        :param key_info: A custom KeyInfo element to insert in the signature. Use this to supply
            ``<wsse:SecurityTokenReference>`` or other custom key references.
        :type key_info: :py:class:`lxml.etree.Element`
        :param id_attribute:
            Name of the attribute whose value ``URI`` refers to. By default, SignXML will search for "Id", then "ID".
        :type id_attribute: string

        :returns:
            A :py:class:`lxml.etree.Element` object representing the root of the XML tree containing the signature and
            the payload data.

        To specify the location of an enveloped signature within **data**, insert a
        ``<ds:Signature Id="placeholder"></ds:Signature>`` element in **data** (where
        "ds" is the "http://www.w3.org/2000/09/xmldsig#" namespace). This element will
        be replaced by the generated signature, and excised when generating the digest.
        """
        if id_attribute is not None:
            self.id_attributes = (id_attribute, )

        if isinstance(cert, (str, bytes)):
            cert_chain = list(iterate_pem(cert))
        else:
            cert_chain = cert

        if isinstance(reference_uri, (str, bytes)):
            reference_uris = [reference_uri]
        else:
            reference_uris = reference_uri

        sig_root, doc_root, c14n_inputs, reference_uris = self._unpack(data, reference_uris)
        signed_info_element, signature_value_element = self._build_sig(sig_root, reference_uris, c14n_inputs)

        if key is None:
            raise InvalidInput('Parameter "key" is required')

        signed_info_c14n = self._c14n(signed_info_element, algorithm=self.c14n_alg)
        if self.sign_alg.startswith("hmac-"):
            from cryptography.hazmat.primitives.hmac import HMAC
            signer = HMAC(key=key,
                          algorithm=self._get_hmac_digest_method_by_tag(self.sign_alg),
                          backend=default_backend())
            signer.update(signed_info_c14n)
            signature_value_element.text = ensure_str(b64encode(signer.finalize()))
            sig_root.append(signature_value_element)
        elif any(self.sign_alg.startswith(i) for i in ["dsa-", "rsa-", "ecdsa-"]):
            if isinstance(key, (str, bytes)):
                from cryptography.hazmat.primitives.serialization import load_pem_private_key
                key = load_pem_private_key(key, password=passphrase, backend=default_backend())

            hash_alg = self._get_signature_digest_method_by_tag(self.sign_alg)
            if self.sign_alg.startswith("dsa-"):
                signature = key.sign(signed_info_c14n, algorithm=hash_alg)
            elif self.sign_alg.startswith("ecdsa-"):
                signature = key.sign(signed_info_c14n, signature_algorithm=ec.ECDSA(algorithm=hash_alg))
            elif self.sign_alg.startswith("rsa-"):
                signature = key.sign(signed_info_c14n, padding=PKCS1v15(), algorithm=hash_alg)
            else:
                raise NotImplementedError()
            if self.sign_alg.startswith("dsa-"):
                # Note: The output of the DSA signer is a DER-encoded ASN.1 sequence of two DER integers.
                from asn1crypto.algos import DSASignature
                decoded_signature = DSASignature.load(signature).native
                r = decoded_signature['r']
                s = decoded_signature['s']
                signature = long_to_bytes(r).rjust(32, b"\0") + long_to_bytes(s).rjust(32, b"\0")

            signature_value_element.text = ensure_str(b64encode(signature))

            if key_info is None:
                key_info = SubElement(sig_root, ds_tag("KeyInfo"))
                if key_name is not None:
                    keyname = SubElement(key_info, ds_tag("KeyName"))
                    keyname.text = key_name

                if cert_chain is None:
                    self._serialize_key_value(key, key_info)
                else:
                    x509_data = SubElement(key_info, ds_tag("X509Data"))
                    for cert in cert_chain:
                        x509_certificate = SubElement(x509_data, ds_tag("X509Certificate"))
                        if isinstance(cert, (str, bytes)):
                            x509_certificate.text = strip_pem_header(cert)
                        else:
                            from OpenSSL.crypto import dump_certificate, FILETYPE_PEM
                            x509_certificate.text = strip_pem_header(dump_certificate(FILETYPE_PEM, cert))
            else:
                sig_root.append(key_info)
        else:
            raise NotImplementedError()

        if self.method == methods.enveloping:
            for c14n_input in c14n_inputs:
                doc_root.append(c14n_input)
        return doc_root if self.method == methods.enveloped else sig_root