Exemple #1
0
def _construct_extra_parameters(extra_data):
    """
    Given a dictionary of extra key-value pairs (all str),
    return a string that may be appended to a google authenticator / oathtoken URL.
    Values that are non-strings will be converted to str.
    Keys and values are converted to UTF-8 and urlquoted.
    :return: a string (may be empty if ``extra_data`` is empty)
    """
    extra_data_list = []
    for key, value in extra_data.items():
        encoded_key = quote(to_byte_string(key))
        encoded_value = quote(to_byte_string(value))
        extra_data_list.append('{key}={value}'.format(key=encoded_key, value=encoded_value))
    return ('&' if extra_data_list else '') + '&'.join(extra_data_list)
Exemple #2
0
def _construct_extra_parameters(extra_data):
    """
    Given a dictionary of extra key-value pairs (all str),
    return a string that may be appended to a google authenticator / oathtoken URL.
    Values that are non-strings will be converted to str.
    Keys and values are converted to UTF-8 and urlquoted.
    :return: a string (may be empty if ``extra_data`` is empty)
    """
    extra_data_list = []
    for key, value in extra_data.items():
        encoded_key = quote(to_byte_string(key))
        encoded_value = quote(to_byte_string(value))
        extra_data_list.append('{key}={value}'.format(key=encoded_key,
                                                      value=encoded_value))
    return ('&' if extra_data_list else '') + '&'.join(extra_data_list)
def verify_certificate_path(certificate, trusted_ca_paths):
    """
    Verify a certificate against the list of directories each containing files with
    a certificate chain.

    :param certificate: The PEM certificate to verify
    :param trusted_ca_paths: A list of directories
    :return: True or False
    """
    from os import listdir
    from os.path import isfile, join, isdir

    for capath in trusted_ca_paths:
        if isdir(capath):
            chainfiles = [
                join(capath, f) for f in listdir(capath)
                if isfile(join(capath, f))
            ]
            for chainfile in chainfiles:
                chain = parse_chainfile(chainfile)
                try:
                    verify_certificate(to_byte_string(certificate), chain)
                    return True
                except Exception as exx:
                    log.debug(
                        u"Can not verify attestation certificate against chain {0!s}."
                        .format(chain))
        else:
            log.warning(
                "The configured attestation CA directory does not exist.")
    return False
    def test_25_encodings(self):
        u = u'Hello Wörld'
        b = b'Hello World'
        self.assertEquals(to_utf8(None), None)
        self.assertEquals(to_utf8(u), u.encode('utf8'))
        self.assertEquals(to_utf8(b), b)

        self.assertEquals(to_unicode(u), u)
        self.assertEquals(to_unicode(b), b.decode('utf8'))
        self.assertEquals(to_unicode(None), None)
        self.assertEquals(to_unicode(10), 10)

        self.assertEquals(to_bytes(u), u.encode('utf8'))
        self.assertEquals(to_bytes(b), b)
        self.assertEquals(to_bytes(10), 10)

        self.assertEquals(to_byte_string(u), u.encode('utf8'))
        self.assertEquals(to_byte_string(b), b)
        self.assertEquals(to_byte_string(10), b'10')
    def test_25_encodings(self):
        u = u'Hello Wörld'
        b = b'Hello World'
        self.assertEquals(to_utf8(None), None)
        self.assertEquals(to_utf8(u), u.encode('utf8'))
        self.assertEquals(to_utf8(b), b)

        self.assertEquals(to_unicode(u), u)
        self.assertEquals(to_unicode(b), b.decode('utf8'))
        self.assertEquals(to_unicode(None), None)
        self.assertEquals(to_unicode(10), 10)

        self.assertEquals(to_bytes(u), u.encode('utf8'))
        self.assertEquals(to_bytes(b), b)
        self.assertEquals(to_bytes(10), 10)

        self.assertEquals(to_byte_string(u), u.encode('utf8'))
        self.assertEquals(to_byte_string(b), b)
        self.assertEquals(to_byte_string(10), b'10')
def verify_certificate(certificate, chain):
    """
    Verify a certificate against the certificate chain, which can be of any length

    The certificate chain starts with the root certificate and contains further
    intermediate certificates

    :param certificate: The certificate
    :type certificate: PEM encoded string
    :param chain: A list of PEM encoded certificates
    :type chain: list
    :return: raises an exception
    """
    # first reverse the list, since it can be popped better
    chain = list(reversed(chain))
    if not chain:
        raise privacyIDEAError(
            "Can not verify certificate against an empty chain.")
    certificate = load_pem_x509_certificate(to_byte_string(certificate),
                                            default_backend())
    chain = [
        load_pem_x509_certificate(to_byte_string(c), default_backend())
        for c in chain
    ]
    # verify chain
    while chain:
        signer = chain.pop()
        if chain:
            # There is another element in the list, so we check the intermediate:
            signee = chain.pop()
            signer.public_key().verify(signee.signature,
                                       signee.tbs_certificate_bytes,
                                       padding.PKCS1v15(),
                                       signee.signature_hash_algorithm)
            signer = signee

    # This was the last certificate in the chain, so we check the certificate
    signer.public_key().verify(certificate.signature,
                               certificate.tbs_certificate_bytes,
                               padding.PKCS1v15(),
                               certificate.signature_hash_algorithm)
    def update(self, param):
        """
        This method is called during the initialization process.
        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)

        request = getParam(param, "request", optional)
        spkac = getParam(param, "spkac", optional)
        certificate = getParam(param, "certificate", optional)
        generate = getParam(param, "genkey", optional)
        template_name = getParam(param, "template", optional)
        if request or generate:
            # If we do not upload a user certificate, then we need a CA do
            # sign the uploaded request or generated certificate.
            ca = getParam(param, "ca", required)
            self.add_tokeninfo("CA", ca)
            cacon = get_caconnector_object(ca)
        if request:
            if not spkac:
                # We only do the whole attestation checking in case we have no SPKAC
                request_csr = load_pem_x509_csr(to_byte_string(request),
                                                default_backend())
                if not request_csr.is_signature_valid:
                    raise privacyIDEAError("request has invalid signature.")
                # If a request is sent, we can have an attestation certificate
                attestation = getParam(param, "attestation", optional)
                verify_attestation = getParam(param, "verify_attestation",
                                              optional)
                if attestation:
                    request_numbers = request_csr.public_key().public_numbers()
                    attestation_cert = load_pem_x509_certificate(
                        to_byte_string(attestation), default_backend())
                    attestation_numbers = attestation_cert.public_key(
                    ).public_numbers()
                    if request_numbers != attestation_numbers:
                        log.warning(
                            "certificate request does not match attestation certificate."
                        )
                        raise privacyIDEAError(
                            "certificate request does not match attestation certificate."
                        )

                    try:
                        verified = verify_certificate_path(
                            attestation, param.get(ACTION.TRUSTED_CA_PATH))
                    except Exception as exx:
                        # We could have file system errors during verification.
                        log.debug("{0!s}".format(traceback.format_exc()))
                        verified = False

                    if not verified:
                        log.warning(
                            "Failed to verify certificate chain of attestation certificate."
                        )
                        if verify_attestation:
                            raise privacyIDEAError(
                                "Failed to verify certificate chain of attestation certificate."
                            )

            # During the initialization process, we need to create the
            # certificate
            x509object = cacon.sign_request(request,
                                            options={
                                                "spkac": spkac,
                                                "template": template_name
                                            })
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
        elif generate:
            # Create the certificate on behalf of another user.
            # Now we need to create the key pair,
            # the request
            # and the certificate
            # We need the user for whom the certificate should be created
            user = get_user_from_param(param, optionalOrRequired=required)

            keysize = getParam(param, "keysize", optional, 2048)
            key = crypto.PKey()
            key.generate_key(crypto.TYPE_RSA, keysize)
            req = crypto.X509Req()
            req.get_subject().CN = user.login
            # Add email to subject
            if user.info.get("email"):
                req.get_subject().emailAddress = user.info.get("email")
            req.get_subject().organizationalUnitName = user.realm
            # TODO: Add Country, Organization, Email
            # req.get_subject().countryName = 'xxx'
            # req.get_subject().stateOrProvinceName = 'xxx'
            # req.get_subject().localityName = 'xxx'
            # req.get_subject().organizationName = 'xxx'
            req.set_pubkey(key)
            req.sign(key, "sha256")
            csr = to_unicode(
                crypto.dump_certificate_request(crypto.FILETYPE_PEM, req))
            x509object = cacon.sign_request(
                csr, options={"template": template_name})
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
            # Save the private key to the encrypted key field of the token
            s = crypto.dump_privatekey(crypto.FILETYPE_PEM, key)
            self.add_tokeninfo("privatekey", s, value_type="password")

        if "pin" in param:
            self.set_pin(param.get("pin"), encrypt=True)

        if certificate:
            self.add_tokeninfo("certificate", certificate)