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 update(self, param, reset_failcount=True): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) description = "U2F initialization" reg_data = getParam(param, "regdata") if reg_data: self.init_step = 2 attestation_cert, user_pub_key, key_handle, \ signature, description = parse_registration_data(reg_data) client_data = getParam(param, "clientdata", required) client_data_str = url_decode(client_data) app_id = self.get_tokeninfo("appId", "") # Verify the registration data # In case of any crypto error, check_data raises an exception check_registration_data(attestation_cert, app_id, client_data_str, user_pub_key, key_handle, signature) self.set_otpkey(key_handle) self.add_tokeninfo("pubKey", user_pub_key) self.set_description(description)
def update(self, param, reset_failcount=True): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) reg_data = getParam(param, "regdata") verify_cert = is_true(getParam(param, "u2f.verify_cert", default=True)) if not reg_data: self.token.rollout_state = ROLLOUTSTATE.CLIENTWAIT # Set the description in the first enrollment step if "description" in param: self.set_description(getParam(param, "description", default="")) elif reg_data and self.token.rollout_state == ROLLOUTSTATE.CLIENTWAIT: attestation_cert, user_pub_key, key_handle, \ signature, automatic_description = parse_registration_data(reg_data, verify_cert=verify_cert) client_data = getParam(param, "clientdata", required) client_data_str = url_decode(client_data) app_id = self.get_tokeninfo("appId", "") # Verify the registration data # In case of any crypto error, check_data raises an exception check_registration_data(attestation_cert, app_id, client_data_str, user_pub_key, key_handle, signature) self.set_otpkey(key_handle) self.add_tokeninfo("pubKey", user_pub_key) # add attestation certificate info issuer = x509name_to_string(attestation_cert.get_issuer()) serial = "{!s}".format(attestation_cert.get_serial_number()) subject = x509name_to_string(attestation_cert.get_subject()) self.add_tokeninfo("attestation_issuer", issuer) self.add_tokeninfo("attestation_serial", serial) self.add_tokeninfo("attestation_subject", subject) # Reset rollout state self.token.rollout_state = "" # If no description has already been set, set the automatic description or the # description given in the 2nd request if not self.token.description: self.set_description( getParam(param, "description", default=automatic_description)) else: raise ParameterError( "regdata provided but token not in clientwait rollout_state.")
def update(self, param, reset_failcount=True): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) description = "U2F initialization" reg_data = getParam(param, "regdata") verify_cert = is_true(getParam(param, "u2f.verify_cert", default=True)) if reg_data: self.init_step = 2 attestation_cert, user_pub_key, key_handle, \ signature, description = parse_registration_data(reg_data, verify_cert=verify_cert) client_data = getParam(param, "clientdata", required) client_data_str = url_decode(client_data) app_id = self.get_tokeninfo("appId", "") # Verify the registration data # In case of any crypto error, check_data raises an exception check_registration_data(attestation_cert, app_id, client_data_str, user_pub_key, key_handle, signature) self.set_otpkey(key_handle) self.add_tokeninfo("pubKey", user_pub_key) # add attestation certificat info issuer = x509name_to_string(attestation_cert.get_issuer()) serial = "{!s}".format(attestation_cert.get_serial_number()) subject = x509name_to_string(attestation_cert.get_subject()) self.add_tokeninfo("attestation_issuer", issuer) self.add_tokeninfo("attestation_serial", serial) self.add_tokeninfo("attestation_subject", subject) # If a description is given we use the given description description = getParam(param, "description", default=description) self.set_description(description)
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_03_url_decode(self): dec = url_decode("SGFsbG8sIGRhcyBpc3QgZWluIFRlc3QuLi4") self.assertEqual(dec, "Hallo, das ist ein Test...")
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