MFA configuring Timed One Time Password (TOTP)

Other posts on MFA:

What is a Timed One Time Password?

You can have a hardware dongle, or an authenticator app on your phone (or other device) configured with a secret key. You can request the dongle or app to generate a temporary password which is valid for a period, typically 30 seconds or one minute. With this validity period it makes it hard for other people to use this password to get access to your system.

In theory the application to take the secret and generate a code should be simple to implement, but not all of the MFA parameters work will all authentication applications, for example some applications only support SHA-1, and do not support SHA256. You need to configure MFA and the userid to use parameters which work with your choice of authentication app. 

The AZFEXEC configuration tool allows you to specify

  • SHA-1, SHA256, SHA384 SHA512

You can configure a user to have SHA1, SHA256, SHA384, SHA512. Some authentication applications only support SHA1.

If you get it wrong, you can reset the userid, add the correct tags, and get the user to reactivate the userid.

Follow the documentation

The documentation is pretty good.

I defined the resources

//         DD   *,SYMBOLS=JCLONLY 
RLIST MFADEF FACTOR.AZFTOTP1
RLIST FACILITY IRR.RFACTOR.MFADEF.AZFTOTP1
RLIST FACILITY IRR.RFACTOR.USER

RDEF MFADEF FACTOR.AZFTOTP1 OWNER(&OWNER)
RDEF FACILITY IRR.RFACTOR.MFADEF.AZFTOTP1 OWNER(&OWNER)
RDEF FACILITY IRR.RFACTOR.USER UACC(NONE)

SETROPTS RACLIST(MFADEF) REFRESH
SETROPTS RACLIST(FACILITY) REFRESH

and

//         DD   *,SYMBOLS=JCLONLY 
PERMIT IRR.RFACTOR.MFADEF.AZFTOTP1 ACCESS(ALTER) CLASS(FACILITY) -
ID(&ADMIN)
PERMIT IRR.RFACTOR.MFADEF.AZFTOTP1 ACCESS(READ) CLASS(FACILITY) -
ID(&STC)
PERMIT IRR.RFACTOR.USER ACCESS(UPDATE) CLASS(FACILITY) ID(&STC)
PERMIT IRR.DIGTCERT.LISTRING CLASS(FACILITY) ID(&STC) ACCESS(READ)

SETROPTS RACLIST(FACILITY) REFRESH
SETROPTS RACLIST(MFADEF) REFRESH

RLIST FACILITY IRR.RFACTOR.MFADEF.AZFTOTP1 ALL
RLIST FACILITY IRR.RFACTOR.USER ALL
RLIST MFADEF FACTOR.AZFTOTP1 MFA ALL

I followed Additional system programming steps for TOTP and used AZFEXEC to configure AZFTOTP1.

I used the following values

  • PKCS#11 Token Name: MFATOKEN
  • Key Label: I let it default to what was used previously
  • Use Single-key Encryption: I let it default to Y
  • REALM: I used MYREALM. Once you have MFA configured you may wish to revisit this
  • Initial Trace Level: default
  • Digest Algorithm: 2 (SHA256). Some authenticator apps do not support all algorithm. You can change this on a per user basis
  • Token Code Length: 1 (6 Digit). Some authenticator apps only support a length of 6
  • Token Period: 2 (30 seconds). Some authenticator apps only support 30 seconds
  • Window:1 (default)
  • Compound In-band Authentication: This is to use more than one factor to logon. 
    • During initial set up and testing I set this to N. Once this worked, I set it to Y
    • Credential Order: 1. I logged on with 123456:PASSW0RD
    • Factor Separator: I used the default ( see the above line 123456>:<PASSW0RD)
  • Suspension Threshold: 10. This was set to the default value “0”,
  • Initial Trace level: default

Start the IBM MFA services started task

As part of the base MFA configuration I had already done the steps in Start the IBM MFA services started task.

Restart the MFA started tasks.

Task AZF#IN00 now produces message

AZF2109I Authenticator initialized : entry 0x206E40A8, name AZFTOTP1 (strong).

Restart the MFAweb server task (AZF#IN01)

Configure a user

I used

//         DD   *,SYMBOLS=JCLONLY 
* RESET THE MFA ATTRIBUTES
ALU &TOTPUSER MFA(NOPWFALLBACK)
ALU &TOTPUSER MFA(FACTOR(AZFTOTP1) NOACTIVE )
ALU &TOTPUSER MFA(FACTOR(AZFTOTP1) NOTAGS )
ALU &TOTPUSER MFA(DELPOLICY( OOBCERT ) )
ALU &TOTPUSER MFA(DELPOLICY( OOBTOTP ) )

ALU &TOTPUSER MFA(FACTOR(AZFTOTP1) ACTIVE TAGS(REGSTATE:OPEN))

ALU &TOTPUSER MFA(FACTOR(AZFTOTP1) NOACTIVE )

LU &TOTPUSER MFA

The LU output has

MULTIFACTOR AUTHENTICATION INFORMATION:            
---------------------------------------
PASSWORD FALLBACK IS ALLOWED
FACTOR = AZFTOTP1
STATUS = ACTIVE
FACTOR TAGS =
REGSTATE:OPEN

Activate the user

Use the web site https://xx.xx.xx.xx:6793/AZFTOTP1/genericStart to start the activation. This prompts for your userid and password. If they are correct and the userid has been configured correctly it will display a QR code.

Use your authentication app to add a userid, by scanning the QR code. If successful, the app will generate a code. Enter this code in the web page to complete the activation.

Initial set up and testing

During initial testing, you can use just the 6 digit code to logon, for example to TSO. Once this is working you can use the AZFEXEC panels to configure AZFTOTP1 to enable Compound In-band Authentication, where you will need the One Time Password, plus your (TSO) password. You can specify if you want the format 123456:passw0rd or passw0rd:123456.

For TSO to take the TOTP and password, TSO will need to configured to support passwords greater than 8 characters long (passphrase support). The IKJTSOxx needs.

LOGON PASSPHRASE(ON)

For those applications which do not accept long password you will need to set up an Out of Band policy.

Define a simple Out of Band policy for just the TOTP

//         DD   *,SYMBOLS=JCLONLY 
RDEL MFADEF POLICY.OOBTOTP
RDEF MFADEF POLICY.OOBTOTP OWNER(&OWNER) -
MFPOLICY(FACTOR(AZFTOTP1) TOKENTIMEOUT(60) REUSE(N))
SETROPTS RACLIST(MFADEF) REFRESH
RLIST MFADEF POLICY.OOBTOTP MFPOLICY
RDELETE FACILITY IRR.RFACTOR.POLICY.OOBTOTP
RDEF FACILITY IRR.RFACTOR.POLICY.OOBTOTP UACC(READ) -
OWNER(&OWNER)
SETROPTS RACLIST(FACILITY) REFRESH

MFA: setting up Linux as an authenticator to generate a TOTP password

Other posts on MFA:

With Timed One Timed Passwords, you can use an application on your mobile phone for generating the TOTP codes.

You can also do this from Linux and generate the code to be able to logon to z/OS from Linux (Ubuntu 22.04). I used cURL and a Linux authenticator tool called oathtool. I expect other techniques are available, such as with Python.

Overview of the process

  • From Linux, send the userid and password request in a URL from Linux to https://&#8230;.:6793/AZFTOTP1/genericToken.
  • This sends back a response with
    • “status”:0,
    • “rc”:0,
    • “rsn”:0,
    • “preflightPathBase”:”/AZFTOTP1/preflight”,
    • “inviteCode”:”HXKNSSWMMDIZ2DVB1R2VNTGA2MOUJDKE”,
    • “otpauthURL”:”otpauth://totp/T012@MYREALM
    • ?secret=MQB4T…2Y
    • &issuer=MYREALM
    • &algorithm=SHA1
    • &digits=6
    • &period=30″}
  • The data is
    • The “preflightPathBase” is the URL to send back the code to
    • The “inviteCode” identifies the specific request to MFA
    • The secret is the value used to generate the OTP – it should be kept securely
    • Algorithm specifies the algorithm to be used, for example SHA1, or SHA256
    • The number of digits to be generated in the numeric code
    • The period when it should generate a new code, typically 30 seconds.
  • The oathtool is invoked passing the secret and the algorithm etc. and it generates a code
  • The code is sent back to the requester to complete the registration process

The bash script

url="https://10.1.1.2:6793"
http=$url"/AZFTOTP1/genericToken"

data='{"userid":"T012","password":"11111111"}'

x=$(curl --config curlyubi.parms --tlsv1.2 --data $data $http )
# echo "response" $x

rc=$(echo $x | cut -d',' -f 1 )
rsn=$(echo $x | cut -d',' -f 2 )
echo "rc:"$rc
# check it is a valid response
if [ "$rc" = "{\"status\":0" ]; then
echo "valid....."
else
echo "RC:"$rc "RSN:"$rsn $x
return
fi
# extract the data from the input data - split at ',' and return the nth field
# remove surrounding quotes etc
preFlight=$(echo $x | cut -d',' -f 4 |awk -F'":"|"' '{print $3}')
echo "preflight:"$preFlight

invite=$(echo $x | cut -d',' -f 5 |awk -F'":"|"' '{print $3}')
#a5=$(echo $x | cut -d',' -f 5 )
echo "invite code:"$invite

secret=$(echo $x | cut -d',' -f 6 | awk -F'secret=|&issuer' '{print $2}')
#echo "secret is "$secret

alg=$(echo $x | cut -d',' -f 6 | awk -F'algorithm=|&digits' '{print $2}')
#echo "algorithm" $alg

digits=$(echo $x | cut -d',' -f 6 | awk -F'digits=|&period' '{print $2}')
#echo "digits:"$digits

period=$(echo $x | cut -d',' -f 6 | awk -F'period=|"}' '{print $2}')

# echo "period:" $period
# generate the code
tss="--time-step-size="$period
code=$(oathtool --totp=$alg --digits=$digits $tss --window=0 --base32 $secret)

# and send it back
ht=$url""$preFlight"/"$invite"/"$code
y=$(curl $trace --config curlyubi.parms --tlsv1.2 -X GET $ht )
echo "Final response" $y

Where the bash code does

  • rsn=$(echo $x | cut -d’,’ -f 2 ) says take the data in variable x, split it at “,” (cut -d’,’) and take the second field (-f 2)
  • awk -F’digits=|&period’ ‘{print $2}’ says split the data into … “digits=” …. “&period” and take the second piece of data, the ….

When this ran successfully it generated

{“msg”:”yes”,”status”:0}

When I reran it I got a message from the first curl request

response {“rc”:8,”rsn”:23}

if you register using the web browser, the message is

TOTP Enrollment is not available for your User ID. Your account is already provisioned.

In the ./htdocs/js/totpUtils.js is the mapping from rsn code to message.

Generating a code when needed

Whenever you execute

code=$(oathtool –totp=$alg –digits=$digits $tss –window=0 –base32 $secret)

a new code is generated. This means you need to retain the various parameters ( secret, digits etc) on Linux. Having the parameters in a file may be insecure, so you may want to consider encrypting the file with the parameters, and use, for example, a dongle with the private key on it. This means to be able to access the parameters you need the dongle.

What is supported?

The oathtool help says the supported algorithms are “SHA1”, “SHA256”, or “SHA512” The MFA product also supports SHA384 – but cannot be used with authtool.