Пример #1
0
    def _getChallenge(self, ocrasuite, bkey, serial, ocrapin="", data=None, count=0, ttime=None):

        otp1 = None

        p = {"serial": serial, "data": "0105037311 Konto 50150850 BLZ 1752,03 Eur"}
        if data != None:
            p[data] = data

        response = self.app.get(genUrl(controller="ocra", action="request"), params=p)
        log.info("response %s\n", response)
        assert '"value": true' in response

        """ -2b- from the response get the challenge """
        jresp = json.loads(response.body)
        challenge1 = str(jresp.get("detail").get("challenge"))
        transid1 = str(jresp.get("detail").get("transactionid"))

        now = datetime.now()
        if ttime != None:
            now = ttime
        stime = now.strftime("%s")
        itime = int(stime)

        param = {}
        param["C"] = count
        param["Q"] = challenge1
        param["P"] = ocrapin
        param["S"] = ""
        param["T"] = itime

        ocra = OcraSuite(ocrasuite)
        data = ocra.combineData(**param)
        otp1 = ocra.compute(data, bkey)

        return (otp1, transid1)
Пример #2
0
    def _setup_(self):

        if self.ocra != None and self.bkey != None:
            return

        key_len = 20
        if self.ocrasuite.find('-SHA256'):
            key_len = 32
        elif self.ocrasuite.find('-SHA512'):
            key_len = 64

        self.bkey = kdf2(self.sharedsecret, self.nonce, self.activationkey, len=key_len)
        self.ocra = OcraSuite(self.ocrasuite)

        self.counter = 0

        return
Пример #3
0
    def signData(self, data):
        '''
        sign the received data with the secret key

        :param data: arbitrary string object
        :type param: string

        :return: hexlified signature of the data
        '''
        log.debug('[signData] %r:' % (data))

        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)
        signature = ocraSuite.signData(data)

        log.debug('[signData]: %r:' % (signature))
        return signature
Пример #4
0
    def _getChallenge(self,
                      ocrasuite,
                      bkey,
                      serial,
                      ocrapin='',
                      data=None,
                      count=0,
                      ttime=None):

        otp1 = None

        p = {
            "serial": serial,
            "data": "0105037311 Konto 50150850 BLZ 1752,03 Eur"
        }
        if data != None:
            p[data] = data

        response = self.app.get(genUrl(controller='ocra', action='request'),
                                params=p)
        log.info("response %s\n", response)
        assert '"value": true' in response
        ''' -2b- from the response get the challenge '''
        jresp = json.loads(response.body)
        challenge1 = str(jresp.get('detail').get('challenge'))
        transid1 = str(jresp.get('detail').get('transactionid'))

        now = datetime.now()
        if ttime != None:
            now = ttime
        stime = now.strftime("%s")
        itime = int(stime)

        param = {}
        param['C'] = count
        param['Q'] = challenge1
        param['P'] = ocrapin
        param['S'] = ''
        param['T'] = itime

        ocra = OcraSuite(ocrasuite)
        data = ocra.combineData(**param)
        otp1 = ocra.compute(data, bkey)

        return (otp1, transid1)
Пример #5
0
    def verify_challenge_is_valid(self, challenge, session):
        '''
        verify, if a challenge is valid according to the ocrasuite definition
        of the token
        '''

        ret = True

        counter = self.getOtpCount()

        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)

        ## set the pin onyl in the compliant hashed mode
        pin = ''
        if ocraSuite.P is not None:
            pinObj = self.token.getUserPin()
            pin = pinObj.getKey()

        try:
            param = {}
            param['C'] = counter
            param['Q'] = challenge
            param['P'] = pin
            param['S'] = session
            if ocraSuite.T is not None:
                now = datetime.datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param['T'] = itime

            ''' verify that the data is compliant with the OcraSuitesuite
                and the client is able to calc the otp
            '''
            c_data = ocraSuite.combineData(**param)
            ocraSuite.compute(c_data)

        except Exception as ex:
            log.error("[Ocra2TokenClass] challenge verification failed: "
                                "%s,%r: " % (challenge, ex))
            log.error("[Ocra2TokenClass] %r" % (traceback.format_exc()))
            ret = False

        return ret
Пример #6
0
    def _getChallenge(self, ocrasuite, bkey, serial, ocrapin='', data=None, count=0, ttime=None):

        otp1 = None

        p = {"serial"      : serial,
             "data"        : "0105037311 Konto 50150850 BLZ 1752,03 Eur"
            }
        if data != None:
            p[data] = data

        response = self.app.get(genUrl(controller='ocra', action='request'), params=p)
        log.info("response %s\n", response)
        assert '"value": true' in response

        ''' -2b- from the response get the challenge '''
        jresp = json.loads(response.body)
        challenge1 = str(jresp.get('detail').get('challenge'))
        transid1 = str(jresp.get('detail').get('transactionid'))


        now = datetime.now()
        if ttime != None:
            now = ttime
        stime = now.strftime("%s")
        itime = int(stime)

        param = {}
        param['C'] = count
        param['Q'] = challenge1
        param['P'] = ocrapin
        param['S'] = ''
        param['T'] = itime

        ocra = OcraSuite(ocrasuite)
        data = ocra.combineData(**param)
        otp1 = ocra.compute(data, bkey)

        return (otp1, transid1)
Пример #7
0
    def update(self, params, reset_failcount=True):
        '''
        update: add further definition for token from param in case of init
        '''
        log.debug('[update] %r: %r: ' % (params, reset_failcount))


        if params.has_key('ocrasuite'):
            self.ocraSuite = params.get('ocrasuite')
        else:
            activationcode = params.get('activationcode', None)
            sharedSecret = params.get('sharedsecret', None)


            if activationcode is None and sharedSecret is None:
                self.ocraSuite = self.getOcraSuiteSuite()
            else:
                self.ocraSuite = self.getQROcraSuiteSuite()

        if params.get('activationcode', None):
            ## due to changes in the tokenclass parameter handling
            ## we have to add for compatibility a genkey parameter
            if params.has_key('otpkey') == False and params.has_key('genkey') == False:
                log.warning('[Ocra2TokenClass:update] missing parameter genkey\
                             to complete the rollout 2!')
                params['genkey'] = 1


        TokenClass.update(self, params, reset_failcount=reset_failcount)

        self.addToTokenInfo('ocrasuite', self.ocraSuite)

        ocraSuite = OcraSuite(self.ocraSuite)
        otplen = ocraSuite.truncation
        self.setOtpLen(otplen)

        ocraPin = params.get('ocrapin', None)
        if ocraPin is not None:
            self.token.setUserPin(ocraPin)

        if params.has_key('otpkey'):
            self.setOtpKey(params.get('otpkey'))

        self._rollout_1(params)
        self._rollout_2(params)

        log.debug('[update]:')
        return
Пример #8
0
    def _setup_(self):

        if self.ocra != None and self.bkey != None:
            return

        key_len = 20
        if self.ocrasuite.find('-SHA256'):
            key_len = 32
        elif self.ocrasuite.find('-SHA512'):
            key_len = 64

        self.bkey = kdf2(self.sharedsecret, self.nonce, self.activationkey, len=key_len)
        self.ocra = OcraSuite(self.ocrasuite)

        self.counter = 0

        return
Пример #9
0
    def challenge(self, data, session='', typ='raw', challenge=None):
        '''
        the challenge method is for creating an transaction / challenge object

        remark: the transaction has a maximum lifetime and a reference to
                the OcraSuite token (serial)

        :param data:     data, which is the base for the challenge or None
        :type data:     string or None
        :param session:  session support for ocratokens
        :type session:  string
        :type typ:      define, which kind of challenge base should be used
                         could be raw - take the data input as is
                               (extract chars accordind challenge definition Q)
                         or random    - will generate a random input
                         or hased     - will take the hash of the input data

        :return:    challenge response containing the transcation id and the
                    challenge for the ocrasuite
        :rtype :    tuple of (transId(string), challenge(string))


        '''
        log.debug('[challenge] %r: %r: %r' % (data, session, challenge))

        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)

        if data is None or len(data) == 0:
            typ = 'random'

        if challenge is None:
            if typ == 'raw':
                challenge = ocraSuite.data2rawChallenge(data)
            elif typ == 'random':
                challenge = ocraSuite.data2randomChallenge(data)
            elif typ == 'hash':
                challenge = ocraSuite.data2hashChallenge(data)

        log.debug('[Ocra2TokenClass] challenge: %r ' % (challenge))

        counter = self.getOtpCount()

        ## set the pin onyl in the compliant hashed mode
        pin = ''
        if ocraSuite.P is not None:
            pinObj = self.token.getUserPin()
            pin = pinObj.getKey()

        try:
            param = {}
            param['C'] = counter
            param['Q'] = challenge
            param['P'] = pin
            param['S'] = session
            if ocraSuite.T is not None:
                now = datetime.datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param['T'] = itime

            ''' verify that the data is compliant with the OcraSuitesuite
                and the client is able to calc the otp
            '''
            c_data = ocraSuite.combineData(**param)
            ocraSuite.compute(c_data)

        except Exception as ex:
            log.error("[Ocra2TokenClass] %r" % (traceback.format_exc()))
            raise Exception('[Ocra2TokenClass] Failed to create ocrasuite '
                                                        'challenge: %r' % (ex))

        ##  create a non exisiting challenge
        try:

            (res, opt) = create_challenge(self, options={'messgae': data})

            transid = opt.get('transactionid')
            challenge = opt.get('challenge')

        except Exception as ex:
            ##  this might happen if we have a db problem or
            ##   the uniqnes constrain does not fit
            log.error("[Ocra2TokenClass] %r" % (traceback.format_exc()))
            raise Exception('[Ocra2TokenClass] Failed to create '
                                                'challenge object: %s' % (ex))

        realm = None
        realms = self.token.getRealms()
        if len(realms) > 0:
            realm = realms[0]

        url = ''
        if realm is not None:
            url = get_qrtan_url(realm.name)

        log.debug('[challenge]: %r: %r: %r' % (transid, challenge, url))
        return (transid, challenge, True, url)
Пример #10
0
    def ptest_OCRA_token_failcounterInc(self, tid=1):
        '''
            test_OCRA_token_failcounterInc: failcounter increment

            description:
                for all ocrasuites:
                   create and enroll token
                   verify the first otp
                   get some challenges
                   4 times:
                      verify a wrong otp
                      verify a wrong transaction
                      check status and if fail counter has incremented
        '''
        tcount = 0
        for test in self.tests:
            ocrasuite = test['ocrasuite']
            key = test['keyh']
            bkey = test['key']
            ocrapin = 'myocrapin'
            tid = tid
            serial = "QR_One_%r_%r_%r_%r" % (tid, tcount, int(time.time()), random.randint(0, 100))
            log.info("## serial: %s" % serial)
            count = 0
            tcount = tcount + 1

            ocra = OcraSuite(ocrasuite)
            pinlen = ocra.truncation
            ''' -1- create an ocra token '''
            parameters = {
                          "serial"      : serial,
                          "user"        : "root",
                          "pin"         : "pin",
                          "description" : "first QRToken",
                          'type'        : 'ocra',
                          'ocrapin'     : ocrapin,
                          'otpkey'      : key,
                          'ocrasuite'   : ocrasuite
                          }

            response = self.app.get(genUrl(controller='admin', action='init'), params=parameters)
            assert '"value": true' in response

            ## verify that the token is usable
            ''' -2- fetch the challenge '''
            p = {"serial"      : serial,
                 "data"        : "0105037311 Konto 50150850 BLZ 1752,03 Eur"
                }
            response = self.app.get(genUrl(controller='ocra', action='request'), params=p)
            log.info("response %s\n", response)
            if '"value": true' not in response:
                assert '"value": true' in response

            ''' -3.a- from the response get the challenge '''
            jresp = json.loads(response.body)
            challenge = str(jresp.get('detail').get('challenge'))
            transid = str(jresp.get('detail').get('transactionid'))

            param = {}
            param['C'] = count
            param['Q'] = challenge
            param['P'] = ocrapin
            param['S'] = ''
            if ocra.T != None:
                '''    Default value for G is 1M, i.e., time-step size is one minute and the
                       T represents the number of minutes since epoch time [UT].
                '''
                now = datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param['T'] = itime

            ocra = OcraSuite(ocrasuite)
            data = ocra.combineData(**param)
            otp = ocra.compute(data, bkey)

            ppin = 'pin' + otp

            ''' -3.b- verify the correct otp value '''
            parameters = {"transactionid"   : transid,
                          "pass"            : ppin,
                          }
            response = self.app.get(genUrl(controller='ocra', action='check_t'), params=parameters)
            log.info("response %s\n", response)
            if '"result": true' not in response:
                assert '"result": true' in response

            # verify that the failcounter increments (max is 10)
            fcount = 0
            for count in range(1, 3):

                ## create more than one challenge
                chals = random.randint(2, 5)
                for cc in range(1, chals):
                    ''' -2- fetch the challenge '''
                    p = {"serial"      : serial,
                         "data"        : "0105037311 Konto 50150850 BLZ 1752,03 Eur"
                        }
                    response = self.app.get(genUrl(controller='ocra', action='request'), params=p)
                    log.info("response %s\n", response)
                    if '"value": true' not in response:
                        assert '"value": true' in response


                ''' -3.a- from the response get the challenge '''
                jresp = json.loads(response.body)
                challenge = str(jresp.get('detail').get('challenge'))
                transid = str(jresp.get('detail').get('transactionid'))

                ppin = 'pin' + 'a' * pinlen

                ''' -4- verify the wrong otp value '''
                parameters = {"transactionid"   : transid,
                              "pass"            : ppin,
                              }
                response = self.app.get(genUrl(controller='ocra', action='check_t'), params=parameters)
                log.info("response %s\n", response)
                if '"result": false' not in response:
                    assert '"result": false' in response
                fcount += 1

                ppin = 'pin' + '4' * pinlen

                ''' -5- verify the wrong otp value '''
                parameters = {"transactionid"   : transid,
                              "pass"            : ppin,
                              }
                response = self.app.get(genUrl(controller='ocra', action='check_t'), params=parameters)
                log.info("response %s\n", response)
                if not '"result": false' in response:
                    assert '"result": false' in response
                fcount += 1

                ''' -6- check if the failcounter has incremented  '''
                parameters = {"transactionid"   : transid,
                              }
                response = self.app.get(genUrl(controller='ocra', action='checkstatus'), params=parameters)
                log.info("response %s\n", response)
                assert '"status": true' in response
                assstring = '"failcount": %d,' % (fcount)
                log.info("assert %s\n", assstring)
                if assstring not in response:
                    log.error(response)
                    assert assstring in response

                sleep = random.uniform(0.0, 0.3)
                time.sleep(sleep)

            ''' -remove the ocra token '''
            parameters = {"serial"      : serial, }
            response = self.app.get(genUrl(controller='admin', action='remove'), params=parameters)
            log.info("response %s\n", response)
            assert '"value": 1' in response

            for _iii in range(0, 3):
                parameters = {"serial"      : serial, }
                response = self.app.get(genUrl(controller='admin', action='remove'), params=parameters)


        return response
Пример #11
0
class OcraOtp(object):

    def __init__(self, ocrapin=None):
        self.ocra = None
        self.bkey = None
        self.ocrapin = ocrapin
        self.activationkey = None
        self.sharedsecret = None
        self.ocrasuite = None
        self.serial = None
        self.counter = 0


    def init_1(self, response):
        ''' take the response of the first init to setup the OcraOtp'''

        jresp = json.loads(response.body)
        app_import = str(jresp.get('detail').get('app_import'))
        self.sharedsecret = str(jresp.get('detail').get('sharedsecret'))
        self.serial = str(jresp.get('detail').get('serial'))

        ''' now parse the appurl for the ocrasuite '''
        uri = urlparse(app_import.replace('lseqr://', 'http://'))
        qs = uri.query
        qdict = parse_qs(qs)

        ocrasuite = qdict.get('os', None)
        if ocrasuite != None and len(ocrasuite) > 0:
            ocrasuite = ocrasuite[0]

        self.ocrasuite = ocrasuite

        return (self.ocrasuite, self.sharedsecret, self.serial)


    def init_2(self, response, activationKey):
        self.activationkey = activationKey

        jresp = json.loads(response.body)
        self.nonce = str(jresp.get('detail').get('nonce'))
        self.transid = str(jresp.get('detail').get('transactionid'))
        app_import = str(jresp.get('detail').get('app_import'))


        ''' now parse the appurl for the ocrasuite '''
        uri = urlparse(app_import.replace('lseqr://', 'http://'))
        qs = uri.query
        qdict = parse_qs(qs)
        nonce = qdict.get('no', None)
        if nonce != None and len(nonce) > 0:
            nonce = nonce[0]

        challenge = qdict.get('ch', None)
        if challenge != None and len(challenge) > 0:
            challenge = challenge[0]

        self.challenge = challenge
        self.ocra = None
        self.bkey = None

        return (self.challenge, self.transid)


    def _setup_(self):

        if self.ocra != None and self.bkey != None:
            return

        key_len = 20
        if self.ocrasuite.find('-SHA256'):
            key_len = 32
        elif self.ocrasuite.find('-SHA512'):
            key_len = 64

        self.bkey = kdf2(self.sharedsecret, self.nonce, self.activationkey, len=key_len)
        self.ocra = OcraSuite(self.ocrasuite)

        self.counter = 0

        return

    def callcOtp(self, challenge=None, ocrapin=None, counter= -1):

        if self.ocra == None:
            self._setup_()

        if ocrapin == None:
            ocrapin = self.ocrapin

        if challenge == None:
            challenge = self.challenge
        if counter == -1:
            counter = self.counter

        param = {}
        param['C'] = counter
        param['Q'] = challenge
        param['P'] = ocrapin
        param['S'] = ''
        if self.ocra.T != None:
            '''    Default value for G is 1M, i.e., time-step size is one minute and the
                   T represents the number of minutes since epoch time [UT].
            '''
            now = datetime.now()
            stime = now.strftime("%s")
            itime = int(stime)
            param['T'] = itime

        data = self.ocra.combineData(**param)
        otp = self.ocra.compute(data, self.bkey)

        if counter == -1:
            self.counter += 1

        return otp
Пример #12
0
    def ptest_OCRA_token_failcounterInc(self, tid=1):
        """
            test_OCRA_token_failcounterInc: failcounter increment

            description:
                for all ocrasuites:
                   create and enroll token
                   verify the first otp
                   get some challenges
                   4 times:
                      verify a wrong otp
                      verify a wrong transaction
                      check status and if fail counter has incremented
        """
        tcount = 0
        for test in self.tests:
            ocrasuite = test["ocrasuite"]
            key = test["keyh"]
            bkey = test["key"]
            ocrapin = "myocrapin"
            tid = tid
            serial = "QR_One_%r_%r_%r_%r" % (tid, tcount, int(time.time()), random.randint(0, 100))
            log.info("## serial: %s" % serial)
            count = 0
            tcount = tcount + 1

            ocra = OcraSuite(ocrasuite)
            pinlen = ocra.truncation
            """ -1- create an ocra token """
            parameters = {
                "serial": serial,
                "user": "******",
                "pin": "pin",
                "description": "first QRToken",
                "type": "ocra",
                "ocrapin": ocrapin,
                "otpkey": key,
                "ocrasuite": ocrasuite,
            }

            response = self.app.get(genUrl(controller="admin", action="init"), params=parameters)
            assert '"value": true' in response

            ## verify that the token is usable
            """ -2- fetch the challenge """
            p = {"serial": serial, "data": "0105037311 Konto 50150850 BLZ 1752,03 Eur"}
            response = self.app.get(genUrl(controller="ocra", action="request"), params=p)
            log.info("response %s\n", response)
            if '"value": true' not in response:
                assert '"value": true' in response

            """ -3.a- from the response get the challenge """
            jresp = json.loads(response.body)
            challenge = str(jresp.get("detail").get("challenge"))
            transid = str(jresp.get("detail").get("transactionid"))

            param = {}
            param["C"] = count
            param["Q"] = challenge
            param["P"] = ocrapin
            param["S"] = ""
            if ocra.T != None:
                """    Default value for G is 1M, i.e., time-step size is one minute and the
                       T represents the number of minutes since epoch time [UT].
                """
                now = datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param["T"] = itime

            ocra = OcraSuite(ocrasuite)
            data = ocra.combineData(**param)
            otp = ocra.compute(data, bkey)

            ppin = "pin" + otp

            """ -3.b- verify the correct otp value """
            parameters = {"transactionid": transid, "pass": ppin}
            response = self.app.get(genUrl(controller="ocra", action="check_t"), params=parameters)
            log.info("response %s\n", response)
            if '"result": true' not in response:
                assert '"result": true' in response

            # verify that the failcounter increments (max is 10)
            fcount = 0
            for count in range(1, 3):

                ## create more than one challenge
                chals = random.randint(2, 5)
                for cc in range(1, chals):
                    """ -2- fetch the challenge """
                    p = {"serial": serial, "data": "0105037311 Konto 50150850 BLZ 1752,03 Eur"}
                    response = self.app.get(genUrl(controller="ocra", action="request"), params=p)
                    log.info("response %s\n", response)
                    if '"value": true' not in response:
                        assert '"value": true' in response

                """ -3.a- from the response get the challenge """
                jresp = json.loads(response.body)
                challenge = str(jresp.get("detail").get("challenge"))
                transid = str(jresp.get("detail").get("transactionid"))

                ppin = "pin" + "a" * pinlen

                """ -4- verify the wrong otp value """
                parameters = {"transactionid": transid, "pass": ppin}
                response = self.app.get(genUrl(controller="ocra", action="check_t"), params=parameters)
                log.info("response %s\n", response)
                if '"result": false' not in response:
                    assert '"result": false' in response
                fcount += 1

                ppin = "pin" + "4" * pinlen

                """ -5- verify the wrong otp value """
                parameters = {"transactionid": transid, "pass": ppin}
                response = self.app.get(genUrl(controller="ocra", action="check_t"), params=parameters)
                log.info("response %s\n", response)
                if not '"result": false' in response:
                    assert '"result": false' in response
                fcount += 1

                """ -6- check if the failcounter has incremented  """
                parameters = {"transactionid": transid}
                response = self.app.get(genUrl(controller="ocra", action="checkstatus"), params=parameters)
                log.info("response %s\n", response)
                assert '"status": true' in response
                assstring = '"failcount": %d,' % (fcount)
                log.info("assert %s\n", assstring)
                if assstring not in response:
                    log.error(response)
                    assert assstring in response

                sleep = random.uniform(0.0, 0.3)
                time.sleep(sleep)

            """ -remove the ocra token """
            parameters = {"serial": serial}
            response = self.app.get(genUrl(controller="admin", action="remove"), params=parameters)
            log.info("response %s\n", response)
            assert '"value": 1' in response

            for _iii in range(0, 3):
                parameters = {"serial": serial}
                response = self.app.get(genUrl(controller="admin", action="remove"), params=parameters)

        return response
Пример #13
0
    def calculateOtp(self):
        '''

        '''
        from linotp.lib.crypt import kdf2
        from linotp.lib.ocra import OcraSuite
        from datetime import datetime

        from urlparse import urlparse
        from urlparse import parse_qs

        res = {}
        #description = 'ocra/calculateOtp: calculate the first otp from the given init2 response '

        try:
            params = getLowerParams(request.params)
            log.debug("[calculateOtp]: %r" % params)

            checkPolicyPre('ocra', "calcOTP")

            sharedsecret = params.get('sharedsecret')
            activationcode = params.get('activationcode')
            nonce = params.get('nonce')
            ocrasuite = params.get('ocrasuite')
            challenge = params.get('challenge')
            counter = params.get('counter')
            ocrapin = params.get('ocrapin')

            nonce3 = params.get('no')
            ocrasuite3 = params.get('os')
            #serial3         = params.get('se')

            challenge = params.get('challenge')
            counter = params.get('counter')
            ocrapin = params.get('ocrapin')
            init1 = params.get('init1')
            init2 = params.get('init2')

            ## parse init1 '''
            if init1 is not None:
                ## now parse the appurl for the ocrasuite '''
                uri = urlparse(init1.replace('lseqr://', 'http://'))
                qs = uri.query
                qdict = parse_qs(qs)

                ocrasuite2 = qdict.get('os', None)
                if ocrasuite2 is not None and len(ocrasuite2) > 0:
                    ocrasuite2 = ocrasuite2[0]

                if ocrasuite is None:
                    ocrasuite = ocrasuite2

                sharedsecret2 = qdict.get('sh', None)
                if sharedsecret2 is not None and len(sharedsecret2) > 0:
                    sharedsecret2 = sharedsecret2[0]

                if sharedsecret is None:
                    sharedsecret = sharedsecret2

            ## parse init1
            if init2 is not None:
                ## now parse the appurl for the ocrasuite
                uri = urlparse(init2.replace('lseqr://', 'http://'))
                qs = uri.query
                qdict = parse_qs(qs)

                challenge2 = qdict.get('ch', None)
                if challenge2 is not None and len(challenge2) > 0:
                    challenge2 = challenge2[0]
                if challenge is None:
                    challenge = challenge2

                nonce2 = qdict.get('no', None)
                if nonce2 is not None and len(nonce2) > 0:
                    nonce2 = nonce2[0]
                if nonce is None:
                    nonce = nonce2

            if ocrapin is None:
                ocrapin = ''
            if counter is None:
                counter = 0

            if nonce3 is not None:
                nonce = unicode(nonce3)

            if ocrasuite3 is not None:
                ocrasuite = unicode(ocrasuite3)

            ##  now we have all in place for the key derivation to create the new key
            ##     sharedsecret, activationcode and nonce
            key_len = 20
            if ocrasuite.find('-SHA256'):
                key_len = 32
            elif ocrasuite.find('-SHA512'):
                key_len = 64

            if sharedsecret is not None:
                sharedsecret = unicode(sharedsecret)
            if nonce is not None:
                nonce = unicode(nonce)
            if activationcode is not None:
                activationcode = unicode(activationcode)

            newkey = kdf2(sharedsecret, nonce, activationcode, len=key_len)
            ## hnewkey = binascii.hexlify(newkey)
            ocra = OcraSuite(ocrasuite)

            param = {}
            param['C'] = int(counter)
            param['Q'] = unicode(challenge)
            param['P'] = unicode(ocrapin)
            param['S'] = ''
            if ocra.T is not None:
                ## Default value for G is 1M, i.e., time-step size is one minute and the
                ##  T represents the number of minutes since epoch time [UT].
                now = datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param['T'] = itime

            data = ocra.combineData(**param)
            otp = ocra.compute(data, newkey)

            res = {'otp':otp}

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.exception("[ocra/calculateOtp] policy failed: %r" % pe)
            Session.rollback()
            return sendError(response, pe)

        except Exception as e:
            log.exception("[ocra/calculateOtp] failed: %r" % e)
            Session.rollback()
            return sendError(response, unicode(e), 0)

        finally:
            Session.close()
            log.debug('[ocra/calculateOtp] done')
Пример #14
0
    def calculateOtp(self):
        '''

        '''
        from linotp.lib.crypt import kdf2
        from linotp.lib.ocra import OcraSuite
        from datetime import datetime

        from urlparse import urlparse
        from urlparse import parse_qs

        res = {}
        #description = 'ocra/calculateOtp: calculate the first otp from the given init2 response '

        try:
            params = getLowerParams(request.params)
            log.debug("[calculateOtp]: %r" % params)

            checkPolicyPre('ocra', "calcOTP")

            sharedsecret = params.get('sharedsecret')
            activationcode = params.get('activationcode')
            nonce = params.get('nonce')
            ocrasuite = params.get('ocrasuite')
            challenge = params.get('challenge')
            counter = params.get('counter')
            ocrapin = params.get('ocrapin')

            nonce3 = params.get('no')
            ocrasuite3 = params.get('os')
            #serial3         = params.get('se')

            challenge = params.get('challenge')
            counter = params.get('counter')
            ocrapin = params.get('ocrapin')
            init1 = params.get('init1')
            init2 = params.get('init2')

            ## parse init1 '''
            if init1 is not None:
                ## now parse the appurl for the ocrasuite '''
                uri = urlparse(init1.replace('lseqr://', 'http://'))
                qs = uri.query
                qdict = parse_qs(qs)

                ocrasuite2 = qdict.get('os', None)
                if ocrasuite2 is not None and len(ocrasuite2) > 0:
                    ocrasuite2 = ocrasuite2[0]

                if ocrasuite is None:
                    ocrasuite = ocrasuite2

                sharedsecret2 = qdict.get('sh', None)
                if sharedsecret2 is not None and len(sharedsecret2) > 0:
                    sharedsecret2 = sharedsecret2[0]

                if sharedsecret is None:
                    sharedsecret = sharedsecret2

            ## parse init1
            if init2 is not None:
                ## now parse the appurl for the ocrasuite
                uri = urlparse(init2.replace('lseqr://', 'http://'))
                qs = uri.query
                qdict = parse_qs(qs)

                challenge2 = qdict.get('ch', None)
                if challenge2 is not None and len(challenge2) > 0:
                    challenge2 = challenge2[0]
                if challenge is None:
                    challenge = challenge2

                nonce2 = qdict.get('no', None)
                if nonce2 is not None and len(nonce2) > 0:
                    nonce2 = nonce2[0]
                if nonce is None:
                    nonce = nonce2

            if ocrapin is None:
                ocrapin = ''
            if counter is None:
                counter = 0

            if nonce3 is not None:
                nonce = unicode(nonce3)

            if ocrasuite3 is not None:
                ocrasuite = unicode(ocrasuite3)

            ##  now we have all in place for the key derivation to create the new key
            ##     sharedsecret, activationcode and nonce
            key_len = 20
            if ocrasuite.find('-SHA256'):
                key_len = 32
            elif ocrasuite.find('-SHA512'):
                key_len = 64

            if sharedsecret is not None:
                sharedsecret = unicode(sharedsecret)
            if nonce is not None:
                nonce = unicode(nonce)
            if activationcode is not None:
                activationcode = unicode(activationcode)

            newkey = kdf2(sharedsecret, nonce, activationcode, len=key_len)
            ## hnewkey = binascii.hexlify(newkey)
            ocra = OcraSuite(ocrasuite)

            param = {}
            param['C'] = int(counter)
            param['Q'] = unicode(challenge)
            param['P'] = unicode(ocrapin)
            param['S'] = ''
            if ocra.T is not None:
                ## Default value for G is 1M, i.e., time-step size is one minute and the
                ##  T represents the number of minutes since epoch time [UT].
                now = datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param['T'] = itime

            data = ocra.combineData(**param)
            otp = ocra.compute(data, newkey)

            res = {'otp': otp}

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.exception("[ocra/calculateOtp] policy failed: %r" % pe)
            Session.rollback()
            return sendError(response, pe)

        except Exception as e:
            log.exception("[ocra/calculateOtp] failed: %r" % e)
            Session.rollback()
            return sendError(response, unicode(e), 0)

        finally:
            Session.close()
            log.debug('[ocra/calculateOtp] done')
Пример #15
0
class OcraOtp(object):
    def __init__(self, ocrapin=None):
        self.ocra = None
        self.bkey = None
        self.ocrapin = ocrapin
        self.activationkey = None
        self.sharedsecret = None
        self.ocrasuite = None
        self.serial = None
        self.counter = 0

    def init_1(self, response):
        """ take the response of the first init to setup the OcraOtp"""

        jresp = json.loads(response.body)
        app_import = str(jresp.get("detail").get("app_import"))
        self.sharedsecret = str(jresp.get("detail").get("sharedsecret"))
        self.serial = str(jresp.get("detail").get("serial"))

        """ now parse the appurl for the ocrasuite """
        uri = urlparse(app_import.replace("lseqr://", "http://"))
        qs = uri.query
        qdict = parse_qs(qs)

        ocrasuite = qdict.get("os", None)
        if ocrasuite != None and len(ocrasuite) > 0:
            ocrasuite = ocrasuite[0]

        self.ocrasuite = ocrasuite

        return (self.ocrasuite, self.sharedsecret, self.serial)

    def init_2(self, response, activationKey):
        self.activationkey = activationKey

        jresp = json.loads(response.body)
        self.nonce = str(jresp.get("detail").get("nonce"))
        self.transid = str(jresp.get("detail").get("transactionid"))
        app_import = str(jresp.get("detail").get("app_import"))

        """ now parse the appurl for the ocrasuite """
        uri = urlparse(app_import.replace("lseqr://", "http://"))
        qs = uri.query
        qdict = parse_qs(qs)
        nonce = qdict.get("no", None)
        if nonce != None and len(nonce) > 0:
            nonce = nonce[0]

        challenge = qdict.get("ch", None)
        if challenge != None and len(challenge) > 0:
            challenge = challenge[0]

        self.challenge = challenge
        self.ocra = None
        self.bkey = None

        return (self.challenge, self.transid)

    def _setup_(self):

        if self.ocra != None and self.bkey != None:
            return

        key_len = 20
        if self.ocrasuite.find("-SHA256"):
            key_len = 32
        elif self.ocrasuite.find("-SHA512"):
            key_len = 64

        self.bkey = kdf2(self.sharedsecret, self.nonce, self.activationkey, len=key_len)
        self.ocra = OcraSuite(self.ocrasuite)

        self.counter = 0

        return

    def callcOtp(self, challenge=None, ocrapin=None, counter=-1):

        if self.ocra == None:
            self._setup_()

        if ocrapin == None:
            ocrapin = self.ocrapin

        if challenge == None:
            challenge = self.challenge
        if counter == -1:
            counter = self.counter

        param = {}
        param["C"] = counter
        param["Q"] = challenge
        param["P"] = ocrapin
        param["S"] = ""
        if self.ocra.T != None:
            """    Default value for G is 1M, i.e., time-step size is one minute and the
                   T represents the number of minutes since epoch time [UT].
            """
            now = datetime.now()
            stime = now.strftime("%s")
            itime = int(stime)
            param["T"] = itime

        data = self.ocra.combineData(**param)
        otp = self.ocra.compute(data, self.bkey)

        if counter == -1:
            self.counter += 1

        return otp
Пример #16
0
class OcraOtp(object):

    def __init__(self, ocrapin=None):
        self.ocra = None
        self.bkey = None
        self.ocrapin = ocrapin
        self.activationkey = None
        self.sharedsecret = None
        self.ocrasuite = None
        self.serial = None
        self.counter = 0


    def init_1(self, response):
        ''' take the response of the first init to setup the OcraOtp'''

        jresp = json.loads(response.body)
        app_import = str(jresp.get('detail').get('app_import'))
        self.sharedsecret = str(jresp.get('detail').get('sharedsecret'))
        self.serial = str(jresp.get('detail').get('serial'))

        ''' now parse the appurl for the ocrasuite '''
        uri = urlparse(app_import.replace('lseqr://', 'http://'))
        qs = uri.query
        qdict = parse_qs(qs)

        ocrasuite = qdict.get('os', None)
        if ocrasuite != None and len(ocrasuite) > 0:
            ocrasuite = ocrasuite[0]

        self.ocrasuite = ocrasuite

        return (self.ocrasuite, self.sharedsecret, self.serial)


    def init_2(self, response, activationKey):
        self.activationkey = activationKey

        jresp = json.loads(response.body)
        self.nonce = str(jresp.get('detail').get('nonce'))
        self.transid = str(jresp.get('detail').get('transactionid'))
        app_import = str(jresp.get('detail').get('app_import'))


        ''' now parse the appurl for the ocrasuite '''
        uri = urlparse(app_import.replace('lseqr://', 'http://'))
        qs = uri.query
        qdict = parse_qs(qs)
        nonce = qdict.get('no', None)
        if nonce != None and len(nonce) > 0:
            nonce = nonce[0]

        challenge = qdict.get('ch', None)
        if challenge != None and len(challenge) > 0:
            challenge = challenge[0]

        self.challenge = challenge
        self.ocra = None
        self.bkey = None

        return (self.challenge, self.transid)


    def _setup_(self):

        if self.ocra != None and self.bkey != None:
            return

        key_len = 20
        if self.ocrasuite.find('-SHA256'):
            key_len = 32
        elif self.ocrasuite.find('-SHA512'):
            key_len = 64

        self.bkey = kdf2(self.sharedsecret, self.nonce, self.activationkey, len=key_len)
        self.ocra = OcraSuite(self.ocrasuite)

        self.counter = 0

        return

    def callcOtp(self, challenge=None, ocrapin=None, counter= -1):

        if self.ocra == None:
            self._setup_()

        if ocrapin == None:
            ocrapin = self.ocrapin

        if challenge == None:
            challenge = self.challenge
        if counter == -1:
            counter = self.counter

        param = {}
        param['C'] = counter
        param['Q'] = challenge
        param['P'] = ocrapin
        param['S'] = ''
        if self.ocra.T != None:
            '''    Default value for G is 1M, i.e., time-step size is one minute and the
                   T represents the number of minutes since epoch time [UT].
            '''
            now = datetime.now()
            stime = now.strftime("%s")
            itime = int(stime)
            param['T'] = itime

        data = self.ocra.combineData(**param)
        otp = self.ocra.compute(data, self.bkey)

        if counter == -1:
            self.counter += 1

        return otp
Пример #17
0
    def createChallenge(self, state, options=None):
        '''
        standard API to create an ocra challenge
        '''
        res = True

        ## which kind of challenge gen should be used
        typ = 'raw'

        input = None
        challenge = None
        session = None
        message = ""

        if options is not None:
            input = options.get('challenge', None)
            if input is None:
                input = options.get('message', None)
            if input is None:
                input = options.get('data', None)

            typ = options.get('challenge_type', 'raw')
            ## ocra token could contain a session attribute
            session = options.get('ocra_session', None)

        if input is None or len(input) == 0:
            typ = 'random'

        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)

        if typ == 'raw':
            challenge = ocraSuite.data2rawChallenge(input)
        elif typ == 'random':
            challenge = ocraSuite.data2randomChallenge(input)
        elif typ == 'hash':
            challenge = ocraSuite.data2hashChallenge(input)

        log.debug('[Ocra2TokenClass] challenge: %r ' % (challenge))

        store_data = {
                'challenge' : "%s" % (challenge),
                'serial' : self.token.getSerial(),
                'input' : '',
                'url' : '',
                }

        if input is not None:
            store_data['input'] = input

        if session is not None:
            store_data["session"] = session

        res = self.verify_challenge_is_valid(challenge, session)

        ## add Info: so depending on the Info, the rendering could be done
        ##          as a callback into the token via
        ##          token.getQRImageData(opt=details)
        realms = self.token.getRealms()
        if len(realms) > 0:
            store_data["url"] = get_qrtan_url(realms[0].name)

        ## we will return a dict of all
        attributes = self.prepare_message(store_data, state)
        attributes['challenge'] = challenge

        if attributes != None and "data" in attributes:
            message = attributes.get("data")
            del attributes['data']

        return (res, message, store_data, attributes)
Пример #18
0
    def resync(self, otp1, otp2, options=None):
        '''
        - for the resync to work, we take the last two transactions and their challenges
        - for each challenge, we search forward the sync window length

        '''
        log.debug('[resync] %r : %r' % (otp1, otp2))

        ret = False
        challenges = []

        ## the challenges are orderd, the first one is the newest
        challenges = get_challenges(self.getSerial())

        ##  check if there are enough challenges around
        if len(challenges) < 2:
            return False

        challenge1 = {}
        challenge2 = {}

        if options is None:

            ## the newer one
            ch1 = challenges[0]
            challenge1['challenge'] = ch1.get('data').get('challenge')
            challenge1['transid'] = ch1.get('transid')
            challenge1['session'] = ch1.get('session')
            challenge1['id'] = ch1.get('id')


            ## the elder one
            ch2 = challenges[0]
            challenge2['challenge'] = ch2.get('data').get('challenge')
            challenge2['transid'] = ch2.get('transid')
            challenge2['session'] = ch2.get('session')
            challenge2['id'] = ch2.get('id')

        else:
            if options.has_key('challenge1'):
                challenge1['challenge'] = options.get('challenge1')
            if options.has_key('challenge2'):
                challenge2['challenge'] = options.get('challenge2')


        if len(challenge1) == 0 or len(challenge2) == 0:
            error = "No challeges found!"
            log.error('[Ocra2TokenClass:resync] %s' % (error))
            raise Exception('[Ocra2TokenClass:resync] %s' % (error))



        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)

        syncWindow = self.token.getSyncWindow()
        if  ocraSuite.T is not None:
            syncWindow = syncWindow / 10

        counter = self.token.getOtpCounter()

        ## set the ocra token pin
        ocraPin = ''
        if ocraSuite.P is not None:
            ocraPinObj = self.token.getUserPin()
            ocraPin = ocraPinObj.getKey()

            if ocraPin is None or len(ocraPin) == 0:
                ocraPin = ''

        timeShift = 0
        if  ocraSuite.T is not None:
            timeShift = int(self.getFromTokenInfo("timeShift", 0))

        try:

            count_1 = ocraSuite.checkOtp(otp1, counter, syncWindow, challenge1, pin=ocraPin, timeshift=timeShift)
            if count_1 == -1:
                log.info('[resync] lookup for first otp value failed!')
                ret = False
            else:
                count_2 = ocraSuite.checkOtp(otp2, counter, syncWindow, challenge2, pin=ocraPin, timeshift=timeShift)
                if count_2 == -1:
                    log.info('[resync] lookup for second otp value failed!')
                    ret = False
                else:
                    if ocraSuite.C is not None:
                        if count_1 + 1 == count_2:
                            self.setOtpCount(count_2)
                            ret = True

                    if  ocraSuite.T is not None:
                        if count_1 - count_2 <= ocraSuite.T * 2:
                            ##  callculate the timeshift
                            date = datetime.datetime.fromtimestamp(count_2)
                            log.info('[resync] syncing token to new timestamp: %r' % (date))

                            now = datetime.datetime.now()
                            stime = now.strftime("%s")
                            timeShift = count_2 - int(stime)
                            self.addToTokenInfo('timeShift', timeShift)
                            ret = True

        except Exception as ex:
            log.error('[Ocra2TokenClass:resync] unknown error: %r' % (ex))
            raise Exception('[Ocra2TokenClass:resync] unknown error: %s' % (ex))

        log.debug('[resync]: %r ' % (ret))
        return ret
Пример #19
0
    def ptest_OCRA_token_failcounterInc(self, tid=1):
        '''
            test_OCRA_token_failcounterInc: failcounter increment

            description:
                for all ocrasuites:
                   create and enroll token
                   verify the first otp
                   get some challenges
                   4 times:
                      verify a wrong otp
                      verify a wrong transaction
                      check status and if fail counter has incremented
        '''
        tcount = 0
        for test in self.tests:
            ocrasuite = test['ocrasuite']
            key = test['keyh']
            bkey = test['key']
            ocrapin = 'myocrapin'
            tid = tid
            serial = "QR_One_%r_%r_%r_%r" % (tid, tcount, int(time.time()), random.randint(0, 100))
            log.info("## serial: %s" % serial)
            count = 0
            tcount = tcount + 1

            ocra = OcraSuite(ocrasuite)
            pinlen = ocra.truncation
            ''' -1- create an ocra token '''
            parameters = {
                          "serial"      : serial,
                          "user"        : "root",
                          "pin"         : "pin",
                          "description" : "first QRToken",
                          'type'        : 'ocra',
                          'ocrapin'     : ocrapin,
                          'otpkey'      : key,
                          'ocrasuite'   : ocrasuite
                          }

            response = self.app.get(genUrl(controller='admin', action='init'), params=parameters)
            assert '"value": true' in response

            ## verify that the token is usable
            ''' -2- fetch the challenge '''
            p = {"serial"      : serial,
                 "data"        : "0105037311 Konto 50150850 BLZ 1752,03 Eur"
                }
            response = self.app.get(genUrl(controller='ocra', action='request'), params=p)
            log.info("response %s\n", response)
            if '"value": true' not in response:
                assert '"value": true' in response

            ''' -3.a- from the response get the challenge '''
            jresp = json.loads(response.body)
            challenge = str(jresp.get('detail').get('challenge'))
            transid = str(jresp.get('detail').get('transactionid'))

            param = {}
            param['C'] = count
            param['Q'] = challenge
            param['P'] = ocrapin
            param['S'] = ''
            if ocra.T != None:
                '''    Default value for G is 1M, i.e., time-step size is one minute and the
                       T represents the number of minutes since epoch time [UT].
                '''
                now = datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param['T'] = itime

            ocra = OcraSuite(ocrasuite)
            data = ocra.combineData(**param)
            otp = ocra.compute(data, bkey)

            ppin = 'pin' + otp

            ''' -3.b- verify the correct otp value '''
            parameters = {"transactionid"   : transid,
                          "pass"            : ppin,
                          }
            response = self.app.get(genUrl(controller='ocra', action='check_t'), params=parameters)
            log.info("response %s\n", response)
            if '"result": true' not in response:
                assert '"result": true' in response

            # verify that the failcounter increments (max is 10)
            fcount = 0
            for count in range(1, 3):

                ## create more than one challenge
                chals = random.randint(2, 5)
                for cc in range(1, chals):
                    ''' -2- fetch the challenge '''
                    p = {"serial"      : serial,
                         "data"        : "0105037311 Konto 50150850 BLZ 1752,03 Eur"
                        }
                    response = self.app.get(genUrl(controller='ocra', action='request'), params=p)
                    log.info("response %s\n", response)
                    if '"value": true' not in response:
                        assert '"value": true' in response


                ''' -3.a- from the response get the challenge '''
                jresp = json.loads(response.body)
                challenge = str(jresp.get('detail').get('challenge'))
                transid = str(jresp.get('detail').get('transactionid'))

                ppin = 'pin' + 'a' * pinlen

                ''' -4- verify the wrong otp value '''
                parameters = {"transactionid"   : transid,
                              "pass"            : ppin,
                              }
                response = self.app.get(genUrl(controller='ocra', action='check_t'), params=parameters)
                log.info("response %s\n", response)
                if '"result": false' not in response:
                    assert '"result": false' in response
                fcount += 1

                ppin = 'pin' + '4' * pinlen

                ''' -5- verify the wrong otp value '''
                parameters = {"transactionid"   : transid,
                              "pass"            : ppin,
                              }
                response = self.app.get(genUrl(controller='ocra', action='check_t'), params=parameters)
                log.info("response %s\n", response)
                if not '"result": false' in response:
                    assert '"result": false' in response
                fcount += 1

                ''' -6- check if the failcounter has incremented  '''
                parameters = {"transactionid"   : transid,
                              }
                response = self.app.get(genUrl(controller='ocra', action='checkstatus'), params=parameters)
                log.info("response %s\n", response)
                assert '"status": true' in response
                assstring = '"failcount": %d,' % (fcount)
                log.info("assert %s\n", assstring)
                if assstring not in response:
                    log.error(response)
                    assert assstring in response

                sleep = random.uniform(0.0, 0.3)
                time.sleep(sleep)

            ''' -remove the ocra token '''
            parameters = {"serial"      : serial, }
            response = self.app.get(genUrl(controller='admin', action='remove'), params=parameters)
            log.info("response %s\n", response)
            assert '"value": 1' in response

            for _iii in range(0, 3):
                parameters = {"serial"      : serial, }
                response = self.app.get(genUrl(controller='admin', action='remove'), params=parameters)


        return response
Пример #20
0
    def checkOtp(self, passw , counter, window, options=None):
        '''
        checkOtp - standard callback of linotp to verify the token

        :param passw:      the passw / otp, which has to be checked
        :type passw:       string
        :param counter:    the start counter
        :type counter:     int
        :param  window:    the window, in which the token is valid
        :type  window:     int
        :param options:    options contains the transaction id,
                            eg. if check_t checks one transaction
                            this will support assynchreonous otp checks
                            (when check_t is used)
        :type options:     dict

        :return:           verification counter or -1
        :rtype:            int (-1)

        '''
        log.debug('[checkOtp] %r: %r: %r' % (passw, counter, window))
        ret = -1

        challenges = []
        serial = self.getSerial()

        if options is None:
            options = {}

        maxRequests = int(getFromConfig("Ocra2MaxChallengeRequests", '3'))

        if 'transactionid' in options:
            transid = options.get('transactionid', None)
            challs = get_challenges(serial=serial, transid=transid)
            for chall in challs:
                (rec_tan, rec_valid) = chall.getTanStatus()
                if rec_tan == False:
                    challenges.append(chall)
                elif rec_valid == False:
                    ## add all touched but failed challenges
                    if chall.getTanCount() <= maxRequests:
                        challenges.append(chall)

        if 'challenge' in options:
            ## direct challenge - there might be addtionalget info like
            ## session data in the options
            challenges.append(options)

        if len(challenges) == 0:
            challs = get_challenges(serial=serial)
            for chall in challs:
                (rec_tan, rec_valid) = chall.getTanStatus()
                if rec_tan == False:
                    ## add all untouched challenges
                    challenges.append(chall)
                elif rec_valid == False:
                    ## add all touched but failed challenges
                    if chall.getTanCount() <= maxRequests:
                        challenges.append(chall)

        if len(challenges) == 0:
            err = 'No open transaction found for token %s' % serial
            log.error(err)  ##TODO should log and fail!!
            raise Exception(err)

        ## prepare the challenge check - do the ocra setup
        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)

        ## set the ocra token pin
        ocraPin = ''
        if ocraSuite.P is not None:
            ocraPinObj = self.token.getUserPin()
            ocraPin = ocraPinObj.getKey()

            if ocraPin is None or len(ocraPin) == 0:
                ocraPin = ''

        timeShift = 0
        if  ocraSuite.T is not None:
            defTimeWindow = int(getFromConfig("ocra.timeWindow", 180))
            window = int(self.getFromTokenInfo('timeWindow', defTimeWindow)) / ocraSuite.T
            defTimeShift = int(getFromConfig("ocra.timeShift", 0))
            timeShift = int(self.getFromTokenInfo("timeShift", defTimeShift))

        default_retry_window = int(getFromConfig("ocra2.max_check_challenge_retry", 0))
        retry_window = int(self.getFromTokenInfo("max_check_challenge_retry", default_retry_window))

        ## now check the otp for each challenge

        for ch in challenges:
            challenge = {}

            ##  preserve transaction context, so we could use this in the status callback
            self.transId = ch.get('transid', None)
            challenge['transid'] = self.transId
            challenge['session'] = ch.get('session', None)

            ## we saved the 'real' challenge in the data
            data = ch.get('data', None)
            if data is not None:
                challenge['challenge'] = data.get('challenge')
            elif 'challenge' in ch:
                ## handle explicit challenge requests
                challenge['challenge'] = ch.get('challenge')

            if challenge.get('challenge') is None:
                raise Exception('could not checkOtp due to missing challenge'
                                ' in request: %r' % ch)

            ret = ocraSuite.checkOtp(passw, counter, window, challenge, pin=ocraPin , options=options, timeshift=timeShift)
            log.debug('[checkOtp]: %r' % (ret))

            ## due to the assynchronous challenge verification of the checkOtp
            ## it might happen, that the found counter is lower than the given
            ## one. Thus we fix this here to deny assynchronous verification

            # we do not support retry checks anymore:
            # which means, that ret might be smaller than the actual counter
            if ocraSuite.T is None:
                if ret + retry_window < counter:
                    ret = -1

            if ret != -1:
                break

        if -1 == ret:
            ##  autosync: test if two consecutive challenges + it's counter match
            ret = self.autosync(ocraSuite, passw, challenge)


        return ret