Ejemplo n.º 1
0
def _c14n(t,
          exclusive,
          with_comments,
          inclusive_prefix_list=None,
          schema=None):
    """
    Perform XML canonicalization (c14n) on an lxml.etree.

    :param t: XML as lxml.etree
    :param exclusive: boolean
    :param with_comments: boolean, keep comments or not
    :param inclusive_prefix_list: List of namespaces to include (?)
    :returns: XML as string (utf8)
    """
    xml_str = etree.tostring(t)
    doc = parse_xml(xml_str,
                    remove_whitespace=config.c14n_strip_ws,
                    remove_comments=not with_comments,
                    schema=schema)
    buf = etree.tostring(doc,
                         method='c14n',
                         exclusive=exclusive,
                         with_comments=with_comments,
                         inclusive_ns_prefixes=inclusive_prefix_list)
    u = unescape_xml_entities(buf.decode("utf8",
                                         'replace')).encode("utf8").strip()
    if u[0] != '<':
        raise XMLSigException("C14N buffer doesn't start with '<'")
    if u[-1] != '>':
        raise XMLSigException("C14N buffer doesn't end with '>'")
    return u
Ejemplo n.º 2
0
    def __init__(self, filename, private):
        super(XMLSecCryptoFile, self).__init__(source='file',
                                               do_padding=False,
                                               private=private,
                                               do_digest=False)
        with io.open(filename, "rb") as file:
            if private:
                self.key = serialization.load_pem_private_key(
                    file.read(), password=None, backend=default_backend())
                if not isinstance(self.key, rsa.RSAPrivateKey):
                    raise XMLSigException(
                        "We don't support non-RSA private keys at the moment.")

                # XXX Do not leak private key -- is there any situation
                # where we might need this pem?
                self.cert_pem = None
                # self.cert_pem = self.key.private_bytes(
                #     encoding=serialization.Encoding.PEM,
                #     format=serialization.PrivateFormat.PKCS8,
                #     encryption_algorithm=serialization.NoEncryption())

                self.keysize = self.key.key_size
            else:
                self.key = load_pem_x509_certificate(file.read(),
                                                     backend=default_backend())
                if not isinstance(self.key.public_key(), rsa.RSAPublicKey):
                    raise XMLSigException(
                        "We don't support non-RSA public keys at the moment.")

                self.cert_pem = self.key.public_bytes(
                    encoding=serialization.Encoding.PEM)
                self.keysize = self.key.public_key().key_size

        self._from_file = filename  # for debugging
Ejemplo n.º 3
0
def _verify(t, keyspec, sig_path=".//{%s}Signature" % NS['ds']):
    """
    Verify the signature(s) in an XML document.

    Throws an XMLSigException on any non-matching signatures.

    :param t: XML as lxml.etree
    :param keyspec: X.509 cert filename, string with fingerprint or X.509 cert as string
    :returns: True if signature(s) validated, False if there were no signatures
    """
    if config.debug_write_to_files:
        with open("/tmp/foo-sig.xml", "w") as fd:
            fd.write(etree.tostring(root_elt(t)))

    # Load and parse certificate, unless keyspec is a fingerprint.
    cert = _load_keyspec(keyspec)

    validated = []
    for sig in t.findall(sig_path):
        sv = sig.findtext(".//{%s}SignatureValue" % NS['ds'])
        if sv is None:
            raise XMLSigException("No SignatureValue")

        this_f_public = None
        this_keysize = None
        if cert is None:
            # keyspec is fingerprint - look for matching certificate in XML
            this_cert = _load_keyspec(keyspec, signature_element=sig)
            if this_cert is None:
                raise XMLSigException(
                    "Could not find certificate to validate signature")
            this_f_public = this_cert['f_public']
            this_keysize = this_cert['keysize']
        else:
            # Non-fingerprint keyspec, use pre-parsed values
            this_cert = cert
            this_f_public = cert['f_public']
            this_keysize = cert['keysize']

        logging.debug("key size: %d bits" % this_cert['keysize'])

        if this_cert is None:
            raise XMLSigException(
                "Could not find certificate to validate signature")

        si = sig.find(".//{%s}SignedInfo" % NS['ds'])
        cm_alg = _cm_alg(si)
        digest_alg = _sig_digest(si)

        validated_objects = _process_references(t, sig, sig_path)
        b_digest = _create_signature_digest(si, cm_alg, digest_alg)
        actual = _signed_value(b_digest, this_keysize, True, digest_alg)
        expected = this_f_public(b64d(sv))

        if expected != actual:
            raise XMLSigException("Signature validation failed")
        validated.extend(validated_objects)

    return validated
Ejemplo n.º 4
0
def sign(t, key_spec, cert_spec=None, reference_uri=''):
    """
    Sign an XML document. This means to 'complete' all Signature elements in the XML.

    :param t: XML as lxml.etree
    :param key_spec: private key reference, see _load_keyspec() for syntax.
    :param cert_spec: None or public key reference (to add cert to document), see _load_keyspec() for syntax.
    :param reference_uri: Envelope signature reference URI
    :returns: XML as lxml.etree (for convenience, 't' is modified in-place)
    """
    do_padding = False  # only in the case of our fallback keytype do we need to do pkcs1 padding here

    private = _load_keyspec(key_spec, private=True)
    if private is None:
        raise XMLSigException("Unable to load private key from '%s'" % key_spec)

    if private['source'] == 'file':
        do_padding = True  # need to do p1 padding in this case

    if cert_spec is None and private['source'] == 'pkcs11':
        cert_spec = private['data']
        logging.debug("Using P11 cert_spec :\n%s" % cert_spec)

    public = _load_keyspec(cert_spec)
    if public is None:
        raise XMLSigException("Unable to load public key from '%s'" \
                              % (cert_spec))
    if public['keysize'] != private['keysize']:
        raise XMLSigException("Public and private key sizes do not match (%s, %s)" \
                                  % (public['keysize'], private['keysize']))
    logging.debug("Using %s bit key" % (private['keysize']))

    if t.find(".//{%s}Signature" % NS['ds']) is None:
        add_enveloped_signature(t, reference_uri=reference_uri)

    if _DEBUG_WRITE_TO_FILES:
        with open("/tmp/sig-ref.xml", "w") as fd:
            fd.write(etree.tostring(_root(t)))

    for sig in t.findall(".//{%s}Signature" % NS['ds']):
        hash_alg = _process_references(t, sig)
        si = sig.find(".//{%s}SignedInfo" % NS['ds'])
        b_digest = _create_signature_digest(si, hash_alg)

        # RSA sign hash digest and insert it into the XML
        tbs = _signed_value(b_digest, private['keysize'], do_padding, hash_alg)
        signed = private['f_private'](tbs)
        signature = b64e(signed)
        logging.debug("SignatureValue: %s" % signature)
        si.addnext(DS.SignatureValue(signature))

        if public is not None:
            # Insert cert_data as b64-encoded X.509 certificate into XML document
            sv_elt = si.getnext()
            sv_elt.addnext(DS.KeyInfo(DS.X509Data(DS.X509Certificate(pem2b64(public['data'])))))

    return t
Ejemplo n.º 5
0
def _ref_digest(ref):
    dm = ref.find(".//{%s}DigestMethod" % NS['ds'])
    if dm is None:
        raise XMLSigException(
            "Unable to find DigestMethod for Reference@URI {!s}".format(
                ref.get('URI')))
    alg_uri = _alg(dm)
    hash_alg = (alg_uri.split("#"))[1]
    if not hash_alg:
        raise XMLSigException(
            "Unable to determine digest algorithm from {!s}".format(alg_uri))
    return hash_alg
Ejemplo n.º 6
0
def _ref_digest(ref):
    dm = ref.find(".//{%s}DigestMethod" % NS['ds'])
    if dm is None:
        raise XMLSigException(
            "Unable to find DigestMethod for Reference@URI {!s}".format(
                ref.get('URI')))
    alg_uri = _alg(dm)
    if alg_uri is None:
        raise XMLSigException("No suitable DigestMethod")
    hash_alg = constants.sign_alg_xmldsig_digest_to_internal(alg_uri.lower())

    return hash_alg
Ejemplo n.º 7
0
def parse_uri(pk11_uri):
    o = urlparse(pk11_uri)
    if o.scheme != 'pkcs11':
        raise XMLSigException("Bad URI scheme in pkcs11 URI %s" % pk11_uri)

    logging.debug("parsed pkcs11 uri: %s" % repr(o))

    slot = 0
    library = None
    keyname = None
    query = {}

    if not '/' in o.path:
        raise XMLSigException(
            "Missing keyname part in pkcs11 URI (pkcs11://[library[:slot]/]keyname[?pin=<pin>])"
        )

    (module_path, sep, keyqs) = o.path.rpartition('/')

    qs = o.query
    if qs:
        keyname = keyqs
    elif '?' in keyqs:
        (keyname, sep, qss) = keyqs.rpartition('?')
        qs = qss
    else:
        keyname = keyqs

    if qs:
        for av in qs.split('&'):
            if not '=' in av:
                raise XMLSigException("Bad query string in pkcs11 URI %s" %
                                      pk11_uri)
            (a, sep, v) = av.partition('=')
            assert a
            assert v
            query[a] = v

    if ':' in module_path:
        (library, sep, slot_str) = module_path.rpartition(":")
        slot = int(slot_str)
    else:
        library = module_path

    if library is None or len(library) == 0:
        library = os.environ.get('PYKCS11LIB', None)

    if library is None or len(library) == 0:
        raise XMLSigException("No PKCS11 module in pkcs11 URI %s" % pk11_uri)

    logging.debug("returning %s %s %s %s" % (library, slot, keyname, query))
    return library, slot, keyname, query
Ejemplo n.º 8
0
def _verify(t,
            keyspec,
            sig_path=".//{%s}Signature" % NS['ds'],
            drop_signature=False):
    """
    Verify the signature(s) in an XML document.

    Throws an XMLSigException on any non-matching signatures.

    :param t: XML as lxml.etree
    :param keyspec: X.509 cert filename, string with fingerprint or X.509 cert as string
    :returns: True if signature(s) validated, False if there were no signatures
    """
    if config.debug_write_to_files:
        with open("/tmp/foo-sig.xml", "w") as fd:
            fd.write(etree.tostring(root_elt(t)))

    validated = []
    for sig in t.findall(sig_path):
        try:
            sv = sig.findtext(".//{%s}SignatureValue" % NS['ds'])
            if not sv:
                raise XMLSigException("No SignatureValue")

            logging.debug("SignatureValue: {!s}".format(sv))
            this_cert = xmlsec.crypto.from_keyspec(keyspec,
                                                   signature_element=sig)
            logging.debug("key size: {!s} bits".format(this_cert.keysize))

            si = sig.find(".//{%s}SignedInfo" % NS['ds'])
            logging.debug("Found signedinfo {!s}".format(etree.tostring(si)))
            cm_alg = _cm_alg(si)
            sig_digest_alg = _sig_digest(si)

            refmap = _process_references(t,
                                         sig,
                                         sig_path=sig_path,
                                         drop_signature=drop_signature)
            for ref, obj in refmap.items():
                b_digest = _create_signature_digest(si, cm_alg, sig_digest_alg)
                actual = _signed_value(b_digest, this_cert.keysize, True,
                                       sig_digest_alg)
                if not this_cert.verify(b64d(sv), actual):
                    raise XMLSigException(
                        "Failed to validate {!s} using ref digest {!s} and cm {!s}"
                        .format(etree.tostring(sig), ref_digest_alg, cm_alg))
                validated.append(obj)
        except XMLSigException, ex:
            logging.error(ex)
Ejemplo n.º 9
0
def _signed_value(data, key_size, do_pad, hash_alg):  # TODO Do proper asn1 CMS
    """Return unencrypted rsa-sha1 signature value `padded_digest` from `data`.

    The resulting signed value will be in the form:
    (01 | FF* | 00 | prefix | digest) [RSA-SHA1]
    where "digest" is of the generated c14n xml for <SignedInfo>.

    Args:
      data: str of bytes to sign
      key_size: int of key length in bits; => len(`data`) + 3
    Returns:
      str: rsa-sha1 signature value of `data`
    """

    prefix = ASN1_BER_ALG_DESIGNATOR_PREFIX.get(hash_alg)
    if not prefix:
        raise XMLSigException("Unknown hash algorithm %s" % hash_alg)
    asn_digest = prefix + data
    if do_pad:
        # Pad to "one octet shorter than the RSA modulus" [RSA-SHA1]
        # WARNING: key size is in bits, not bytes!
        padded_size = key_size / 8 - 1
        pad_size = padded_size - len(asn_digest) - 2
        pad = '\x01' + '\xFF' * pad_size + '\x00'
        return pad + asn_digest
    else:
        return asn_digest
Ejemplo n.º 10
0
def _sig_alg(si):
    sm = si.find(".//{%s}SignatureMethod" % NS['ds'])
    sig_uri = _alg(sm)
    if sm is None or sig_uri is None:
        raise XMLSigException("No SignatureMethod")

    return constants.sign_alg_xmldsig_sig_to_internal(sig_uri.lower())
Ejemplo n.º 11
0
    def __init__(self, signature_element, keyspec):
        source = None
        data = None
        #print "XMLSecCryptoFromXML using %s and keyspec=%s" % (signature_element, keyspec)
        fp = keyspec
        if ':' not in keyspec:
            fp, _ = _cert_fingerprint(keyspec)
        cd = _find_cert_by_fingerprint(signature_element, fp)
        if cd is not None:
            data = cd
            source = 'signature_element'
        elif '-----BEGIN' in keyspec:
            data = keyspec
            source = 'keyspec'

        if data is None:
            raise ValueError("Unable to find cert matching fingerprint: %s" %
                             fp)

        super(XMLSecCryptoFromXML, self).__init__(source=source,
                                                  do_padding=False,
                                                  private=False,
                                                  do_digest=False)

        self.key = load_pem_x509_certificate(data, backend=default_backend())
        if not isinstance(self.key.public_key(), rsa.RSAPublicKey):
            raise XMLSigException(
                "We don't support non-RSA public keys at the moment.")

        # XXX now we could implement encrypted-PEM-support
        self.cert_pem = self.key.public_bytes(
            encoding=serialization.Encoding.PEM)

        self.keysize = self.key.public_key().key_size
        self._from_keyspec = keyspec  # for debugging
Ejemplo n.º 12
0
 def sign(self, data, hash_alg, pad_alg="PKCS1v15"):
     if self.is_private:
         hasher = getattr(hashes, hash_alg)
         padder = getattr(padding, pad_alg)
         return self.key.sign(data, padder(), hasher())
     else:
         raise XMLSigException('Signing is only possible with a private key.')
Ejemplo n.º 13
0
def _transform(uri,
               t,
               tr=None,
               schema=None,
               sig_path=".//{%s}Signature" % NS['ds']):
    if uri == constants.TRANSFORM_ENVELOPED_SIGNATURE:
        return _enveloped_signature(t, sig_path)

    if uri == constants.TRANSFORM_C14N_EXCLUSIVE_WITH_COMMENTS:
        return _c14n(t,
                     exclusive=True,
                     with_comments=True,
                     inclusive_prefix_list=_find_nslist(tr),
                     schema=schema)

    if uri == constants.TRANSFORM_C14N_EXCLUSIVE:
        return _c14n(t,
                     exclusive=True,
                     with_comments=False,
                     inclusive_prefix_list=_find_nslist(tr),
                     schema=schema)

    if uri == constants.TRANSFORM_C14N_INCLUSIVE:
        return _c14n(t, exclusive=False, with_comments=False, schema=schema)

    raise XMLSigException("unknown or unimplemented transform %s" % uri)
Ejemplo n.º 14
0
def _signed_value(data, key_size, do_pad, hash_alg):  # TODO Do proper asn1 CMS
    """Return unencrypted rsa-sha1 signature value `padded_digest` from `data`.

    The resulting signed value will be in the form:
    (01 | FF* | 00 | prefix | digest) [RSA-SHA1]
    where "digest" is of the generated c14n xml for <SignedInfo>.

    :param data: str of bytes to sign
    :param key_size: key length (if known) in bits; => len(`data`) + 3
    :param do_pad: Do PKCS1 (?) padding of the data - requires integer key_size
    :param hash_alg: Hash algorithm as string (e.g. 'sha1')
    :returns: rsa-sha signature value of `data`

    :type data: string
    :type key_size: None | int
    :type do_pad: bool
    :type hash_alg: string
    :rtype: string
    """

    prefix = constants.ASN1_BER_ALG_DESIGNATOR_PREFIX.get(hash_alg)
    if not prefix:
        raise XMLSigException("Unknown hash algorithm %s" % hash_alg)
    asn_digest = prefix + data
    if do_pad:
        # Pad to "one octet shorter than the RSA modulus" [RSA-SHA1]
        # WARNING: key size is in bits, not bytes!
        padded_size = key_size / 8 - 1
        pad_size = padded_size - len(asn_digest) - 2
        pad = '\x01' + '\xFF' * pad_size + '\x00'
        return pad + asn_digest
    else:
        return asn_digest
Ejemplo n.º 15
0
def _process_references(t, sig=None):
    """
    :returns: hash algorithm as string
    """
    if sig is None:
        sig = t.find(".//{%s}Signature" % NS['ds'])
    hash_alg = None
    for ref in sig.findall(".//{%s}Reference" % NS['ds']):
        obj = None
        uri = ref.get('URI', None)
        if uri is None or uri == '#' or uri == '':
            ct = _remove_child_comments(_root(copy.deepcopy(t)))
            obj = _root(ct)
        elif uri.startswith('#'):
            ct = copy.deepcopy(t)
            obj = _remove_child_comments(_get_by_id(ct, uri[1:]))
        else:
            raise XMLSigException("Unknown reference %s" % uri)

        if obj is None:
            raise XMLSigException("Unable to dereference Reference URI='%s'" % uri)

        for tr in ref.findall(".//{%s}Transform" % NS['ds']):
            logging.debug("transform: %s" % _alg(tr))
            obj = _transform(_alg(tr), obj, tr)

        if _DEBUG_WRITE_TO_FILES:
            with open("/tmp/foo-obj.xml", "w") as fd:
                fd.write(obj)

        dm = ref.find(".//{%s}DigestMethod" % NS['ds'])
        if dm is None:
            raise XMLSigException("Unable to find DigestMethod")
        this_hash_alg = (_alg(dm).split("#"))[1]
        logging.debug("using hash algorithm %s" % this_hash_alg)
        hash_alg = hash_alg or this_hash_alg
        if this_hash_alg != hash_alg:
            raise XMLSigException("Unable to handle more than one hash algorithm (%s != %s)"
                                  % (this_hash_alg, hash_alg))
        digest = _digest(obj, this_hash_alg)
        logging.debug("digest for %s: %s" % (uri, digest))
        dv = ref.find(".//{%s}DigestValue" % NS['ds'])
        logging.debug(etree.tostring(dv))
        dv.text = digest
    return hash_alg
Ejemplo n.º 16
0
 def sign(self, data, hash_alg, pad_alg="PKCS1v15"):
     if self.is_private:
         if not isinstance(data, six.binary_type):
             data = unicode_to_bytes(data)
         hasher = getattr(hashes, hash_alg)
         padder = getattr(padding, pad_alg)
         return self.key.sign(data, padder(), hasher())
     else:
         raise XMLSigException('Signing is only possible with a private key.')
Ejemplo n.º 17
0
def from_keyspec(keyspec, private=False, signature_element=None):
    """
    Load a key referenced by a keyspec (see below).

    To 'load' a key means different things based on what can be loaded through a
    given specification. For example, if keyspec is a a PKCS#11 reference to a
    private key then naturally the key itself is not available.

    Possible keyspecs, in evaluation order :

      - a callable.    Return a partial dict with 'f_private' set to the keyspec.
      - a filename.    Load a PEM X.509 certificate from the file.
      - a PKCS#11-URI  (see xmlsec.pk11.parse_uri()). Return a dict with 'f_private'
                       set to a function calling the 'sign' function for the key,
                       and the rest based on the (public) key returned by
                       xmlsec.pk11.signer().
      - an http:// URL REST URL used for signing (see pyeleven).
      - a fingerprint. If signature_element is provided, the key is located using
                       the fingerprint (provided as string).
      - X.509 string.  An X.509 certificate as string.

    If the keyspec is prefixed by 'xmlsec+', that prefix will be removed.
    This is a workaround for pysaml2 that handles keyspecs starting with
    'http' differently.

    Resulting dictionary (used except for 'callable') :

      {'keyspec': keyspec,
       'source': 'pkcs11' or 'file' or 'fingerprint' or 'keyspec',
       'data': X.509 certificate as string if source != 'pkcs11',
       'key': Parsed key from certificate if source != 'pkcs11',
       'keysize': Keysize in bits if source != 'pkcs11',
       'f_public': rsa_x509_pem.f_public(key) if private == False,
       'f_private': rsa_x509_pem.f_private(key) if private == True,
      }

    :param keyspec: Keyspec as string or callable. See above.
    :param private: True of False, is keyspec a private key or not?
    :param signature_element:
    :returns: dict, see above.
    """
    if keyspec.startswith('xmlsec+'):
        # workaround for pysaml2 which handles http keyspecs differently
        keyspec = keyspec[7:]
    thread_local = threading.local()
    cache = getattr(thread_local, 'keycache', {})
    if keyspec in cache:
        return cache[keyspec]
    key = _load_keyspec(keyspec, private, signature_element)

    if key is None:
        raise XMLSigException(
            'Unable to load private key from {!s}'.format(keyspec))

    cache[keyspec] = key
    thread_local.cache = cache
    return key
Ejemplo n.º 18
0
def delete_elt(elt):
    if elt.getparent() is None:
        raise XMLSigException("Cannot delete root")
    if elt.tail is not None:
        #logging.debug("tail: '%s'" % elt.tail)
        p = elt.getprevious()
        if p is not None:
            #logging.debug("adding tail to previous")
            if p.tail is None:
                p.tail = ''
            p.tail += elt.tail
        else:
            #logging.debug("adding tail to parent")
            up = elt.getparent()
            if up is None:
                raise XMLSigException("Signature has no parent")
            if up.text is None:
                up.text = ''
            up.text += elt.tail
    elt.getparent().remove(elt)
Ejemplo n.º 19
0
def _c14n(t, exclusive, with_comments, inclusive_prefix_list=None):
    """
    Perform XML canonicalization (c14n) on an lxml.etree.

    NOTE: The c14n done here is missing whitespace removal. The whitespace has to
    be removed at parse time. One way to do that is to use xmlsec.parse_xml().

    :param t: XML as lxml.etree
    :param exclusive: boolean
    :param with_comments: boolean, keep comments or not
    :param inclusive_prefix_list: List of namespaces to include (?)
    :returns: XML as string (utf8)
    """
    cxml = etree.tostring(t, method="c14n", exclusive=exclusive, with_comments=with_comments,
                          inclusive_ns_prefixes=inclusive_prefix_list)
    u = _unescape(cxml.decode("utf8", 'replace')).encode("utf8").strip()
    if u[0] != '<':
        raise XMLSigException("C14N buffer doesn't start with '<'")
    if u[-1] != '>':
        raise XMLSigException("C14N buffer doesn't end with '>'")
    return u
Ejemplo n.º 20
0
def _create_signature_digest(si, hash_alg):
    """
    :param hash_alg: string such as 'sha1'
    """
    cm = si.find(".//{%s}CanonicalizationMethod" % NS['ds'])
    cm_alg = _alg(cm)
    if cm is None or cm_alg is None:
        raise XMLSigException("No CanonicalizationMethod")
    sic = _transform(cm_alg, si)
    logging.debug("SignedInfo C14N: %s" % sic)
    digest = _digest(sic, hash_alg)
    logging.debug("SignedInfo digest: %s" % digest)
    return b64d(digest)
Ejemplo n.º 21
0
 def verify(self, signature, msg, hash_alg, pad_alg="PKCS1v15"):
     if not self.is_private:
         try:
             hasher = getattr(hashes, hash_alg)
             padder = getattr(padding, pad_alg)
             self.key.public_key().verify(signature, msg, padder(),
                                          hasher())
         except InvalidSignature:
             return False
         return True
     else:
         raise XMLSigException(
             'Verifying is only possible with a certificate.')
Ejemplo n.º 22
0
 def verify(self, signature, msg, hash_alg, pad_alg="PKCS1v15"):
     if not self.is_private:
         if not isinstance(msg, six.binary_type):
             msg = unicode_to_bytes(msg)
         try:
             hasher = getattr(hashes, hash_alg)
             padder = getattr(padding, pad_alg)
             self.key.public_key().verify(signature, msg, padder(),
                                          hasher())
         except InvalidSignature:
             return False
         return True
     else:
         raise XMLSigException(
             'Verifying is only possible with a certificate.')
Ejemplo n.º 23
0
 def sign(self, data, hash_alg=None):
     try:
         import requests
         import json
         url = '{!s}/rawsign'.format(self._keyspec)
         r = requests.post(url, json=dict(mech='RSAPKCS1', data=data.encode("base64")))
         if r.status_code != requests.codes.ok:
             r.raise_for_status()
         msg = r.json()
         if not 'signed' in msg:
             raise ValueError("Missing signed data in response message")
         return msg['signed'].decode('base64')
     except Exception, ex:
         from traceback import print_exc
         print_exc(ex)
         raise XMLSigException(ex)
Ejemplo n.º 24
0
    def __init__(self, keyspec):
        super(XMLSecCryptoP11, self).__init__(source='pkcs11', do_padding=False, private=True)

        from xmlsec import pk11

        self._private_callable, data = pk11.signer(keyspec)
        logging.debug("Using pkcs11 signing key: {!s}".format(self._private_callable))
        if data is not None:
            self.key = load_pem_x509_certificate(data, backend=default_backend())
            if not isinstance(self.key.public_key(), rsa.RSAPublicKey):
                raise XMLSigException("We don't support non-RSA public keys at the moment.")

            self.cert_pem = self.key.public_bytes(encoding=serialization.Encoding.PEM)
            self.keysize = self.key.public_key().key_size

        self._from_keyspec = keyspec  # for debugging
Ejemplo n.º 25
0
def signer(pk11_uri, mech=PyKCS11.MechanismRSAPKCS1):
    library, slot, keyname, query = parse_uri(pk11_uri)

    pin = None
    pin_spec = query.get('pin', "env:PYKCS11PIN")
    if pin_spec.startswith("env:"):
        pin = os.environ.get(pin_spec[4:], None)
    else:
        pin = pin_spec

    session = _session(str(library), slot, str(pin))

    key, cert = _find_key(session, keyname)
    if key is None:
        raise XMLSigException("No such key: %s" % pk11_uri)

    if cert is not None:
        logging.info("Found matching cert in token")

    return lambda data: _sign_and_close(session, key, data, mech), cert
Ejemplo n.º 26
0
def _cert2dict(cert):
    """
    Build cert_dict similar to old rsa_x509_pem backend. Shouldn't
    be used by new code.
    @param cert A cryptography.x509.Certificate object
    """
    key = cert.public_key()
    if not isinstance(key, rsa.RSAPublicKey):
        raise XMLSigException(
            "We don't support non-RSA public keys at the moment.")
    cdict = dict()
    cdict['type'] = "X509 CERTIFICATE"
    cdict['pem'] = cert.public_bytes(encoding=serialization.Encoding.PEM)
    cdict['body'] = b64encode(
        cert.public_bytes(encoding=serialization.Encoding.DER))
    n = key.public_numbers()
    cdict['modulus'] = n.n
    cdict['publicExponent'] = n.e
    cdict['subject'] = cert.subject
    cdict['cert'] = RSAobjShim(cert)

    return cdict
Ejemplo n.º 27
0
 def sign(self, data, hash_alg=None):
     try:
         import requests
         import json
         url = '{!s}/rawsign'.format(self._keyspec)
         if not isinstance(data, six.binary_type):
             data = data.encode("utf-8")
         data = base64.b64encode(data)
         r = requests.post(url, json=dict(mech='RSAPKCS1', data=data))
         if r.status_code != requests.codes.ok:
             r.raise_for_status()
         msg = r.json()
         if 'signed' not in msg:
             raise ValueError("Missing signed data in response message")
         signed_msg = msg['signed']
         if not isinstance(signed_msg, six.binary_type):
             signed_msg = signed_msg.encode("utf-8")
         return base64.b64decode(signed_msg)
     except Exception as ex:
         from traceback import format_exc
         log.debug(format_exc())
         raise XMLSigException(ex)
Ejemplo n.º 28
0
def _transform(uri,
               t,
               tr=None,
               schema=None,
               sig_path=".//{%s}Signature" % NS['ds']):
    if uri == constants.TRANSFORM_ENVELOPED_SIGNATURE:
        return _enveloped_signature(t, sig_path)

    if uri == constants.TRANSFORM_C14N_EXCLUSIVE_WITH_COMMENTS:
        nslist = None
        if tr is not None:
            elt = tr.find(".//{%s}InclusiveNamespaces" %
                          'http://www.w3.org/2001/10/xml-exc-c14n#')
            if elt is not None:
                nslist = elt.get('PrefixList', '').split()
        return _c14n(t,
                     exclusive=True,
                     with_comments=True,
                     inclusive_prefix_list=nslist,
                     schema=schema)

    if uri == constants.TRANSFORM_C14N_EXCLUSIVE:
        nslist = None
        if tr is not None:
            elt = tr.find(".//{%s}InclusiveNamespaces" %
                          'http://www.w3.org/2001/10/xml-exc-c14n#')
            if elt is not None:
                nslist = elt.get('PrefixList', '').split()
        return _c14n(t,
                     exclusive=True,
                     with_comments=False,
                     inclusive_prefix_list=nslist,
                     schema=schema)

    if uri == constants.TRANSFORM_C14N_INCLUSIVE:
        return _c14n(t, exclusive=False, with_comments=False, schema=schema)

    raise XMLSigException("unknown or unimplemented transform %s" % uri)
Ejemplo n.º 29
0
def _try_a_to_b(dic, item):
    try:
        return dic[item]
    except KeyError:
        raise XMLSigException("Algorithm '%s' not supported." % item)
Ejemplo n.º 30
0
__author__ = 'leifj'

from xmlsec.exceptions import XMLSigException
from six.moves.urllib_parse import urlparse
import os
import logging
from xmlsec.utils import b642pem

_modules = {}

try:
    import PyKCS11
    from PyKCS11.LowLevel import CKA_ID, CKA_LABEL, CKA_CLASS, CKO_PRIVATE_KEY, CKO_CERTIFICATE, CKK_RSA, CKA_KEY_TYPE, CKA_VALUE
except ImportError:
    raise XMLSigException("pykcs11 is required for PKCS#11 keys - cf README.rst")

all_attributes = list(PyKCS11.CKA.keys())

# remove the CKR_ATTRIBUTE_SENSITIVE attributes since we can't get
all_attributes.remove(PyKCS11.LowLevel.CKA_PRIVATE_EXPONENT)
all_attributes.remove(PyKCS11.LowLevel.CKA_PRIME_1)
all_attributes.remove(PyKCS11.LowLevel.CKA_PRIME_2)
all_attributes.remove(PyKCS11.LowLevel.CKA_EXPONENT_1)
all_attributes.remove(PyKCS11.LowLevel.CKA_EXPONENT_2)
all_attributes.remove(PyKCS11.LowLevel.CKA_COEFFICIENT)
all_attributes = [e for e in all_attributes if isinstance(e, int)]


def parse_uri(pk11_uri):
    o = urlparse(pk11_uri)