예제 #1
0
    def test_06_attestation_certificate_allowed(self):
        # No policies, return True.
        self.assertTrue(attestation_certificate_allowed(None, None))
        self.assertTrue(attestation_certificate_allowed({}, {}))

        # Policy but no info, return False.
        self.assertFalse(
            attestation_certificate_allowed(
                None, {"subject/.*Yubico.*/": ['WebAuthn']}))
        self.assertFalse(
            attestation_certificate_allowed(
                {}, {"subject/.*Yubico.*/": ['WebAuthn']}))

        # Certificate allowed, return True.
        self.assertTrue(
            attestation_certificate_allowed(
                {"attestation_subject": "C=SE,O=Yubico AB"},
                {"subject/.*Yubico.*/": ['WebAuthn']}))

        # Certificate not allowed, return False.
        self.assertFalse(
            attestation_certificate_allowed(
                {"attestation_subject": "C=SE,O=Frobnicate"},
                {"subject/.*Yubico.*/": ['WebAuthn']}))

        # Multiple Policies, match iff all match.
        self.assertTrue(
            attestation_certificate_allowed(
                {
                    "attestation_subject": "C=SE,O=Yubico AB",
                    "attestation_serial": "61730834"
                }, {
                    "subject/.*Yubico.*/": ['WebAuthn1'],
                    "serial/61730834/": ['WebAuthn2']
                }))
        self.assertFalse(
            attestation_certificate_allowed(
                {
                    "attestation_subject": "C=SE,O=Yubico AB",
                    "attestation_serial": "61730834"
                }, {
                    "subject/.*Yubico.*/": ['WebAuthn1'],
                    "serial/12345678/": ['WebAuthn2']
                }))
예제 #2
0
    def check_otp(self, otpval, counter=None, window=None, options=None):
        """
        This checks the response of a previous challenge.

        :param otpval: N/A
        :param counter: The authentication counter
        :param window: N/A
        :param options: contains "clientdata", "signaturedata" and
            "transaction_id"
        :return: A value > 0 in case of success
        """
        ret = -1
        clientdata = options.get("clientdata")
        signaturedata = options.get("signaturedata")
        transaction_id = options.get("transaction_id")
        # The challenge in the challenge DB object is saved in hex
        challenge = binascii.unhexlify(options.get("challenge", ""))
        if clientdata and signaturedata and transaction_id and challenge:
            # This is a valid response for a U2F token
            challenge_url = url_encode(challenge)
            clientdata = url_decode(clientdata)
            clientdata_dict = json.loads(to_unicode(clientdata))
            client_challenge = clientdata_dict.get("challenge")
            if challenge_url != client_challenge:
                return ret
            if clientdata_dict.get("typ") != "navigator.id.getAssertion":
                raise ValidateError("Incorrect navigator.id")
            #client_origin = clientdata_dict.get("origin")
            signaturedata = url_decode(signaturedata)
            signaturedata_hex = hexlify_and_unicode(signaturedata)
            user_presence, counter, signature = parse_response_data(
                signaturedata_hex)

            user_pub_key = self.get_tokeninfo("pubKey")
            app_id = self.get_tokeninfo("appId")
            if check_response(user_pub_key, app_id, clientdata,
                              hexlify_and_unicode(signature), counter,
                              user_presence):
                # Signature verified.
                # check, if the counter increased!
                if counter > self.get_otp_count():
                    self.set_otp_count(counter)
                    ret = counter
                    # At this point we can check, if the attestation
                    # certificate is authorized.
                    # If not, we can raise a policy exception
                    if not attestation_certificate_allowed(
                        {
                            "attestation_issuer":
                            self.get_tokeninfo("attestation_issuer"),
                            "attestation_serial":
                            self.get_tokeninfo("attestation_serial"),
                            "attestation_subject":
                            self.get_tokeninfo("attestation_subject")
                        },
                            Match.user(options.get("g"),
                                       scope=SCOPE.AUTHZ,
                                       action=U2FACTION.REQ,
                                       user_object=self.user if self.user else
                                       None).action_values(unique=False)):
                        log.warning(
                            "The U2F device {0!s} is not allowed to authenticate due to policy restriction"
                            .format(self.token.serial))
                        raise PolicyError("The U2F device is not allowed "
                                          "to authenticate due to policy "
                                          "restriction.")

                else:
                    log.warning("The signature of %s was valid, but contained "
                                "an old counter." % self.token.serial)
            else:
                log.warning("Checking response for token {0!s} failed.".format(
                    self.token.serial))

        return ret