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(clientdata) client_challenge = clientdata_dict.get("challenge") if challenge_url != client_challenge: raise ValidateError("Challenge mismatch. The U2F key did not " "send to original challenge.") 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 = binascii.hexlify(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, binascii.hexlify(signature), counter, user_presence): # Signature verified. # check, if the counter increased! if counter > self.get_otp_count(): self.set_otp_count(counter) ret = counter 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
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(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 g = options.get("g") user_object = self.user allowed_certs_pols = g.policy_object.get_action_values( U2FACTION.REQ, scope=SCOPE.AUTHZ, user_object=user_object if user_object else None, client=g.client_ip, audit_data=g.audit_object.audit_data) for allowed_cert in allowed_certs_pols: tag, matching, _rest = allowed_cert.split("/", 3) tag_value = self.get_tokeninfo( "attestation_{0!s}".format(tag)) # if we do not get a match, we bail out m = re.search(matching, tag_value) if not m: 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
def test_05_parse_response(self): response = "0100000001304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f" up, count, sig = parse_response_data(response) self.assertTrue(up, "\x01") self.assertTrue(count, 1) self.assertTrue(sig, response[5:])
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(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 g = options.get("g") if self.user: token_user = self.user.login token_realm = self.user.realm token_resolver = self.user.resolver else: token_realm = token_resolver = token_user = None allowed_certs_pols = g.policy_object.get_action_values( U2FACTION.REQ, scope=SCOPE.AUTHZ, realm=token_realm, user=token_user, resolver=token_resolver, client=g.client_ip, audit_data=g.audit_object.audit_data) for allowed_cert in allowed_certs_pols: tag, matching, _rest = allowed_cert.split("/", 3) tag_value = self.get_tokeninfo( "attestation_{0!s}".format(tag)) # if we do not get a match, we bail out m = re.search(matching, tag_value) if not m: 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