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'] }))
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