linotp.lib.tokens.ocra2token module

This file containes the standard token definitions:
  • OCRA2TokenClass

the OCRA2 Token will use the standard challenge response instead of the dedicated ocra/request and ocra/check_t

The rollout is a 2 step process with the following steps:

  1. call the /admin/init controller with the following parameters
param type:must be “ocra2” for an ocra2 token
param genkey:must be “1”, if the server should generate the seed otherwise you can use the :param otpkey: with the seed
param ocrasuite:
 your ocra suite of choice e.g. “OCRA-1:HOTP-SHA256-8:C-QA64”
param sharedsecret:
 value must be “1”
param serial:optional, if the serial will be defined by external

as reply a set of information is returned, where the relevant part is the in the image data for the softtoken qrscan in the structure


<img width=250 src=”data:image/png;base64,iVBO....

which could be embedded in the enrollment application. Other relevant information (as well part in the qr encoded data) is the

“sharedsecret”: “25676ef34bd1873834bbe10c4c4176b0a9689619”

which is the server data part for the pairing process transferd to the qrtan app.

2. complete the rollout The qrtan app will calculate an activation code, that must be transfered back to the server as a set of input data for the second enrollment step by calling the /admin/init controller with the following parameters:

param type:must be of the same token type “ocra2”
param serial:must be the same as received from the first request
param genkey:must be of “1”, which indicates, that the init is not finished
param activationcode:
param ocrasuite:
 same ocrasuite as above “OCRA-1:HOTP-SHA256-8:C-QA64”,
param message:optional the message, that is displayed in the app, e.g. “Transaktion: Ausrollen eines OCRA2 Tokens”,

As response again an <img > is returned, which is the ‘finishing’ transaction, where the qrtan app will reply only with an otp value

Further challenge request and response processing could then be managed by using the /validate/check_s with

param serial:token serial number, as defined above
param challenge:
 the challenge input data as heart of the transaction

or when using /validate/check with

param user:the assigned token user / owner
param passw:which contains the token pin
param challenge:
 the challenge input data as heart of the transaction

a response to this request will then contain the /detail/ocraurl/img image data and the transaction id, which is the referer to the incomming challenge respones from the qrtan app.

The challenge response then is verified by /validate/check_t and the parameters:

param transactionid:
 the transaction id “440364804594”,
param pass:the otp value e.g. “48344099”

But as well the /validate/check controller could be used to verify the transaction by providing in addition the user name.

class linotp.lib.tokens.ocra2token.Ocra2TokenClass(aToken)[source]

Bases: linotp.lib.tokenclass.TokenClass

Ocra2TokenClass implement an ocra compliant token

used from Config
OcraMaxChallenges - number of open challenges per token
if None: 3

Ocra2ChallengeValidityTime timeout definition in seconds OcraDefaultSuite - if none :’OCRA-1:HOTP-SHA256-8:C-QN08’ QrOcraDefaultSuite - if none :’OCRA-1:HOTP-SHA256-8:C-QA64’

algorithm Ocra Token Rollout: tow phases of rollout

  1. https://linotpserver/admin/init?

    type=ocra& genkey=1& sharedsecret=1& user=BENUTZERNAME& session=SESSIONKEY

    =>> “serial” : SERIENNUMMER, “sharedsecret” : DATAOBJECT, “app_import” : IMPORTURL - genSharedSecret - vom HSM oder urandom ? - app_import : + linotp://

    • ocrasuite ->> default aus dem config: (DefaultOcraSuite)
    • sharedsecret (Länge wie ???)
    • seriennummer
    • seriennummer: uuid
    • token wird angelegt ist aber nicht aktiv!!! (counter == 0)
  2. https://linotpserver/admin/init?

    type=ocra& genkey=1& activationcode=AKTIVIERUNGSCODE& user=BENUTZERNAME& message=MESSAGE& session=SESSIONKEY

    =>> “serial” : SERIENNUMMER, “nonce” : DATAOBJECT, “transactionid” : “TRANSAKTIONSID, “app_import” : IMPORTURL

    • nonce - von HSM oder random ?
    • pkcs5 - kdf2
    • es darf zur einer Zeit nur eine QR Token inaktiv (== im Ausrollzustand) sein !!!!! der Token wird über den User gefunden
    • seed = pdkdf2(nonce + activcode + shared secret)
    • challenge generiern - von urandom oder HSM
  3. check_t
    • counter ist > nach der ersten Transaktion
    • if counter >= 1: delete sharedsecret löschen
autosync(ocraSuite, passw, challenge)[source]

try to resync a token automaticaly, if a former and the current request failed

  • ocraSuite (ocra object) – the ocraSuite of the current Token
  • passw
challenge(data, session='', typ='raw', challenge=None)[source]

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)
  • data (string or None) – data, which is the base for the challenge or None
  • session (string) – session support for ocratokens

challenge response containing the transcation id and the challenge for the ocrasuite

:rtype : tuple of (transId(string), challenge(string))

checkOtp(passw, counter, window, options=None)[source]

checkOtp - standard callback of linotp to verify the token

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

verification counter or -1

Return type:

int (-1)

checkResponse4Challenge(user, passw, options=None, challenges=None)[source]

verify the response of a previous challenge

  • user – the requesting user
  • passw – the to be checked pass: (otp) & trans_id | (pin+otp)
  • options – options an additional argument, which could be token specific
  • challenges – the list of challenges, where each challenge is described as dict

tuple of (boolean and the list matching challenge ids)

createChallenge(state, options=None)[source]

standard API to create an ocra challenge

classmethod getClassInfo(key=None, ret='all')[source]

getClassInfo - returns all or a subtree of the token definition

  • key (string) – subsection identifier
  • ret (user defined) – default return value, if nothing is found

subsection if key exists or user defined

:rtype : s.o.

classmethod getClassPrefix()[source]
classmethod getClassType()[source]

getClassType - return the token type shortname

Return type:string

getInfo - return the status of the token rollout

Returns:info of the ocra token state
Return type:dict
getInitDetail(params, user=None)[source]

to complete the token normalisation, the response of the initialiastion should be build by the token specific method, the getInitDetails


getQROcraSuiteSuite - return the QR Ocra Suite - if none, it will return the default

Returns:Ocrasuite of token
Return type:string

getQROcraSuiteSuite - return the QR Ocra Suite - if none, it will return the default

Returns:QROcrasuite of token
Return type:string

getStatus - assembles the status of a transaction / challenge in a dict

{ “serial”: SERIENNUMMER1,
“transactionid”: TRANSACTIONID1, “received_tan”: true, “valid_tan”: true, “failcount”: 0


Parameters:transactionId (string) – the transaction / challenge id
Returns:status dict
Return type:dict
classmethod get_helper_params_post(param, user=None)[source]
is_challenge_request(passw, user, options=None)[source]

check, if the request would start a challenge

  • default: if the passw contains only the pin, this request would

trigger a challenge

  • in this place as well the policy for a token is checked
  • passw – password, which might be pin or pin+otp
  • options – dictionary of additional request parameters

returns true or false

is_challenge_response(passw, user, options=None, challenges=None)[source]

test for the ocra token, if this is a response to a challenge

normal challenge response brings in a password and there is at least a stored challenge available. But OCRA support as well direct challenges, which bring the challenge data and the otp within the same request.

  • passw – password, which might be pin or pin+otp
  • user – the requesting user
  • options – dictionary of additional request parameters

returns true or false


this method proves the validity of a challenge - the default implementation tests, if the challegenge start is in the default vality time window.

Parameters:challenge – challenge object
Returns:true or false
prepare_message(data, transId)[source]

prepare the challenge response message

  • data
  • transId – the transaction/state refenence id

remark: we need the state/transId in the inner scope to support the signing of the whole request including the state/transId

resync(otp1, otp2, options=None)[source]
  • for the resync to work, we take the last two transactions and their challenges
  • for each challenge, we search forward the sync window length

sign the received data with the secret key

Parameters:data – arbitrary string object
Returns:hexlified signature of the data

statusValidationFail - callback to enable a status change,

will be called if the token verification has failed

:return - nothing


statusValidationSuccess - callback to enable a status change,

remark: will be called if the token has been succesfull verified

  • nothing
update(params, reset_failcount=True)[source]

update: add further definition for token from param in case of init

verify_challenge_is_valid(challenge, session)[source]

verify, if a challenge is valid according to the ocrasuite definition of the token

linotp.lib.tokens.ocra2token.get_qrtan_url(qrtan_policy_name, realms, callback_id=None)[source]

Worker to returns the URL for the half automatic mode for the QR TAN token for the given realm

  • qrtan_policy_name – either ‘qrtanurl_init’ or ‘qrtanurl’
  • realms – list of realms or None
  • callback_id – support of multiple callback definitions

url string


there might be more than one url, if the token belongs to more than one realm. it is tested, if all are the same, otherwise an exception is raised

linotp.lib.tokens.ocra2token.qrtan_url(realms, callback_id=None)[source]

Returns the URL for the half automatic mode for the QR TAN token for the given realm

Remark:there might be more than one url, if the token belongs to more than one realm
Parameters:realms – list of realms or None
Returns:url string
linotp.lib.tokens.ocra2token.qrtanurl_init(realms, callback_id=None)[source]

Returns the URL for the half automatic mode for the QR TAN token for the given realm

Remark:there might be more than one url, if the token belongs to more than one realm
Parameters:realms – list of realms or None
Returns:url string