Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rlm_totp: Backport changes from v3.2.x #5181

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions debian/libfreeradius4.install
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ usr/lib/freeradius/libfreeradius-sim.so
usr/lib/freeradius/libfreeradius-tacacs.so
usr/lib/freeradius/libfreeradius-tftp.so
usr/lib/freeradius/libfreeradius-tls.so
usr/lib/freeradius/libfreeradius-totp.so
usr/lib/freeradius/libfreeradius-unlang.so
usr/lib/freeradius/libfreeradius-util.so
usr/lib/freeradius/libfreeradius-vmps.so
1 change: 1 addition & 0 deletions doc/antora/modules/raddb/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
*** xref:mods-available/sqlippool.adoc[SQL-IP-Pool Module]
*** xref:mods-available/sradutmp.adoc[sRadutmp Module]
*** xref:mods-available/stats.adoc[Stats Module]
*** xref:mods-available/totp.adoc[TOTP Module]
jpereira marked this conversation as resolved.
Show resolved Hide resolved
*** xref:mods-available/unbound.adoc[Unbound Module]
*** xref:mods-available/unix.adoc[Unix Module]
*** xref:mods-available/unpack.adoc[Unpack Module]
Expand Down
50 changes: 42 additions & 8 deletions doc/antora/modules/raddb/pages/mods-available/totp.adoc
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@



Time-based One-Time Passwords (TOTP)
= Time-based One-Time Passwords (TOTP)

Defined in https://tools.ietf.org/html/rfc6238[RFC 6238], and used in Google Authenticator.
Defined in `rfc6238`, and used in Google Authenticator.

This module can only be used in the "authenticate" section.

The Base32-encoded secret should be placed into:


Any "bare" key should be placed into:


If `TOTP.Key` exists, then it will be used instead of `TOTP.Secret`.

The TOTP password entered by the user should be placed into:


The module will return "ok" if the passwords match, and "fail"
The module will return `ok` if the passwords match, and `fail`
if the passwords do not match.

Note that this module will NOT interact with Google. The module is
NOTE: The crypto algorithms are HmacSHA1, HmacSHA256 and HmacSHA512.

NOTE: This module will *NOT* interact with Google. The module is
intended to be used where the local administrator knows the TOTP
secret key, and user has an authenticator app on their phone.

Note also that while you can use the Google "chart" APIs to
NOTE: Also that while you can use the Google "chart" APIs to
generate a QR code, doing this will give the secret to Google!

Administrators should instead install a tool such as "qrcode"
Expand All @@ -29,15 +36,42 @@ Administrators should instead install a tool such as "qrcode"
and then run that locally to get an image.


The module takes no configuration items.

## Configuration Settings

totp { ... }::


time_step:: Default time step between time changes.



otp_length:: Length of the one-time password.

Must be 6 or 8



lookback_steps:: How many steps backward in time we look for a matching OTP.



lookback_interval:: Time delta between steps.

Cannot be larger than `time_step`


== Default Configuration

```
# &control.TOTP.Secret
# &request.TOTP.From-User
# `&control.TOTP.Secret`
# `&control.TOTP.Key`
# `&request.TOTP.From-User`
# https://linux.die.net/man/1/qrencode
totp {
time_step = 30
otp_length = 6
lookback_steps = 1
lookback_interval = 30
}
```
53 changes: 41 additions & 12 deletions raddb/mods-available/totp
Original file line number Diff line number Diff line change
@@ -1,46 +1,75 @@
# -*- text -*-
# -*- text -*-
#
# $Id$

########################################################################
#
# Time-based One-Time Passwords (TOTP)
# = Time-based One-Time Passwords (TOTP)
#
# Defined in RFC 6238, and used in Google Authenticator.
# Defined in `rfc6238`, and used in Google Authenticator.
#
# This module can only be used in the "authenticate" section.
#
# The Base32-encoded secret should be placed into:
#
# &control:TOTP-Secret
# `&control.TOTP.Secret`
#
# Any "bare" key should be placed into:
#
# &control:TOTP-Key
# `&control.TOTP.Key`
#
# If TOTP-Key exists, then it will be used instead of TOTP-Secret.
# If `TOTP.Key` exists, then it will be used instead of `TOTP.Secret`.
#
# The TOTP password entered by the user should be placed into:
#
# &request:TOTP-Password
# `&request.TOTP.From-User`
#
# The module will return "ok" if the passwords match, and "fail"
# The module will return `ok` if the passwords match, and `fail`
# if the passwords do not match.
#
# Note that this module will NOT interact with Google. The module is
# NOTE: The crypto algorithms are HmacSHA1, HmacSHA256 and HmacSHA512.
#
# NOTE: This module will *NOT* interact with Google. The module is
# intended to be used where the local administrator knows the TOTP
# secret key, and user has an authenticator app on their phone.
#
# Note also that while you can use the Google "chart" APIs to
# NOTE: Also that while you can use the Google "chart" APIs to
# generate a QR code, doing this will give the secret to Google!
#
# Administrators should instead install a tool such as "qrcode"
#
# https://linux.die.net/man/1/qrencode
#
# and then run that locally to get an image.
#
#
# The module takes no configuration items.

#
# ## Configuration Settings
#
# totp { ... }::
#
totp {
#
# time_step:: Default time step between time changes.
#
time_step = 30

#
# otp_length:: Length of the one-time password.
#
# Must be 6 or 8
#
otp_length = 6

#
# lookback_steps:: How many steps backward in time we look for a matching OTP.
#
lookback_steps = 1

#
# lookback_interval:: Time delta between steps.
#
# Cannot be larger than `time_step`
#
lookback_interval = 30
}
1 change: 1 addition & 0 deletions redhat/freeradius.spec
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,7 @@ fi
%{_libdir}/freeradius/libfreeradius-tacacs.so
%{_libdir}/freeradius/libfreeradius-tftp.so
%{_libdir}/freeradius/libfreeradius-tls.so
%{_libdir}/freeradius/libfreeradius-totp.so
%{_libdir}/freeradius/libfreeradius-unlang.so
%{_libdir}/freeradius/libfreeradius-vmps.so

Expand Down
39 changes: 39 additions & 0 deletions scripts/totp/totp-gen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
# Author: Jorge Pereira <jpereira@freeradius.org>
# Simple TOTP generator.

import argparse
import base64
import hmac
import struct
import sys
import time

def hotp(key, counter, digits=6, digest='sha1'):
key = key.encode('ascii')
counter = struct.pack('>Q', counter)
mac = hmac.new(key, counter, digest).digest()
offset = mac[-1] & 0x0f
binary = struct.unpack('>L', mac[offset:offset+4])[0] & 0x7fffffff
return str(binary)[-digits:].zfill(digits)

def totp(key, time_step=30, digits=6, digest='sha1'):
return hotp(key, int(time.time() / time_step), digits, digest)

def main():
parser = argparse.ArgumentParser(description = "Simple TOTP token generator.")
parser.add_argument("-k", dest = "key", help = "Key in raw format.", required = True)
parser.add_argument("-t", dest = "time_step", help = "time step between time changes.", default = 30, type = int)
parser.add_argument("-d", dest = "digits", help = "Length of the one-time password.", default = 6, type = int)
parser.add_argument("-e", dest = "encode_base32", help = "Encode the output token in base32.", action='store_true')
parser.add_argument("-D", dest = "digest", help = "HMAC algorithm as described by RFC 2104. default: sha1, options: sha1, sha256, sha512", required = False, default = "sha1")
args = parser.parse_args()
token = totp(args.key, args.time_step, args.digits, args.digest)

if args.encode_base32:
token = base64.b32encode(bytearray(token, 'ascii')).decode('ascii')

print(token)

if __name__ == '__main__':
main()
3 changes: 3 additions & 0 deletions share/dictionary/freeradius/dictionary
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ $INCLUDE dictionary.freeradius.internal.ippool
# 5200-5299 SIM management attributes
$INCLUDE dictionary.freeradius.internal.sim

# 5300-5399 TOTP related attributes
$INCLUDE dictionary.freeradius.internal.totp

#
# Include module-specific dictionaries.
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,4 @@ ATTRIBUTE SSHA3-256 28 octets
ATTRIBUTE SSHA3-384 29 octets
ATTRIBUTE SSHA3-512 30 octets

# TOTP passwords and secrets
ATTRIBUTE TOTP 31 tlv

BEGIN-TLV TOTP
ATTRIBUTE Secret 1 string secret
ATTRIBUTE Key 2 octets secret
ATTRIBUTE From-User 3 string
END-TLV TOTP

END-TLV Password
21 changes: 21 additions & 0 deletions share/dictionary/freeradius/dictionary.freeradius.internal.totp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- text -*-
# Copyright (C) 2023 The FreeRADIUS Server project and contributors
# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
# Version $Id$
#
# Non Protocol Attributes used by FreeRADIUS
#
# $Id$
#

#
# TOTP token and secrets
#

ATTRIBUTE TOTP 5300 tlv

BEGIN-TLV TOTP
ATTRIBUTE Secret 1 string secret
ATTRIBUTE Key 2 octets secret
ATTRIBUTE From-User 3 string
END-TLV TOTP
6 changes: 6 additions & 0 deletions src/lib/totp/all.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TARGETNAME := libfreeradius-totp
TARGET := $(TARGETNAME)$(L)

SOURCES := totp.c

src/freeradius-devel: | src/lib/totp/base.h
44 changes: 44 additions & 0 deletions src/lib/totp/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/

/**
* $Id$
* @file lib/totp/base.h
* @brief Common functions for TOTP library
*
* @copyright 2023 The FreeRADIUS server project
*/
RCSIDH(totp_h, "$Id$")

#include <freeradius-devel/server/request.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
uint32_t time_step; //!< seconds
uint32_t otp_length; //!< forced to 6 or 8
uint32_t lookback_steps; //!< number of steps to look back
uint32_t lookback_interval; //!< interval in seconds between steps
} fr_totp_t;

int fr_totp_cmp(fr_totp_t const *cfg, time_t now, uint8_t const *key, size_t keylen, char const *totp);

#ifdef __cplusplus
}
#endif
Loading
Loading