summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/IScsiDxe/IScsiCHAP.c
diff options
context:
space:
mode:
Diffstat (limited to 'NetworkPkg/IScsiDxe/IScsiCHAP.c')
-rw-r--r--NetworkPkg/IScsiDxe/IScsiCHAP.c170
1 files changed, 147 insertions, 23 deletions
diff --git a/NetworkPkg/IScsiDxe/IScsiCHAP.c b/NetworkPkg/IScsiDxe/IScsiCHAP.c
index 744824e63d..351bf329b7 100644
--- a/NetworkPkg/IScsiDxe/IScsiCHAP.c
+++ b/NetworkPkg/IScsiDxe/IScsiCHAP.c
@@ -9,6 +9,39 @@ 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.
@@ -17,6 +50,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
@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
@@ -24,8 +61,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
@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
@@ -35,11 +73,12 @@ IScsiCHAPCalculateResponse (
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;
@@ -47,15 +86,17 @@ IScsiCHAPCalculateResponse (
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;
}
@@ -63,30 +104,30 @@ IScsiCHAPCalculateResponse (
// 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;
}
@@ -113,20 +154,30 @@ IScsiCHAPAuthTarget (
EFI_STATUS Status;
UINT32 SecretSize;
UINT8 VerifyRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];
+ INTN Mismatch;
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) {
+ Mismatch = CompareMem (
+ VerifyRsp,
+ TargetResponse,
+ AuthData->Hash->DigestSize
+ );
+ if (Mismatch != 0) {
Status = EFI_SECURITY_VIOLATION;
}
@@ -166,6 +217,7 @@ IScsiCHAPOnRspReceived (
UINT8 TargetRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];
UINT32 RspLen;
UINTN Result;
+ UINTN HashIndex;
ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);
ASSERT (Conn->RspQue.BufNum != 0);
@@ -257,12 +309,22 @@ IScsiCHAPOnRspReceived (
}
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,
@@ -305,6 +367,7 @@ IScsiCHAPOnRspReceived (
(UINT32) AsciiStrLen (AuthData->AuthConfig->CHAPSecret),
AuthData->InChallenge,
AuthData->InChallengeLength,
+ AuthData->Hash,
AuthData->CHAPResponse
);
@@ -340,9 +403,10 @@ IScsiCHAPOnRspReceived (
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;
}
@@ -458,8 +522,7 @@ IScsiCHAPToSendReq (
// 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;
@@ -480,9 +543,10 @@ IScsiCHAPToSendReq (
//
// CHAP_R=<R>
//
+ ASSERT (AuthData->Hash != NULL);
BinToHexStatus = IScsiBinToHex (
(UINT8 *) AuthData->CHAPResponse,
- MD5_DIGEST_SIZE,
+ AuthData->Hash->DigestSize,
Response,
&RspLen
);
@@ -499,10 +563,13 @@ IScsiCHAPToSendReq (
//
// 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
);
@@ -527,3 +594,60 @@ IScsiCHAPToSendReq (
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);
+ }
+}