]> git.ipfire.org Git - thirdparty/python-fints.git/commitdiff
Implement automatic security_function choosing, implement H[IK]TAN[56] segments
authorHenryk Plötz <henryk@ploetzli.ch>
Thu, 23 Aug 2018 21:08:44 +0000 (23:08 +0200)
committerRaphael Michel <mail@raphaelmichel.de>
Mon, 3 Dec 2018 18:34:29 +0000 (19:34 +0100)
fints/client.py
fints/formals.py
fints/segments/auth.py

index 9644dd31f411f065e6004c8f58f3a58adfeb41c7..f0fb811b187ea15a4fffcdc8539d4b09d8700460 100644 (file)
@@ -4,6 +4,7 @@ import base64
 import zlib
 import json
 from decimal import Decimal
+from collections import OrderedDict
 
 from fints.segments.debit import HKDME, HKDSE
 from mt940.models import Balance
@@ -62,6 +63,7 @@ class FinTS3Client:
         self.upd = SegmentSequence()
         self.allowed_security_functions = []
         self.selected_security_function = None
+        self.selected_tan_medium = None
         self.product_name = 'pyfints'
         self.product_version = '0.2'
         self._standing_dialog = None
@@ -132,6 +134,7 @@ class FinTS3Client:
                 self.bpd_version = data['bpd_version']
 
         self.selected_security_function = data.get('selected_security_function', self.selected_security_function)
+        self.allowed_security_functions = data.get('allowed_security_functions', self.allowed_security_functions)
 
         if all(x in data for x in ('upd_bin', 'upa_bin', 'upd_version')):
             if data['upd_version'] >= self.upd_version:
@@ -147,6 +150,7 @@ class FinTS3Client:
             "bpa_bin": FinTS3Serializer().serialize_message(self.bpa) if self.bpa else None,
             "bpd_version": self.bpd_version,
             "selected_security_function": self.selected_security_function,
+            "selected_tan_medium": self.selected_tan_medium,
         }
 
         if including_private:
@@ -154,6 +158,7 @@ class FinTS3Client:
                 "upd_bin": self.upd.render_bytes(),
                 "upa_bin": FinTS3Serializer().serialize_message(self.upa) if self.upa else None,
                 "upd_version": self.upd_version,
+                "allowed_security_functions": self.allowed_security_functions,
             })
 
         return self._compress_data_v1(data)
@@ -199,7 +204,22 @@ class FinTS3Client:
                 if response.code == '3920':
                     self.allowed_security_functions = list(response.parameters)
                     if self.selected_security_function is None or not self.selected_security_function in self.allowed_security_functions:
-                        self.selected_security_function = self.allowed_security_functions[0]
+                        # Select the first available twostep security_function that we support
+                        for security_function, parameter in self.get_tan_mechanisms().items():
+                            if security_function == '999':
+                                # Skip onestep TAN
+                                continue
+                            if parameter.tan_process != '2':
+                                # Only support process variant 2 for now
+                                continue
+                            try:
+                                self.set_tan_mechanism(parameter.security_function)
+                                break
+                            except NotImplementedError:
+                                pass
+                        else:
+                            # Fall back to onestep
+                            self.set_tan_mechanism('999')
 
     def get_sepa_accounts(self):
         """
@@ -527,19 +547,33 @@ class FinTS3Client:
             )
         return model(dialog, *s[1:1 + len(model.args)])
 
-    def get_tan_methods(self):
+    def get_tan_mechanisms(self):
         """
-        Returns a list of TAN methods.
+        Get the available TAN mechanisms.
 
-        :return: List of TANMethod objects
+        :return: Dictionary of security_function: TwoStepParameters[1-5] objects.
         """
-        dialog = self._get_dialog()
-        dialog.sync()
-        dialog.init()
-        dialog.end()
-        return dialog.tan_mechs
 
-    def get_tan_descriptions(self, media_type = TANMediaType2.ALL, media_class = TANMediaClass4.ALL):
+        retval = OrderedDict()
+
+        for version in range(1, 6):
+            for seg in self.bpd.find_segments('HITANS', version):
+                for parameter in seg.parameter.twostep_parameters:
+                    if parameter.security_function in self.allowed_security_functions:
+                        retval[parameter.security_function] = parameter
+
+        return retval
+
+    def get_current_tan_mechanism(self):
+        return self.selected_security_function
+
+    def set_tan_mechanism(self, security_function):
+        self.selected_security_function = security_function
+
+    def set_tan_medium(self, tan_medium):
+        self.selected_tan_medium = tan_medium
+
+    def get_tan_media(self, media_type = TANMediaType2.ALL, media_class = TANMediaClass4.ALL):
         """Get information about TAN lists/generators.
 
         Returns tuple of fints.formals.TANUsageOption and a list of fints.formals.TANMedia4 or fints.formals.TANMedia5 objects."""
index 49e5f8f263e1d29ffff14cca1784552a69c0eb5a..8e3704fba959ab2c08d7a7338b1e5e731b79ab24 100644 (file)
@@ -138,6 +138,44 @@ class AllowedTransaction(DataElementGroup):
     limit_amount = DataElementField(type='btg', required=False)
     limit_days = DataElementField(type='num', max_length=3, required=False)
 
+class TANTimeDialogAssociation(RepresentableEnum):
+    NOT_ALLOWED = '1' #: TAN nicht zeitversetzt / dialogübergreifend erlaubt
+    ALLOWED = '2' #: TAN zeitversetzt / dialogübergreifend erlaubt
+    BOTH = '3' #: beide Verfahren unterstützt
+    NOT_APPLICABLE = '4' #: nicht zutreffend
+
+class AllowedFormat(RepresentableEnum):
+    NUMERIC = '1' #: numerisch
+    ALPHANUMERIC = '2' #: alfanumerisch
+
+class TANListNumberRequired(RepresentableEnum):
+    NO = '0' #: Nein
+    YES = '2' #: Ja
+
+class InitialisationMode(RepresentableEnum):
+    CLEARTEXT_PIN_NO_TAN = '00' #: Initialisierungsverfahren mit Klartext-PIN und ohne TAN
+    ENCRYPTED_PIN_NO_TAN = '01' #: Schablone 01: Verschlüsselte PIN und ohne TAN
+    MASK_02 = '02' #: Schablone 02: Reserviert, bei FinTS zur Zeit nicht verwendet
+
+class DescriptionRequired(RepresentableEnum):
+    MUST_NOT = '0' #: Bezeichnung des TAN-Mediums darf nicht angegeben werden
+    MAY = '1' #: Bezeichnung des TAN-Mediums kann angegeben werden
+    MUST = '2' #: Bezeichnung des TAN-Mediums muss angegeben werden
+
+class SMSChargeAccountRequired(RepresentableEnum):
+    MUST_NOT = '0' #: SMS-Abbuchungskonto darf nicht angegeben werden
+    MAY = '1' #: SMS-Abbuchungskonto kann angegeben werden
+    MUST = '2' #: SMS-Abbuchungskonto muss angegeben werden
+
+class PrincipalAccountRequired(RepresentableEnum):
+    MUST_NOT = '0' #: Auftraggeberkonto darf nicht angegeben werden
+    MUST = '2' #: Auftraggeberkonto muss angegeben werden, wenn im Geschäftsvorfall enthalten
+
+class TaskHashAlgorithm(RepresentableEnum):
+    NONE = '0' #: Auftrags-Hashwert nicht unterstützt
+    RIPEMD_160 = '1' #: RIPEMD-160
+    SHA_1 = '2' #: SHA-1
+
 class TwoStepParametersCommon(DataElementGroup):
     @property
     def VERSION(self):
@@ -150,7 +188,7 @@ class TwoStepParametersCommon(DataElementGroup):
 class TwoStepParameters1(TwoStepParametersCommon):
     name = DataElementField(type='an', max_length=30, _d="Name des Zwei-Schritt-Verfahrens")
     max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren")
-    allowed_format = DataElementField(type='code', length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
+    allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
     text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren")
     max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren")
     number_of_supported_lists = DataElementField(type='num', length=1, _d="Anzahl unterstützter aktiver TAN-Listen")
@@ -160,13 +198,13 @@ class TwoStepParameters1(TwoStepParametersCommon):
 class TwoStepParameters2(TwoStepParametersCommon):
     name = DataElementField(type='an', max_length=30, _d="Name des Zwei-Schritt-Verfahrens")
     max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren")
-    allowed_format = DataElementField(type='code', length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
+    allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
     text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren")
     max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren")
     number_of_supported_lists = DataElementField(type='num', length=1, _d="Anzahl unterstützter aktiver TAN-Listen")
     multiple_tans_allowed = DataElementField(type='jn', _d="Mehrfach-TAN erlaubt")
-    tan_time_dialog_association = DataElementField(type='code', length=1, _d="TAN Zeit- und Dialogbezug")
-    tan_list_number_required = DataElementField(type='code', length=1, _d="TAN-Listennummer erforderlich")
+    tan_time_dialog_association = CodeField(enum=TANTimeDialogAssociation, length=1, _d="TAN Zeit- und Dialogbezug")
+    tan_list_number_required = CodeField(enum=TANListNumberRequired, length=1, _d="TAN-Listennummer erforderlich")
     cancel_allowed = DataElementField(type='jn', _d="Auftragsstorno erlaubt")
     challenge_class_required = DataElementField(type='jn', _d="Challenge-Klasse erforderlich")
     challenge_value_required = DataElementField(type='jn', _d="Challenge-Betrag erforderlich")
@@ -174,18 +212,18 @@ class TwoStepParameters2(TwoStepParametersCommon):
 class TwoStepParameters3(TwoStepParametersCommon):
     name = DataElementField(type='an', max_length=30, _d="Name des Zwei-Schritt-Verfahrens")
     max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren")
-    allowed_format = DataElementField(type='code', length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
+    allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
     text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren")
     max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren")
     number_of_supported_lists = DataElementField(type='num', length=1, _d="Anzahl unterstützter aktiver TAN-Listen")
     multiple_tans_allowed = DataElementField(type='jn', _d="Mehrfach-TAN erlaubt")
-    tan_time_dialog_association = DataElementField(type='code', length=1, _d="TAN Zeit- und Dialogbezug")
-    tan_list_number_required = DataElementField(type='code', length=1, _d="TAN-Listennummer erforderlich")
+    tan_time_dialog_association = CodeField(enum=TANTimeDialogAssociation, length=1, _d="TAN Zeit- und Dialogbezug")
+    tan_list_number_required = CodeField(enum=TANListNumberRequired, length=1, _d="TAN-Listennummer erforderlich")
     cancel_allowed = DataElementField(type='jn', _d="Auftragsstorno erlaubt")
     challenge_class_required = DataElementField(type='jn', _d="Challenge-Klasse erforderlich")
     challenge_value_required = DataElementField(type='jn', _d="Challenge-Betrag erforderlich")
-    initialisation_mode = DataElementField(type='code', _d="Initialisierungsmodus")
-    description_required = DataElementField(type='code', length=1, _d="Bezeichnung des TAN-Medium erforderlich")
+    initialisation_mode = CodeField(enum=InitialisationMode, _d="Initialisierungsmodus")
+    description_required = CodeField(enum=DescriptionRequired, length=1, _d="Bezeichnung des TAN-Medium erforderlich")
     supported_media_number = DataElementField(type='num', length=1, required=False, _d="Anzahl unterstützter aktiver TAN-Medien")
 
 class TwoStepParameters4(TwoStepParametersCommon):
@@ -193,20 +231,20 @@ class TwoStepParameters4(TwoStepParametersCommon):
     zka_version = DataElementField(type='an', max_length=10, _d="Version ZKA TAN-Verfahren")
     name = DataElementField(type='an', max_length=30, _d="Name des Zwei-Schritt-Verfahrens")
     max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren")
-    allowed_format = DataElementField(type='code', length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
+    allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
     text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren")
     max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren")
     number_of_supported_lists = DataElementField(type='num', length=1, _d="Anzahl unterstützter aktiver TAN-Listen")
     multiple_tans_allowed = DataElementField(type='jn', _d="Mehrfach-TAN erlaubt")
-    tan_time_dialog_association = DataElementField(type='code', length=1, _d="TAN Zeit- und Dialogbezug")
-    tan_list_number_required = DataElementField(type='code', length=1, _d="TAN-Listennummer erforderlich")
+    tan_time_dialog_association = CodeField(enum=TANTimeDialogAssociation, length=1, _d="TAN Zeit- und Dialogbezug")
+    tan_list_number_required = CodeField(enum=TANListNumberRequired, length=1, _d="TAN-Listennummer erforderlich")
     cancel_allowed = DataElementField(type='jn', _d="Auftragsstorno erlaubt")
     sms_charge_account_required = DataElementField(type='jn', _d="SMS-Abbuchungskonto erforderlich")
     challenge_class_required = DataElementField(type='jn', _d="Challenge-Klasse erforderlich")
     challenge_value_required = DataElementField(type='jn', _d="Challenge-Betrag erforderlich")
     challenge_structured = DataElementField(type='jn', _d="Challenge strukturiert")
-    initialisation_mode = DataElementField(type='code', _d="Initialisierungsmodus")
-    description_required = DataElementField(type='code', length=1, _d="Bezeichnung des TAN-Medium erforderlich")
+    initialisation_mode = CodeField(enum=InitialisationMode, _d="Initialisierungsmodus")
+    description_required = CodeField(enum=DescriptionRequired, length=1, _d="Bezeichnung des TAN-Medium erforderlich")
     supported_media_number = DataElementField(type='num', length=1, required=False, _d="Anzahl unterstützter aktiver TAN-Medien")
 
 class TwoStepParameters5(TwoStepParametersCommon):
@@ -214,20 +252,20 @@ class TwoStepParameters5(TwoStepParametersCommon):
     zka_version = DataElementField(type='an', max_length=10, _d="Version ZKA TAN-Verfahren")
     name = DataElementField(type='an', max_length=30, _d="Name des Zwei-Schritt-Verfahrens")
     max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren")
-    allowed_format = DataElementField(type='code', length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
+    allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
     text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren")
     max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren")
     number_of_supported_lists = DataElementField(type='num', length=1, _d="Anzahl unterstützter aktiver TAN-Listen")
     multiple_tans_allowed = DataElementField(type='jn', _d="Mehrfach-TAN erlaubt")
-    tan_time_dialog_association = DataElementField(type='code', length=1, _d="TAN Zeit- und Dialogbezug")
-    tan_list_number_required = DataElementField(type='code', length=1, _d="TAN-Listennummer erforderlich")
+    tan_time_dialog_association = CodeField(enum=TANTimeDialogAssociation, length=1, _d="TAN Zeit- und Dialogbezug")
+    tan_list_number_required = CodeField(enum=TANListNumberRequired, length=1, _d="TAN-Listennummer erforderlich")
     cancel_allowed = DataElementField(type='jn', _d="Auftragsstorno erlaubt")
-    sms_charge_account_required = DataElementField(type='code', length=1, _d="SMS-Abbuchungskonto erforderlich")
-    principal_account_required = DataElementField(type='code', length=1, _d="Auftraggeberkonto erforderlich")
+    sms_charge_account_required = CodeField(enum=SMSChargeAccountRequired, length=1, _d="SMS-Abbuchungskonto erforderlich")
+    principal_account_required = CodeField(enum=PrincipalAccountRequired, length=1, _d="Auftraggeberkonto erforderlich")
     challenge_class_required = DataElementField(type='jn', _d="Challenge-Klasse erforderlich")
     challenge_structured = DataElementField(type='jn', _d="Challenge strukturiert")
-    initialisation_mode = DataElementField(type='code', _d="Initialisierungsmodus")
-    description_required = DataElementField(type='code', length=1, _d="Bezeichnung des TAN-Medium erforderlich")
+    initialisation_mode = CodeField(enum=InitialisationMode, _d="Initialisierungsmodus")
+    description_required = CodeField(enum=DescriptionRequired, length=1, _d="Bezeichnung des TAN-Medium erforderlich")
     supported_media_number = DataElementField(type='num', length=1, required=False, _d="Anzahl unterstützter aktiver TAN-Medien")
 
 class TwoStepParameters6(TwoStepParametersCommon):
@@ -235,25 +273,25 @@ class TwoStepParameters6(TwoStepParametersCommon):
     zka_version = DataElementField(type='an', max_length=10, _d="Version ZKA TAN-Verfahren")
     name = DataElementField(type='an', max_length=30, _d="Name des Zwei-Schritt-Verfahrens")
     max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren")
-    allowed_format = DataElementField(type='code', length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
+    allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren")
     text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren")
     max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren")
     multiple_tans_allowed = DataElementField(type='jn', _d="Mehrfach-TAN erlaubt")
-    tan_time_dialog_association = DataElementField(type='code', length=1, _d="TAN Zeit- und Dialogbezug")
+    tan_time_dialog_association = CodeField(enum=TANTimeDialogAssociation, length=1, _d="TAN Zeit- und Dialogbezug")
     cancel_allowed = DataElementField(type='jn', _d="Auftragsstorno erlaubt")
-    sms_charge_account_required = DataElementField(type='code', length=1, _d="SMS-Abbuchungskonto erforderlich")
-    principal_account_required = DataElementField(type='code', length=1, _d="Auftraggeberkonto erforderlich")
+    sms_charge_account_required = CodeField(enum=SMSChargeAccountRequired, length=1, _d="SMS-Abbuchungskonto erforderlich")
+    principal_account_required = CodeField(enum=PrincipalAccountRequired, length=1, _d="Auftraggeberkonto erforderlich")
     challenge_class_required = DataElementField(type='jn', _d="Challenge-Klasse erforderlich")
     challenge_structured = DataElementField(type='jn', _d="Challenge strukturiert")
-    initialisation_mode = DataElementField(type='code', _d="Initialisierungsmodus")
-    description_required = DataElementField(type='code', length=1, _d="Bezeichnung des TAN-Medium erforderlich")
+    initialisation_mode = CodeField(enum=InitialisationMode, _d="Initialisierungsmodus")
+    description_required = CodeField(enum=DescriptionRequired, length=1, _d="Bezeichnung des TAN-Medium erforderlich")
     response_hhd_uc_required = DataElementField(type='jn', _d="Antwort HHD_UC erforderlich")
     supported_media_number = DataElementField(type='num', length=1, required=False, _d="Anzahl unterstützter aktiver TAN-Medien")
 
 class ParameterTwostepCommon(DataElementGroup):
     onestep_method_allowed = DataElementField(type='jn')
     multiple_tasks_allowed = DataElementField(type='jn')
-    hash_algorithm = DataElementField(type='code', length=1)
+    task_hash_algorithm = CodeField(enum=TaskHashAlgorithm, length=1, _d="Auftrags-Hashwertverfahren")
 
 class ParameterTwostepTAN1(ParameterTwostepCommon):
     security_profile_bank_signature = DataElementField(type='code', length=1)
@@ -620,3 +658,25 @@ class TANUsageOption(RepresentableEnum):
     EXACTLY_ONE = '1'#: Kunde kann genau ein Medium zu einer Zeit nutzen
     MOBILE_PLUS_GENERATOR = '2' #: Kunde kann ein Mobiltelefon und einen TAN-Generator parallel nutzen
 
+class ParameterChallengeClass(DataElementGroup):
+    """Parameter Challenge-Klasse
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Sicherheitsverfahren PIN/TAN"""
+    parameters = DataElementField(type='an', max_length=999, count=9, required=False)
+
+class ResponseHHDUC(DataElementGroup):
+    """Antwort HHD_UC
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Sicherheitsverfahren PIN/TAN"""
+    atc = DataElementField(type='an', max_length=5, _d="ATC")
+    ac = DataElementField(type='bin', max_length=256, _d="Application Cryptogram AC")
+    ef_id_data = DataElementField(type='bin', max_length=256, _d="EF_ID Data")
+    cvr = DataElementField(type='bin', max_length=256, _d="CVR")
+    version_info_chiptan = DataElementField(type='bin', max_length=256, _d="Versionsinfo der chipTAN-Applikation")
+
+class ChallengeValidUntil(DataElementGroup):
+    """Gültigkeitsdatum und -uhrzeit für Challenge
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Sicherheitsverfahren PIN/TAN"""
+    date = DataElementField(type='dat', _d="Datum")
+    time = DataElementField(type='tim', _d="Uhrzeit")
index ad283bcac1ead0da056eb3add11b9702d1500da9..ac1c0bea427af93a84314d06db7e136fb232c07b 100644 (file)
@@ -2,6 +2,7 @@ from fints.fields import CodeField, DataElementField, DataElementGroupField
 from fints.formals import (
     BankIdentifier, Language2, SynchronisationMode, SystemIDStatus,
     TANMediaType2, TANMediaClass4, TANMedia5, TANMediaClass3, TANMedia4, TANUsageOption,
+    KTI1, ParameterChallengeClass, ResponseHHDUC, ChallengeValidUntil
 )
 from fints.utils import fints_escape
 
@@ -122,6 +123,69 @@ class HKTAN(FinTS3SegmentOLD):
         super().__init__(segno, data)
 
 
+class HKTAN5(FinTS3Segment):
+    """Zwei-Schritt-TAN-Einreichung, version 5
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Sicherheitsverfahren PIN/TAN"""
+    tan_process = DataElementField(type='code', length=1, _d="TAN-Prozess")
+    segment_type = DataElementField(type='an', max_length=6, required=False, _d="Segmentkennung")
+    account = DataElementGroupField(type=KTI1, required=False, _d="Kontoverbindung international Auftraggeber")
+    task_hash_value = DataElementField(type='bin', max_length=256, required=False, _d="Auftrags-Hashwert")
+    task_reference = DataElementField(type='an', max_length=35, required=False, _d="Auftragsreferenz")
+    tan_list_number = DataElementField(type='an', max_length=20, required=False, _d="TAN-Listennummer")
+    further_tan_follows = DataElementField(type='jn', length=1, required=False, _d="Weitere TAN folgt")
+    cancel_task = DataElementField(type='jn', length=1, required=False, _d="Auftrag stornieren")
+    sms_charge_account = DataElementGroupField(type=KTI1, required=False, _d="SMS-Abbuchungskonto")
+    challenge_class = DataElementField(type='num', max_length=2, required=False, _d="Challenge-Klasse")
+    parameter_challenge_class = DataElementGroupField(type=ParameterChallengeClass, required=False, _d="Parameter Challenge-Klasse")
+    tan_medium_name = DataElementField(type='an', max_length=32, required=False, _d="Bezeichnung des TAN-Mediums")
+
+
+class HKTAN6(FinTS3Segment):
+    """Zwei-Schritt-TAN-Einreichung, version 6
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Sicherheitsverfahren PIN/TAN"""
+    tan_process = DataElementField(type='code', length=1, _d="TAN-Prozess")
+    segment_type = DataElementField(type='an', max_length=6, required=False, _d="Segmentkennung")
+    account = DataElementGroupField(type=KTI1, required=False, _d="Kontoverbindung international Auftraggeber")
+    task_hash_value = DataElementField(type='bin', max_length=256, required=False, _d="Auftrags-Hashwert")
+    task_reference = DataElementField(type='an', max_length=35, required=False, _d="Auftragsreferenz")
+    further_tan_follows = DataElementField(type='jn', length=1, required=False, _d="Weitere TAN folgt")
+    cancel_task = DataElementField(type='jn', length=1, required=False, _d="Auftrag stornieren")
+    sms_charge_account = DataElementGroupField(type=KTI1, required=False, _d="SMS-Abbuchungskonto")
+    challenge_class = DataElementField(type='num', max_length=2, required=False, _d="Challenge-Klasse")
+    parameter_challenge_class = DataElementGroupField(type=ParameterChallengeClass, required=False, _d="Parameter Challenge-Klasse")
+    tan_medium_name = DataElementField(type='an', max_length=32, required=False, _d="Bezeichnung des TAN-Mediums")
+    response_hhd_uc = DataElementGroupField(type=ResponseHHDUC, required=False, _d="Antwort HHD_UC")
+
+
+class HITAN5(FinTS3Segment):
+    """Zwei-Schritt-TAN-Einreichung Rückmeldung, version 5
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Sicherheitsverfahren PIN/TAN"""
+    tan_process = DataElementField(type='code', length=1, _d="TAN-Prozess")
+    task_hash_value = DataElementField(type='bin', max_length=256, required=False, _d="Auftrags-Hashwert")
+    task_reference = DataElementField(type='an', max_length=35, required=False, _d="Auftragsreferenz")
+    challenge = DataElementField(type='an', max_length=2048, required=False, _d="Challenge")
+    challenge_hhduc = DataElementField(type='bin', required=False, _d="Challenge HHD_UC")
+    challenge_valid_until = DataElementGroupField(type=ChallengeValidUntil, required=False, _d="Gültigkeitsdatum und -uhrzeit für Challenge")
+    tan_list_number = DataElementField(type='an', max_length=20, required=False, _d="TAN-Listennummer")
+    ben = DataElementField(type='an', max_length=99, required=False, _d="BEN")
+    tan_medium_name = DataElementField(type='an', max_length=32, required=False, _d="Bezeichnung des TAN-Mediums")
+
+class HITAN6(FinTS3Segment):
+    """Zwei-Schritt-TAN-Einreichung Rückmeldung, version 6
+
+    Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Sicherheitsverfahren PIN/TAN"""
+    tan_process = DataElementField(type='code', length=1, _d="TAN-Prozess")
+    task_hash_value = DataElementField(type='bin', max_length=256, required=False, _d="Auftrags-Hashwert")
+    task_reference = DataElementField(type='an', max_length=35, required=False, _d="Auftragsreferenz")
+    challenge = DataElementField(type='an', max_length=2048, required=False, _d="Challenge")
+    challenge_hhduc = DataElementField(type='bin', required=False, _d="Challenge HHD_UC")
+    challenge_valid_until = DataElementGroupField(type=ChallengeValidUntil, required=False, _d="Gültigkeitsdatum und -uhrzeit für Challenge")
+    tan_medium_name = DataElementField(type='an', max_length=32, required=False, _d="Bezeichnung des TAN-Mediums")
+
+
 class HKTAB(FinTS3SegmentOLD):
     """
     HKTAB (Verfügbarre TAN-Medien ermitteln)