/*
 * oath.h - header file for liboath
 * Copyright (C) 2009-2021 Simon Josefsson
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */


/**
 * SECTION:oath
 * @title: oath.h
 * @short_description: liboath declarations
 *
 * The oath.h file contains declarations for the liboath library.
 */

#ifndef OATH_H
#define OATH_H

/**
 * OATHAPI:
 *
 * Symbol holding shared library API visibility decorator.
 *
 * This is used internally by the library header file and should never
 * be used or modified by the application.
 *
 * https://www.gnu.org/software/gnulib/manual/html_node/Exported-Symbols-of-Shared-Libraries.html
 */
#ifndef OATHAPI
# if defined LIBOATH_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
#  define OATHAPI __attribute__((__visibility__("default")))
# elif defined LIBOATH_BUILDING && defined _MSC_VER && ! defined LIBOATH_STATIC
#  define OATHAPI __declspec(dllexport)
# elif defined _MSC_VER && ! defined LIBOATH_STATIC
#  define OATHAPI __declspec(dllimport)
# else
#  define OATHAPI
# endif
#endif

#include <stdbool.h>		/* For bool. */
#include <stdint.h>		/* For uint64_t, SIZE_MAX. */
#include <string.h>		/* For size_t.t */
#include <time.h>		/* For time_t. */

# ifdef __cplusplus
extern "C"
{
# endif

/**
 * OATH_VERSION
 *
 * Pre-processor symbol with a string that describe the header file
 * version number.  Used together with oath_check_version() to verify
 * header file and run-time library consistency.
 */
#define OATH_VERSION "2.6.7"

/**
 * OATH_VERSION_NUMBER
 *
 * Pre-processor symbol with a hexadecimal value describing the header
 * file version number.  For example, when the header version is 1.2.3
 * this symbol will have the value 0x01020300.  The last two digits
 * are only used between public releases, and will otherwise be 00.
 */
#define OATH_VERSION_NUMBER 0x02060200

/**
 * oath_rc:
 * @OATH_OK: Successful return
 * @OATH_CRYPTO_ERROR: Internal error in crypto functions
 * @OATH_INVALID_DIGITS: Unsupported number of OTP digits
 * @OATH_PRINTF_ERROR: Error from system printf call
 * @OATH_INVALID_HEX: Hex string is invalid
 * @OATH_TOO_SMALL_BUFFER: The output buffer is too small
 * @OATH_INVALID_OTP: The OTP is not valid
 * @OATH_REPLAYED_OTP: The OTP has been replayed
 * @OATH_BAD_PASSWORD: The password does not match
 * @OATH_INVALID_COUNTER: The counter value is corrupt
 * @OATH_INVALID_TIMESTAMP: The timestamp is corrupt
 * @OATH_NO_SUCH_FILE: The supplied filename does not exist
 * @OATH_UNKNOWN_USER: Cannot find information about user
 * @OATH_FILE_SEEK_ERROR: System error when seeking in file
 * @OATH_FILE_CREATE_ERROR: System error when creating file
 * @OATH_FILE_LOCK_ERROR: System error when locking file
 * @OATH_FILE_RENAME_ERROR: System error when renaming file
 * @OATH_FILE_UNLINK_ERROR: System error when removing file
 * @OATH_TIME_ERROR: System error for time manipulation
 * @OATH_STRCMP_ERROR: A strcmp callback returned an error
 * @OATH_INVALID_BASE32: Base32 string is invalid
 * @OATH_BASE32_OVERFLOW: Base32 encoding would overflow
 * @OATH_MALLOC_ERROR: Memory allocation failed
 * @OATH_FILE_FLUSH_ERROR: System error when flushing file buffer
 * @OATH_FILE_SYNC_ERROR: System error when syncing file to disk
 * @OATH_FILE_CLOSE_ERROR: System error when closing file
 * @OATH_FILE_CHOWN_ERROR: System error when changing file ownership
 * @OATH_FILE_STAT_ERROR: System error when getting file status
 * @OATH_LAST_ERROR: Meta-error indicating the last error code, for use
 *   when iterating over all error codes or similar.
 *
 * Return codes for OATH functions.  All return codes are negative
 * except for the successful code %OATH_OK which are guaranteed to be
 * 0.  Positive values are reserved for non-error return codes.
 *
 * Note that the #oath_rc enumeration may be extended at a later date
 * to include new return codes.
 */
typedef enum
{
  OATH_OK = 0,
  OATH_CRYPTO_ERROR = -1,
  OATH_INVALID_DIGITS = -2,
  OATH_PRINTF_ERROR = -3,
  OATH_INVALID_HEX = -4,
  OATH_TOO_SMALL_BUFFER = -5,
  OATH_INVALID_OTP = -6,
  OATH_REPLAYED_OTP = -7,
  OATH_BAD_PASSWORD = -8,
  OATH_INVALID_COUNTER = -9,
  OATH_INVALID_TIMESTAMP = -10,
  OATH_NO_SUCH_FILE = -11,
  OATH_UNKNOWN_USER = -12,
  OATH_FILE_SEEK_ERROR = -13,
  OATH_FILE_CREATE_ERROR = -14,
  OATH_FILE_LOCK_ERROR = -15,
  OATH_FILE_RENAME_ERROR = -16,
  OATH_FILE_UNLINK_ERROR = -17,
  OATH_TIME_ERROR = -18,
  OATH_STRCMP_ERROR = -19,
  OATH_INVALID_BASE32 = -20,
  OATH_BASE32_OVERFLOW = -21,
  OATH_MALLOC_ERROR = -22,
  OATH_FILE_FLUSH_ERROR = -23,
  OATH_FILE_SYNC_ERROR = -24,
  OATH_FILE_CLOSE_ERROR = -25,
  OATH_FILE_CHOWN_ERROR = -26,
  OATH_FILE_STAT_ERROR = -27,
  /* When adding anything here, update OATH_LAST_ERROR, errors.c
     and tests/tst_errors.c. */
  OATH_LAST_ERROR = -27
} oath_rc;

/* Global */

extern OATHAPI int oath_init (void);
extern OATHAPI int oath_done (void);

extern OATHAPI const char *oath_check_version (const char *req_version);

/* Error handling */

extern OATHAPI const char *oath_strerror (int err);
extern OATHAPI const char *oath_strerror_name (int err);

/* Data encoding */

extern OATHAPI int oath_hex2bin (const char *hexstr,
				 char *binstr, size_t * binlen);
extern OATHAPI void oath_bin2hex (const char *binstr, size_t binlen,
				  char *hexstr);

extern OATHAPI int oath_base32_decode (const char *in, size_t inlen,
				       char **out, size_t *outlen);
extern OATHAPI int oath_base32_encode (const char *in, size_t inlen,
				       char **out, size_t *outlen);

/* HOTP */

/**
 * OATH_HOTP_LENGTH:
 * @digits: number of requested digits in the OTP, excluding checksum
 * @checksum: whether to add a checksum digit or not
 *
 * Pre-processor macro to get length of a OTP string.
 *
 * Returns: Length of generated one-time password.
 **/
#define OATH_HOTP_LENGTH(digits, checksum) (digits + (checksum ? 1 : 0))

/**
 * OATH_HOTP_DYNAMIC_TRUNCATION:
 *
 * Pre-processor symbol to indicate that no HOTP truncation should
 * occur, see oath_hotp_generate().
 */
#define OATH_HOTP_DYNAMIC_TRUNCATION SIZE_MAX

extern OATHAPI int
oath_hotp_generate (const char *secret,
		    size_t secret_length,
		    uint64_t moving_factor,
		    unsigned digits,
		    bool add_checksum,
		    size_t truncation_offset,
		    char *output_otp);


extern OATHAPI int
oath_hotp_validate (const char *secret,
		    size_t secret_length,
		    uint64_t start_moving_factor,
		    size_t window, const char *otp);

/**
 * oath_validate_strcmp_function:
 * @handle: caller handle as passed to oath_hotp_validate_callback()
 * @test_otp: OTP to match against.
 *
 * Prototype of strcmp-like function that will be called by
 * oath_hotp_validate_callback() or oath_totp_validate_callback() to
 * validate OTPs.
 *
 * The function should be similar to strcmp in that it return 0 only
 * on matches.  It differs by permitting use of negative return codes
 * as indication of internal failures in the callback.  Positive
 * values indicate OTP mismatch.
 *
 * This callback interface is useful when you cannot compare OTPs
 * directly using normal strcmp, but instead for example only have a
 * hashed OTP.  You would then typically pass in the hashed OTP in the
 * @strcmp_handle and let your implementation of @oath_strcmp hash the
 * test_otp OTP using the same hash, and then compare the results.
 *
 * Return value: 0 if and only if @test_otp is identical to the OTP to
 *   be validated.  Negative value if an internal failure occurs.
 *   Positive value if the test_otp simply doesn't match.
 *
 * Since: 1.6.0
 **/
typedef int (*oath_validate_strcmp_function) (void *handle,
					      const char *test_otp);

/**
 * oath_hotp_validate_strcmp_function:
 *
 * Pre-processor compatibility definition for
 * oath_validate_strcmp_function().
 *
 * Since: 1.4.0
 */
#define oath_hotp_validate_strcmp_function oath_validate_strcmp_function

extern OATHAPI int
oath_hotp_validate_callback (const char *secret,
			     size_t secret_length,
			     uint64_t start_moving_factor,
			     size_t window,
			     unsigned digits,
			     oath_validate_strcmp_function strcmp_otp,
			     void *strcmp_handle);

/* TOTP */

/**
 * OATH_TOTP_DEFAULT_TIME_STEP_SIZE:
 *
 * Pre-processor symbol to provide a default value for the TOTP
 * time-step value, see oath_totp_generate().
 */
#define OATH_TOTP_DEFAULT_TIME_STEP_SIZE	30

/**
 * OATH_TOTP_DEFAULT_START_TIME:
 *
 * Pre-processor symbol to indicate that you want to use the Unix
 * epoch as a starting pointer for TOTP, see oath_totp_generate().
 */
#define OATH_TOTP_DEFAULT_START_TIME		((time_t) 0)

/**
 * oath_totp_flags:
 * @OATH_TOTP_HMAC_SHA256: Use HMAC-SHA256 instead of HMAC-SHA1.
 * @OATH_TOTP_HMAC_SHA512: Use HMAC-SHA512 instead of HMAC-SHA1.
 *
 * Flags for oath_totp_generate2().
 *
 * Since: 2.6.0
 */
typedef enum {
  OATH_TOTP_HMAC_SHA256 = 1,
  OATH_TOTP_HMAC_SHA512 = 2
} oath_totp_flags;

extern OATHAPI int
oath_totp_generate (const char *secret,
		    size_t secret_length,
		    time_t now,
		    unsigned time_step_size,
		    time_t start_offset,
		    unsigned digits, char *output_otp);

extern OATHAPI int
oath_totp_generate2 (const char *secret,
		     size_t secret_length,
		     time_t now,
		     unsigned time_step_size,
		     time_t start_offset,
		     unsigned digits,
		     int flags,
		     char *output_otp);

extern OATHAPI int
oath_totp_validate (const char *secret,
		    size_t secret_length,
		    time_t now,
		    unsigned time_step_size,
		    time_t start_offset,
		    size_t window, const char *otp);

extern OATHAPI int
oath_totp_validate_callback (const char *secret,
			     size_t secret_length,
			     time_t now,
			     unsigned time_step_size,
			     time_t start_offset,
			     unsigned digits,
			     size_t window,
			     oath_validate_strcmp_function strcmp_otp,
			     void *strcmp_handle);

extern OATHAPI int
oath_totp_validate2 (const char *secret,
		     size_t secret_length,
		     time_t now,
		     unsigned time_step_size,
		     time_t start_offset,
		     size_t window,
		     int *otp_pos,
		     const char *otp);

extern OATHAPI int
oath_totp_validate2_callback (const char *secret,
			      size_t secret_length,
			      time_t now,
			      unsigned time_step_size,
			      time_t start_offset,
			      unsigned digits,
			      size_t window,
			      int *otp_pos,
			      oath_validate_strcmp_function strcmp_otp,
			      void *strcmp_handle);

extern OATHAPI int
oath_totp_validate3 (const char *secret,
		     size_t secret_length,
		     time_t now,
		     unsigned time_step_size,
		     time_t start_offset,
		     size_t window,
		     int *otp_pos,
		     uint64_t *otp_counter,
		     const char *otp);

extern OATHAPI int
oath_totp_validate3_callback (const char *secret,
			      size_t secret_length,
			      time_t now,
			      unsigned time_step_size,
			      time_t start_offset,
			      unsigned digits,
			      size_t window,
			      int *otp_pos,
			      uint64_t *otp_counter,
			      oath_validate_strcmp_function strcmp_otp,
			      void *strcmp_handle);

extern OATHAPI int
oath_totp_validate4 (const char *secret,
		     size_t secret_length,
		     time_t now,
		     unsigned time_step_size,
		     time_t start_offset,
		     size_t window,
		     int *otp_pos,
		     uint64_t *otp_counter,
		     int flags,
		     const char *otp);

extern OATHAPI int
oath_totp_validate4_callback (const char *secret,
			      size_t secret_length,
			      time_t now,
			      unsigned time_step_size,
			      time_t start_offset,
			      unsigned digits,
			      size_t window,
			      int *otp_pos,
			      uint64_t *otp_counter,
			      int flags,
			      oath_validate_strcmp_function strcmp_otp,
			      void *strcmp_handle);

/* Usersfile */

extern OATHAPI int
oath_authenticate_usersfile (const char *usersfile,
			     const char *username,
			     const char *otp,
			     size_t window,
			     const char *passwd,
			     time_t * last_otp);

# ifdef __cplusplus
}
# endif

#endif /* OATH_H */
