[PATCH 4/6] NetworkPkg/IScsiDxe: support multiple hash algorithms for CHAP


Laszlo Ersek
 

Introduce the "mChapHash" table, containing the hash algorithms supported
for CHAP. Hash algos listed at the beginning of the table are preferred by
the initiator.

In ISCSI_CHAP_STEP_ONE, send such a CHAP_A value that is the
comma-separated, ordered list of algorithm identifiers from "mChapHash".
Pre-format this value string at driver startup, in the new function
IScsiCHAPInitHashList().

(In IScsiCHAPInitHashList(), also enforce that every hash algo's digest
size fit into ISCSI_CHAP_MAX_DIGEST_SIZE, as the latter controls the
digest, outgoing challenge, and hex *allocations*.)

In ISCSI_CHAP_STEP_TWO, allow the target to select one of the offered hash
algorithms, and remember the selection for the later steps. For
ISCSI_CHAP_STEP_THREE, hash the challenge from the target with the
selected hash algo.

In ISCSI_CHAP_STEP_THREE, send the correctly sized digest to the target.
If the initiator wants mutual authentication, then generate a challenge
with as many bytes as the target's digest will have, in
ISCSI_CHAP_STEP_FOUR.

In ISCSI_CHAP_STEP_FOUR (i.e., when mutual authentication is required by
the initiator), verify the target's response (digest) with the selected
algorithm.

Clear the selected hash algorithm before every login (remember that in
IScsiDxe, every login is a leading login).

There is no peer-observable change from this patch, as it only reworks the
current MD5 support into the new internal representation.

Cc: Jiaxin Wu <jiaxin.wu@intel.com>
Cc: Maciej Rabeda <maciej.rabeda@linux.intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3355
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
NetworkPkg/IScsiDxe/IScsiCHAP.h | 55 +++++++
NetworkPkg/IScsiDxe/IScsiCHAP.c | 158 +++++++++++++++++---
NetworkPkg/IScsiDxe/IScsiDriver.c | 2 +
NetworkPkg/IScsiDxe/IScsiProto.c | 3 +
4 files changed, 195 insertions(+), 23 deletions(-)

diff --git a/NetworkPkg/IScsiDxe/IScsiCHAP.h b/NetworkPkg/IScsiDxe/IScsiCHAP.h
index b8811b7580f0..1e5cc0b287ed 100644
--- a/NetworkPkg/IScsiDxe/IScsiCHAP.h
+++ b/NetworkPkg/IScsiDxe/IScsiCHAP.h
@@ -31,47 +31,91 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#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.
@@ -92,20 +136,31 @@ IScsiCHAPOnRspReceived (
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
+ );
#endif
diff --git a/NetworkPkg/IScsiDxe/IScsiCHAP.c b/NetworkPkg/IScsiDxe/IScsiCHAP.c
index 744824e63d23..f02ada6444ce 100644
--- a/NetworkPkg/IScsiDxe/IScsiCHAP.c
+++ b/NetworkPkg/IScsiDxe/IScsiCHAP.c
@@ -1,148 +1,194 @@
/** @file
This file is for Challenge-Handshake Authentication Protocol (CHAP)
Configuration.

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

**/

#include "IScsiImpl.h"

+//
+// Supported CHAP hash algorithms, mapped to sets of BaseCryptLib APIs and
+// macros. CHAP_HASH structures at lower subscripts in the array are preferred
+// by the initiator.
+//
+STATIC CONST CHAP_HASH mChapHash[] = {
+ {
+ ISCSI_CHAP_ALGORITHM_MD5,
+ MD5_DIGEST_SIZE,
+ Md5GetContextSize,
+ Md5Init,
+ Md5Update,
+ Md5Final
+ },
+};
+
+//
+// Ordered list of mChapHash[*].Algorithm values. It is formatted for the
+// CHAP_A=<A1,A2...> value string, by the IScsiCHAPInitHashList() function. It
+// is sent by the initiator in ISCSI_CHAP_STEP_ONE.
+//
+STATIC CHAR8 mChapHashListString[
+ 3 + // UINT8 identifier in
+ // decimal
+ (1 + 3) * (ARRAY_SIZE (mChapHash) - 1) + // comma prepended for
+ // entries after the
+ // first
+ 1 + // extra character for
+ // AsciiSPrint()
+ // truncation check
+ 1 // terminating NUL
+ ];
+
/**
Initiator calculates its own expected hash value.

@param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.
@param[in] ChapSecret iSCSI CHAP secret of the authenticator.
@param[in] SecretLength The length of iSCSI CHAP secret.
@param[in] ChapChallenge The challenge message sent by authenticator.
@param[in] ChallengeLength The length of iSCSI CHAP challenge message.
+ @param[in] Hash Pointer to the CHAP_HASH structure that
+ determines the hashing algorithm to use. The
+ caller is responsible for making Hash point
+ to an "mChapHash" element.
@param[out] ChapResponse The calculation of the expected hash value.

@retval EFI_SUCCESS The expected hash value was calculatedly
successfully.
@retval EFI_PROTOCOL_ERROR The length of the secret should be at least
the length of the hash value for the hashing
algorithm chosen.
- @retval EFI_PROTOCOL_ERROR MD5 hash operation fail.
- @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete MD5.
+ @retval EFI_PROTOCOL_ERROR Hash operation fails.
+ @retval EFI_OUT_OF_RESOURCES Failure to allocate resource to complete
+ hashing.

**/
EFI_STATUS
IScsiCHAPCalculateResponse (
IN UINT32 ChapIdentifier,
IN CHAR8 *ChapSecret,
IN UINT32 SecretLength,
IN UINT8 *ChapChallenge,
IN UINT32 ChallengeLength,
+ IN CONST CHAP_HASH *Hash,
OUT UINT8 *ChapResponse
)
{
- UINTN Md5ContextSize;
- VOID *Md5Ctx;
+ UINTN ContextSize;
+ VOID *Ctx;
CHAR8 IdByte[1];
EFI_STATUS Status;

if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN) {
return EFI_PROTOCOL_ERROR;
}

- Md5ContextSize = Md5GetContextSize ();
- Md5Ctx = AllocatePool (Md5ContextSize);
- if (Md5Ctx == NULL) {
+ ASSERT (Hash != NULL);
+
+ ContextSize = Hash->GetContextSize ();
+ Ctx = AllocatePool (ContextSize);
+ if (Ctx == NULL) {
return EFI_OUT_OF_RESOURCES;
}

Status = EFI_PROTOCOL_ERROR;

- if (!Md5Init (Md5Ctx)) {
+ if (!Hash->Init (Ctx)) {
goto Exit;
}

//
// Hash Identifier - Only calculate 1 byte data (RFC1994)
//
IdByte[0] = (CHAR8) ChapIdentifier;
- if (!Md5Update (Md5Ctx, IdByte, 1)) {
+ if (!Hash->Update (Ctx, IdByte, 1)) {
goto Exit;
}

//
// Hash Secret
//
- if (!Md5Update (Md5Ctx, ChapSecret, SecretLength)) {
+ if (!Hash->Update (Ctx, ChapSecret, SecretLength)) {
goto Exit;
}

//
// Hash Challenge received from Target
//
- if (!Md5Update (Md5Ctx, ChapChallenge, ChallengeLength)) {
+ if (!Hash->Update (Ctx, ChapChallenge, ChallengeLength)) {
goto Exit;
}

- if (Md5Final (Md5Ctx, ChapResponse)) {
+ if (Hash->Final (Ctx, ChapResponse)) {
Status = EFI_SUCCESS;
}

Exit:
- FreePool (Md5Ctx);
+ FreePool (Ctx);
return Status;
}

/**
The initiator checks the CHAP response replied by target against its own
calculation of the expected hash value.

@param[in] AuthData iSCSI CHAP authentication data.
@param[in] TargetResponse The response from target.

@retval EFI_SUCCESS The response from target passed
authentication.
@retval EFI_SECURITY_VIOLATION The response from target was not expected
value.
@retval Others Other errors as indicated.

**/
EFI_STATUS
IScsiCHAPAuthTarget (
IN ISCSI_CHAP_AUTH_DATA *AuthData,
IN UINT8 *TargetResponse
)
{
EFI_STATUS Status;
UINT32 SecretSize;
UINT8 VerifyRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];

Status = EFI_SUCCESS;

SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret);
+
+ ASSERT (AuthData->Hash != NULL);
+
Status = IScsiCHAPCalculateResponse (
AuthData->OutIdentifier,
AuthData->AuthConfig->ReverseCHAPSecret,
SecretSize,
AuthData->OutChallenge,
- MD5_DIGEST_SIZE, // ChallengeLength
+ AuthData->Hash->DigestSize, // ChallengeLength
+ AuthData->Hash,
VerifyRsp
);

- if (CompareMem (VerifyRsp, TargetResponse, MD5_DIGEST_SIZE) != 0) {
+ if (CompareMem (VerifyRsp, TargetResponse,
+ AuthData->Hash->DigestSize) != 0) {
Status = EFI_SECURITY_VIOLATION;
}

return Status;
}


/**
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.

**/
@@ -150,38 +196,39 @@ EFI_STATUS
IScsiCHAPOnRspReceived (
IN ISCSI_CONNECTION *Conn
)
{
EFI_STATUS Status;
ISCSI_SESSION *Session;
ISCSI_CHAP_AUTH_DATA *AuthData;
CHAR8 *Value;
UINT8 *Data;
UINT32 Len;
LIST_ENTRY *KeyValueList;
UINTN Algorithm;
CHAR8 *Identifier;
CHAR8 *Challenge;
CHAR8 *Name;
CHAR8 *Response;
UINT8 TargetRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];
UINT32 RspLen;
UINTN Result;
+ UINTN HashIndex;

ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);
ASSERT (Conn->RspQue.BufNum != 0);

Session = Conn->Session;
AuthData = &Session->AuthData.CHAP;
Len = Conn->RspQue.BufSize;
Data = AllocateZeroPool (Len);
if (Data == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Copy the data in case the data spans over multiple PDUs.
//
NetbufQueCopy (&Conn->RspQue, 0, Len, Data);

//
// Build the key-value list from the data segment of the Login Response.
//
@@ -241,44 +288,54 @@ IScsiCHAPOnRspReceived (
// Transit to CHAP step one.
//
Conn->AuthStep = ISCSI_CHAP_STEP_ONE;
Status = EFI_SUCCESS;
break;

case ISCSI_CHAP_STEP_TWO:
//
// The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
//
Value = IScsiGetValueByKeyFromList (
KeyValueList,
ISCSI_KEY_CHAP_ALGORITHM
);
if (Value == NULL) {
goto ON_EXIT;
}

Algorithm = IScsiNetNtoi (Value);
- if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {
+ for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {
+ if (Algorithm == mChapHash[HashIndex].Algorithm) {
+ break;
+ }
+ }
+ if (HashIndex == ARRAY_SIZE (mChapHash)) {
//
// Unsupported algorithm is chosen by target.
//
goto ON_EXIT;
}
+ //
+ // Remember the target's chosen hash algorithm.
+ //
+ ASSERT (AuthData->Hash == NULL);
+ AuthData->Hash = &mChapHash[HashIndex];

Identifier = IScsiGetValueByKeyFromList (
KeyValueList,
ISCSI_KEY_CHAP_IDENTIFIER
);
if (Identifier == NULL) {
goto ON_EXIT;
}

Challenge = IScsiGetValueByKeyFromList (
KeyValueList,
ISCSI_KEY_CHAP_CHALLENGE
);
if (Challenge == NULL) {
goto ON_EXIT;
}
//
// Process the CHAP identifier and CHAP Challenge from Target.
// Calculate Response value.
@@ -289,76 +346,78 @@ IScsiCHAPOnRspReceived (
}

AuthData->InIdentifier = (UINT32) Result;
AuthData->InChallengeLength = (UINT32) sizeof (AuthData->InChallenge);
Status = IScsiHexToBin (
(UINT8 *) AuthData->InChallenge,
&AuthData->InChallengeLength,
Challenge
);
if (EFI_ERROR (Status)) {
Status = EFI_PROTOCOL_ERROR;
goto ON_EXIT;
}
Status = IScsiCHAPCalculateResponse (
AuthData->InIdentifier,
AuthData->AuthConfig->CHAPSecret,
(UINT32) AsciiStrLen (AuthData->AuthConfig->CHAPSecret),
AuthData->InChallenge,
AuthData->InChallengeLength,
+ AuthData->Hash,
AuthData->CHAPResponse
);

//
// Transit to next step.
//
Conn->AuthStep = ISCSI_CHAP_STEP_THREE;
break;

case ISCSI_CHAP_STEP_THREE:
//
// One way CHAP authentication and the target would like to
// authenticate us.
//
Status = EFI_SUCCESS;
break;

case ISCSI_CHAP_STEP_FOUR:
ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);
//
// The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
//
Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);
if (Name == NULL) {
goto ON_EXIT;
}

Response = IScsiGetValueByKeyFromList (
KeyValueList,
ISCSI_KEY_CHAP_RESPONSE
);
if (Response == NULL) {
goto ON_EXIT;
}

- RspLen = MD5_DIGEST_SIZE;
+ ASSERT (AuthData->Hash != NULL);
+ RspLen = AuthData->Hash->DigestSize;
Status = IScsiHexToBin (TargetRsp, &RspLen, Response);
- if (EFI_ERROR (Status) || RspLen != MD5_DIGEST_SIZE) {
+ if (EFI_ERROR (Status) || RspLen != AuthData->Hash->DigestSize) {
Status = EFI_PROTOCOL_ERROR;
goto ON_EXIT;
}

//
// Check the CHAP Name and Response replied by Target.
//
Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);
break;

default:
break;
}

ON_EXIT:

if (KeyValueList != NULL) {
IScsiFreeKeyValueList (KeyValueList);
}
@@ -442,88 +501,141 @@ IScsiCHAPToSendReq (
Session->ConfigData->SessionConfigData.TargetName
);

if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {
Value = ISCSI_KEY_VALUE_NONE;
ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
} else {
Value = ISCSI_AUTH_METHOD_CHAP;
}

IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);

break;

case ISCSI_CHAP_STEP_ONE:
//
// First step, send the Login Request with CHAP_A=<A1,A2...> key-value
// pair.
//
- AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);
- IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, mChapHashListString);

Conn->AuthStep = ISCSI_CHAP_STEP_TWO;
break;

case ISCSI_CHAP_STEP_THREE:
//
// Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
// CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is
// required too.
//
// CHAP_N=<N>
//
IScsiAddKeyValuePair (
Pdu,
ISCSI_KEY_CHAP_NAME,
(CHAR8 *) &AuthData->AuthConfig->CHAPName
);
//
// CHAP_R=<R>
//
+ ASSERT (AuthData->Hash != NULL);
BinToHexStatus = IScsiBinToHex (
(UINT8 *) AuthData->CHAPResponse,
- MD5_DIGEST_SIZE,
+ AuthData->Hash->DigestSize,
Response,
&RspLen
);
ASSERT_EFI_ERROR (BinToHexStatus);
IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);

if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {
//
// CHAP_I=<I>
//
IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);
AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);
IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);
//
// CHAP_C=<C>
//
- IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, MD5_DIGEST_SIZE);
+ IScsiGenRandom ((UINT8 *) AuthData->OutChallenge,
+ AuthData->Hash->DigestSize);
BinToHexStatus = IScsiBinToHex (
(UINT8 *) AuthData->OutChallenge,
- MD5_DIGEST_SIZE,
+ AuthData->Hash->DigestSize,
Challenge,
&ChallengeLen
);
ASSERT_EFI_ERROR (BinToHexStatus);
IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);

Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;
}
//
// Set the stage transition flag.
//
ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
break;

default:
Status = EFI_PROTOCOL_ERROR;
break;
}

FreePool (Response);
FreePool (Challenge);

return Status;
}
+
+/**
+ 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
+ )
+{
+ CHAR8 *Position;
+ UINTN Left;
+ UINTN HashIndex;
+ CONST CHAP_HASH *Hash;
+ UINTN Printed;
+
+ Position = mChapHashListString;
+ Left = sizeof (mChapHashListString);
+ for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {
+ Hash = &mChapHash[HashIndex];
+
+ //
+ // Format the next hash identifier.
+ //
+ // Assert that we can format at least one non-NUL character, i.e. that we
+ // can progress. Truncation is checked after printing.
+ //
+ ASSERT (Left >= 2);
+ Printed = AsciiSPrint (Position, Left, "%a%d", (HashIndex == 0) ? "" : ",",
+ Hash->Algorithm);
+ //
+ // There's no way to differentiate between the "buffer filled to the brim,
+ // but not truncated" result and the "truncated" result of AsciiSPrint().
+ // This is why "mChapHashListString" has an extra byte allocated, and the
+ // reason why we use the less-than (rather than the less-than-or-equal-to)
+ // relational operator in the assertion below -- we enforce "no truncation"
+ // by excluding the "completely used up" case too.
+ //
+ ASSERT (Printed + 1 < Left);
+
+ Position += Printed;
+ Left -= Printed;
+
+ //
+ // Sanity-check the digest size for Hash.
+ //
+ ASSERT (Hash->DigestSize <= ISCSI_CHAP_MAX_DIGEST_SIZE);
+ }
+}
diff --git a/NetworkPkg/IScsiDxe/IScsiDriver.c b/NetworkPkg/IScsiDxe/IScsiDriver.c
index 98b73308c118..485c92972113 100644
--- a/NetworkPkg/IScsiDxe/IScsiDriver.c
+++ b/NetworkPkg/IScsiDxe/IScsiDriver.c
@@ -1763,38 +1763,40 @@ IScsiDriverEntryPoint (
goto Error1;
}

//
// Install the iSCSI Initiator Name Protocol.
//
Status = gBS->InstallProtocolInterface (
&ImageHandle,
&gEfiIScsiInitiatorNameProtocolGuid,
EFI_NATIVE_INTERFACE,
&gIScsiInitiatorName
);
if (EFI_ERROR (Status)) {
goto Error2;
}

//
// Create the private data structures.
//
+ IScsiCHAPInitHashList ();
+
mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));
if (mPrivate == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error3;
}

InitializeListHead (&mPrivate->NicInfoList);
InitializeListHead (&mPrivate->AttemptConfigs);

//
// Initialize the configuration form of iSCSI.
//
Status = IScsiConfigFormInit (gIScsiIp4DriverBinding.DriverBindingHandle);
if (EFI_ERROR (Status)) {
goto Error4;
}

//
// Create the Maximum Attempts.
diff --git a/NetworkPkg/IScsiDxe/IScsiProto.c b/NetworkPkg/IScsiDxe/IScsiProto.c
index 69d1b39dbb1f..e62736bc041f 100644
--- a/NetworkPkg/IScsiDxe/IScsiProto.c
+++ b/NetworkPkg/IScsiDxe/IScsiProto.c
@@ -416,38 +416,41 @@ IScsiGetIp6NicInfo (

return Status;
}

/**
Re-set any stateful session-level authentication information that is used by
the leading login / leading connection.

(Note that this driver only supports a single connection per session -- see
ISCSI_MAX_CONNS_PER_SESSION.)

@param[in,out] Session The iSCSI session.
**/
STATIC
VOID
IScsiSessionResetAuthData (
IN OUT ISCSI_SESSION *Session
)
{
+ if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {
+ Session->AuthData.CHAP.Hash = NULL;
+ }
}

/**
Login the iSCSI session.

@param[in] Session The iSCSI session.

@retval EFI_SUCCESS The iSCSI session login procedure finished.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
@retval EFI_NO_MEDIA There was a media error.
@retval Others Other errors as indicated.

**/
EFI_STATUS
IScsiSessionLogin (
IN ISCSI_SESSION *Session
)
{
EFI_STATUS Status;
--
2.19.1.3.g30247aa5d201

Join devel@edk2.groups.io to automatically receive all group messages.