/** @file
  The header file of CHAP configuration.

Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#pragma once

#define ISCSI_AUTH_METHOD_CHAP  "CHAP"

#define ISCSI_KEY_CHAP_ALGORITHM   "CHAP_A"
#define ISCSI_KEY_CHAP_IDENTIFIER  "CHAP_I"
#define ISCSI_KEY_CHAP_CHALLENGE   "CHAP_C"
#define ISCSI_KEY_CHAP_NAME        "CHAP_N"
#define ISCSI_KEY_CHAP_RESPONSE    "CHAP_R"

//
// Identifiers of supported CHAP hash algorithms:
// https://www.iana.org/assignments/ppp-numbers/ppp-numbers.xhtml#ppp-numbers-9
//
#define ISCSI_CHAP_ALGORITHM_MD5     5
#define ISCSI_CHAP_ALGORITHM_SHA256  7

//
// Byte count of the largest digest over the above-listed
// ISCSI_CHAP_ALGORITHM_* hash algorithms.
//
#define ISCSI_CHAP_MAX_DIGEST_SIZE  SHA256_DIGEST_SIZE

#define ISCSI_CHAP_STEP_ONE    1
#define ISCSI_CHAP_STEP_TWO    2
#define ISCSI_CHAP_STEP_THREE  3
#define ISCSI_CHAP_STEP_FOUR   4

#pragma pack(1)

typedef struct _ISCSI_CHAP_AUTH_CONFIG_NVDATA {
  UINT8    CHAPType;
  CHAR8    CHAPName[ISCSI_CHAP_NAME_STORAGE];
  CHAR8    CHAPSecret[ISCSI_CHAP_SECRET_STORAGE];
  CHAR8    ReverseCHAPName[ISCSI_CHAP_NAME_STORAGE];
  CHAR8    ReverseCHAPSecret[ISCSI_CHAP_SECRET_STORAGE];
} ISCSI_CHAP_AUTH_CONFIG_NVDATA;

#pragma pack()

//
// Typedefs for collecting sets of hash APIs from BaseCryptLib.
//
typedef
UINTN
(EFIAPI *CHAP_HASH_GET_CONTEXT_SIZE)(
  VOID
  );

typedef
BOOLEAN
(EFIAPI *CHAP_HASH_INIT)(
  OUT VOID *Context
  );

typedef
BOOLEAN
(EFIAPI *CHAP_HASH_UPDATE)(
  IN OUT VOID       *Context,
  IN     CONST VOID *Data,
  IN     UINTN      DataSize
  );

typedef
BOOLEAN
(EFIAPI *CHAP_HASH_FINAL)(
  IN OUT VOID  *Context,
  OUT    UINT8 *HashValue
  );

typedef struct {
  UINT8                         Algorithm;   // ISCSI_CHAP_ALGORITHM_*, CHAP_A
  UINT32                        DigestSize;
  CHAP_HASH_GET_CONTEXT_SIZE    GetContextSize;
  CHAP_HASH_INIT                Init;
  CHAP_HASH_UPDATE              Update;
  CHAP_HASH_FINAL               Final;
} CHAP_HASH;

///
/// ISCSI CHAP Authentication Data
///
typedef struct _ISCSI_CHAP_AUTH_DATA {
  ISCSI_CHAP_AUTH_CONFIG_NVDATA    *AuthConfig;
  UINT32                           InIdentifier;
  UINT8                            InChallenge[1024];
  UINT32                           InChallengeLength;
  //
  // The hash algorithm (CHAP_A) that the target selects in
  // ISCSI_CHAP_STEP_TWO.
  //
  CONST CHAP_HASH                  *Hash;
  //
  // Calculated CHAP Response (CHAP_R) value.
  //
  UINT8                            CHAPResponse[ISCSI_CHAP_MAX_DIGEST_SIZE];

  //
  // Auth-data to be sent out for mutual authentication.
  //
  // While the challenge size is technically independent of the hashing
  // algorithm, it is good practice to avoid hashing *fewer bytes* than the
  // digest size. In other words, it's good practice to feed *at least as many
  // bytes* to the hashing algorithm as the hashing algorithm will output.
  //
  UINT32    OutIdentifier;
  UINT8     OutChallenge[ISCSI_CHAP_MAX_DIGEST_SIZE];
} ISCSI_CHAP_AUTH_DATA;

/**
  This function checks the received iSCSI Login Response during the security
  negotiation stage.

  @param[in] Conn             The iSCSI connection.

  @retval EFI_SUCCESS          The Login Response passed the CHAP validation.
  @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  @retval EFI_PROTOCOL_ERROR   Some kind of protocol error occurred.
  @retval Others               Other errors as indicated.

**/
EFI_STATUS
IScsiCHAPOnRspReceived (
  IN ISCSI_CONNECTION  *Conn
  );

/**
  This function fills the CHAP authentication information into the login PDU
  during the security negotiation stage in the iSCSI connection login.

  @param[in]       Conn        The iSCSI connection.
  @param[in, out]  Pdu         The PDU to send out.

  @retval EFI_SUCCESS           All check passed and the phase-related CHAP
                                authentication info is filled into the iSCSI
                                PDU.
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
  @retval EFI_PROTOCOL_ERROR    Some kind of protocol error occurred.

**/
EFI_STATUS
IScsiCHAPToSendReq (
  IN      ISCSI_CONNECTION  *Conn,
  IN OUT  NET_BUF           *Pdu
  );

/**
  Initialize the CHAP_A=<A1,A2...> *value* string for the entire driver, to be
  sent by the initiator in ISCSI_CHAP_STEP_ONE.

  This function sanity-checks the internal table of supported CHAP hashing
  algorithms, as well.
**/
VOID
IScsiCHAPInitHashList (
  VOID
  );
