From eb90c439566cad8ee71d530d8dcd78b1300e0719 Mon Sep 17 00:00:00 2001
From: Doug Flick <dougflick@microsoft.com>
Date: Wed, 8 May 2024 22:56:29 -0700
Subject: [PATCH 2/2] NetworkPkg TcpDxe: SECURITY PATCH CVE-2023-45236

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4541
REF: https://www.rfc-editor.org/rfc/rfc1948.txt
REF: https://www.rfc-editor.org/rfc/rfc6528.txt
REF: https://www.rfc-editor.org/rfc/rfc9293.txt

Bug Overview:
PixieFail Bug #8
CVE-2023-45236
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N
CWE-200 Exposure of Sensitive Information to an Unauthorized Actor

Updates TCP ISN generation to use a cryptographic hash of the
connection's identifying parameters and a secret key.
This prevents an attacker from guessing the ISN used for some other
connection.

This is follows the guidance in RFC 1948, RFC 6528, and RFC 9293.

RFC: 9293 Section 3.4.1.  Initial Sequence Number Selection

   A TCP implementation MUST use the above type of "clock" for clock-
   driven selection of initial sequence numbers (MUST-8), and SHOULD
   generate its initial sequence numbers with the expression:

   ISN = M + F(localip, localport, remoteip, remoteport, secretkey)

   where M is the 4 microsecond timer, and F() is a pseudorandom
   function (PRF) of the connection's identifying parameters ("localip,
   localport, remoteip, remoteport") and a secret key ("secretkey")
   (SHLD-1).  F() MUST NOT be computable from the outside (MUST-9), or
   an attacker could still guess at sequence numbers from the ISN used
   for some other connection.  The PRF could be implemented as a
   cryptographic hash of the concatenation of the TCP connection
   parameters and some secret data.  For discussion of the selection of
   a specific hash algorithm and management of the secret key data,
   please see Section 3 of [42].

   For each connection there is a send sequence number and a receive
   sequence number.  The initial send sequence number (ISS) is chosen by
   the data sending TCP peer, and the initial receive sequence number
   (IRS) is learned during the connection-establishing procedure.

   For a connection to be established or initialized, the two TCP peers
   must synchronize on each other's initial sequence numbers.  This is
   done in an exchange of connection-establishing segments carrying a
   control bit called "SYN" (for synchronize) and the initial sequence
   numbers.  As a shorthand, segments carrying the SYN bit are also
   called "SYNs".  Hence, the solution requires a suitable mechanism for
   picking an initial sequence number and a slightly involved handshake
   to exchange the ISNs.

Cc: Saloni Kasbekar <saloni.kasbekar@intel.com>
Cc: Zachary Clark-williams <zachary.clark-williams@intel.com>

Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
Reviewed-by: Saloni Kasbekar <saloni.kasbekar@intel.com>
---
 NetworkPkg/TcpDxe/TcpDriver.c |  89 ++++++++++++-
 NetworkPkg/TcpDxe/TcpDxe.inf  |   8 +-
 NetworkPkg/TcpDxe/TcpFunc.h   |  23 ++--
 NetworkPkg/TcpDxe/TcpInput.c  |  13 +-
 NetworkPkg/TcpDxe/TcpMain.h   |  59 ++++++--
 NetworkPkg/TcpDxe/TcpMisc.c   | 244 ++++++++++++++++++++++++++++++++--
 NetworkPkg/TcpDxe/TcpTimer.c  |   3 +-
 7 files changed, 391 insertions(+), 48 deletions(-)

diff --git a/NetworkPkg/TcpDxe/TcpDriver.c b/NetworkPkg/TcpDxe/TcpDriver.c
index 7071527..e2a29d9 100644
--- a/NetworkPkg/TcpDxe/TcpDriver.c
+++ b/NetworkPkg/TcpDxe/TcpDriver.c
@@ -83,6 +83,11 @@ EFI_SERVICE_BINDING_PROTOCOL  gTcpServiceBinding = {
   TcpServiceBindingDestroyChild
 };
 
+//
+// This is the handle for the Hash2ServiceBinding Protocol instance this driver produces
+// if the platform does not provide one.
+//
+EFI_HANDLE  mHash2ServiceHandle = NULL;
 
 /**
   Create and start the heartbeat timer for the TCP driver.
@@ -169,6 +174,23 @@ TcpDriverEntryPoint (
   EFI_STATUS  Status;
   UINT32      Random;
 
+  //
+  // Initialize the Secret used for hashing TCP sequence numbers
+  //
+  // Normally this should be regenerated periodically, but since
+  // this is only used for UEFI networking and not a general purpose
+  // operating system, it is not necessary to regenerate it.
+  //
+  Status = PseudoRandomU32 (&mTcpGlobalSecret);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status));
+    return Status;
+  }
+
+  //
+  // Get a random number used to generate a random port number
+  // Intentionally not linking this to mTcpGlobalSecret to avoid leaking information about the secret
+  //
   Status = PseudoRandomU32 (&Random);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a Failed to generate random number: %r\n", __func__, Status));
@@ -213,7 +235,6 @@ TcpDriverEntryPoint (
   //
   // Initialize ISS and random port.
   //
-  mTcpGlobalIss   = Random % mTcpGlobalIss;
   mTcp4RandomPort = (UINT16) (TCP_PORT_KNOWN + (Random % TCP_PORT_KNOWN));
   mTcp6RandomPort = mTcp4RandomPort;
 
@@ -228,6 +249,8 @@ TcpDriverEntryPoint (
   @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6.
 
   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.
+  @retval EFI_UNSUPPORTED        Service Binding Protocols are unavailable.
+  @retval EFI_ALREADY_STARTED    The TCP driver is already started on the controller.
   @retval EFI_SUCCESS            A new IP6 service binding private was created.
 
 **/
@@ -238,11 +261,13 @@ TcpCreateService (
   IN UINT8       IpVersion
   )
 {
-  EFI_STATUS         Status;
-  EFI_GUID           *IpServiceBindingGuid;
-  EFI_GUID           *TcpServiceBindingGuid;
-  TCP_SERVICE_DATA   *TcpServiceData;
-  IP_IO_OPEN_DATA    OpenData;
+  EFI_STATUS                    Status;
+  EFI_GUID                      *IpServiceBindingGuid;
+  EFI_GUID                      *TcpServiceBindingGuid;
+  TCP_SERVICE_DATA              *TcpServiceData;
+  IP_IO_OPEN_DATA               OpenData;
+  EFI_SERVICE_BINDING_PROTOCOL  *Hash2ServiceBinding;
+  EFI_HASH2_PROTOCOL            *Hash2Protocol;
 
   if (IpVersion == IP_VERSION_4) {
     IpServiceBindingGuid  = &gEfiIp4ServiceBindingProtocolGuid;
@@ -276,6 +301,33 @@ TcpCreateService (
     return EFI_UNSUPPORTED;
   }
 
+  Status = gBS->LocateProtocol (&gEfiHash2ProtocolGuid, NULL, (VOID **)&Hash2Protocol);
+  if (EFI_ERROR (Status)) {
+    //
+    // If we can't find the Hashing protocol, then we need to create one.
+    //
+
+    //
+    // Platform is expected to publish the hash service binding protocol to support TCP.
+    //
+    Status = gBS->LocateProtocol (
+                    &gEfiHash2ServiceBindingProtocolGuid,
+                    NULL,
+                    (VOID **)&Hash2ServiceBinding
+                    );
+    if (EFI_ERROR (Status) || (Hash2ServiceBinding == NULL) || (Hash2ServiceBinding->CreateChild == NULL)) {
+      return EFI_UNSUPPORTED;
+    }
+
+    //
+    // Create an instance of the hash protocol for this controller.
+    //
+    Status = Hash2ServiceBinding->CreateChild (Hash2ServiceBinding, &mHash2ServiceHandle);
+    if (EFI_ERROR (Status)) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
   //
   // Create the TCP service data.
   //
@@ -428,6 +480,7 @@ TcpDestroyService (
   EFI_STATUS                    Status;
   LIST_ENTRY                    *List;
   TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT  Context;
+  EFI_SERVICE_BINDING_PROTOCOL             *Hash2ServiceBinding;
 
   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
 
@@ -444,6 +497,30 @@ TcpDestroyService (
     return EFI_SUCCESS;
   }
 
+  //
+  // Destroy the Hash2ServiceBinding instance if it is created by Tcp driver.
+  //
+  if (mHash2ServiceHandle != NULL) {
+    Status = gBS->LocateProtocol (
+                    &gEfiHash2ServiceBindingProtocolGuid,
+                    NULL,
+                    (VOID **)&Hash2ServiceBinding
+                    );
+    if (EFI_ERROR (Status) || (Hash2ServiceBinding == NULL) || (Hash2ServiceBinding->DestroyChild == NULL)) {
+      return EFI_UNSUPPORTED;
+    }
+
+    //
+    // Destroy the instance of the hashing protocol for this controller.
+    //
+    Status = Hash2ServiceBinding->DestroyChild (Hash2ServiceBinding, &mHash2ServiceHandle);
+    if (EFI_ERROR (Status)) {
+      return EFI_UNSUPPORTED;
+    }
+
+    mHash2ServiceHandle = NULL;
+  }
+
   Status = gBS->OpenProtocol (
                   NicHandle,
                   ServiceBindingGuid,
diff --git a/NetworkPkg/TcpDxe/TcpDxe.inf b/NetworkPkg/TcpDxe/TcpDxe.inf
index 1b30980..dc08f76 100644
--- a/NetworkPkg/TcpDxe/TcpDxe.inf
+++ b/NetworkPkg/TcpDxe/TcpDxe.inf
@@ -6,6 +6,7 @@
 #  stack has been loaded in system. This driver supports both IPv4 and IPv6 network stack.
 #
 #  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) Microsoft Corporation
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -68,7 +69,6 @@
   NetLib
   IpIoLib
 
-
 [Protocols]
   ## SOMETIMES_CONSUMES
   ## SOMETIMES_PRODUCES
@@ -81,6 +81,12 @@
   gEfiIp6ServiceBindingProtocolGuid             ## TO_START
   gEfiTcp6ProtocolGuid                          ## BY_START
   gEfiTcp6ServiceBindingProtocolGuid            ## BY_START
+  gEfiHash2ProtocolGuid                         ## BY_START
+  gEfiHash2ServiceBindingProtocolGuid           ## BY_START
+
+[Guids]
+  gEfiHashAlgorithmMD5Guid                      ## CONSUMES
+  gEfiHashAlgorithmSha256Guid                   ## CONSUMES
 
 [Depex]
   gEfiHash2ServiceBindingProtocolGuid
diff --git a/NetworkPkg/TcpDxe/TcpFunc.h b/NetworkPkg/TcpDxe/TcpFunc.h
index 05cd3c7..72cf7b8 100644
--- a/NetworkPkg/TcpDxe/TcpFunc.h
+++ b/NetworkPkg/TcpDxe/TcpFunc.h
@@ -2,7 +2,7 @@
   Declaration of external functions shared in TCP driver.
 
   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
-
+  Copyright (c) Microsoft Corporation
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -36,8 +36,11 @@ VOID
 
   @param[in, out]  Tcb               Pointer to the TCP_CB of this TCP instance.
 
+  @retval EFI_SUCCESS             The operation completed successfully
+  @retval others                  The underlying functions failed and could not complete the operation
+
 **/
-VOID
+EFI_STATUS
 TcpInitTcbLocal (
   IN OUT TCP_CB *Tcb
   );
@@ -128,17 +131,6 @@ TcpCloneTcb (
   IN TCP_CB *Tcb
   );
 
-/**
-  Compute an ISS to be used by a new connection.
-
-  @return The result ISS.
-
-**/
-TCP_SEQNO
-TcpGetIss (
-  VOID
-  );
-
 /**
   Get the local mss.
 
@@ -202,8 +194,11 @@ TcpFormatNetbuf (
   @param[in, out]  Tcb          Pointer to the TCP_CB that wants to initiate a
                                 connection.
 
+  @retval EFI_SUCCESS             The operation completed successfully
+  @retval others                  The underlying functions failed and could not complete the operation
+
 **/
-VOID
+EFI_STATUS
 TcpOnAppConnect (
   IN OUT TCP_CB  *Tcb
   );
diff --git a/NetworkPkg/TcpDxe/TcpInput.c b/NetworkPkg/TcpDxe/TcpInput.c
index 5e6c8c5..bf85846 100644
--- a/NetworkPkg/TcpDxe/TcpInput.c
+++ b/NetworkPkg/TcpDxe/TcpInput.c
@@ -759,6 +759,7 @@ TcpInput (
   TCP_SEQNO   Urg;
   UINT16      Checksum;
   INT32       Usable;
+  EFI_STATUS  Status;
 
   ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));
 
@@ -908,7 +909,17 @@ TcpInput (
       Tcb->LocalEnd.Port  = Head->DstPort;
       Tcb->RemoteEnd.Port = Head->SrcPort;
 
-      TcpInitTcbLocal (Tcb);
+      Status = TcpInitTcbLocal (Tcb);
+      if (EFI_ERROR (Status)) {
+        DEBUG (
+          (DEBUG_ERROR,
+           "TcpInput: discard a segment because failed to init local end for TCB %p\n",
+           Tcb)
+          );
+
+        goto DISCARD;
+      }
+
       TcpInitTcbPeer (Tcb, Seg, &Option);
 
       TcpSetState (Tcb, TCP_SYN_RCVD);
diff --git a/NetworkPkg/TcpDxe/TcpMain.h b/NetworkPkg/TcpDxe/TcpMain.h
index 35f12a1..7f517d5 100644
--- a/NetworkPkg/TcpDxe/TcpMain.h
+++ b/NetworkPkg/TcpDxe/TcpMain.h
@@ -3,7 +3,7 @@
   It is the common head file for all Tcp*.c in TCP driver.
 
   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
-
+  Copyright (c) Microsoft Corporation
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -13,6 +13,7 @@
 
 #include <Protocol/ServiceBinding.h>
 #include <Protocol/DriverBinding.h>
+#include <Protocol/Hash2.h>
 #include <Library/IpIoLib.h>
 #include <Library/DevicePathLib.h>
 #include <Library/PrintLib.h>
@@ -31,7 +32,7 @@ extern EFI_UNICODE_STRING_TABLE      *gTcpControllerNameTable;
 
 extern LIST_ENTRY                    mTcpRunQue;
 extern LIST_ENTRY                    mTcpListenQue;
-extern TCP_SEQNO                     mTcpGlobalIss;
+extern TCP_SEQNO   mTcpGlobalSecret;
 extern UINT32                        mTcpTick;
 
 ///
@@ -45,14 +46,6 @@ extern UINT32                        mTcpTick;
 
 #define TCP_EXPIRE_TIME            65535
 
-///
-/// The implementation selects the initial send sequence number and the unit to
-/// be added when it is increased.
-///
-#define TCP_BASE_ISS               0x4d7e980b
-#define TCP_ISS_INCREMENT_1        2048
-#define TCP_ISS_INCREMENT_2        100
-
 typedef union {
   EFI_TCP4_CONFIG_DATA  Tcp4CfgData;
   EFI_TCP6_CONFIG_DATA  Tcp6CfgData;
@@ -774,4 +767,50 @@ Tcp6Poll (
   IN EFI_TCP6_PROTOCOL        *This
   );
 
+/**
+  Retrieves the Initial Sequence Number (ISN) for a TCP connection identified by local
+  and remote IP addresses and ports.
+
+  This method is based on https://datatracker.ietf.org/doc/html/rfc9293#section-3.4.1
+  Where the ISN is computed as follows:
+    ISN = TimeStamp + MD5(LocalIP, LocalPort, RemoteIP, RemotePort, Secret)
+
+  Otherwise:
+    ISN = M + F(localip, localport, remoteip, remoteport, secretkey)
+
+    "Here M is the 4 microsecond timer, and F() is a pseudorandom function (PRF) of the
+    connection's identifying parameters ("localip, localport, remoteip, remoteport")
+    and a secret key ("secretkey") (SHLD-1). F() MUST NOT be computable from the
+    outside (MUST-9), or an attacker could still guess at sequence numbers from the
+    ISN used for some other connection. The PRF could be implemented as a
+    cryptographic hash of the concatenation of the TCP connection parameters and some
+    secret data. For discussion of the selection of a specific hash algorithm and
+    management of the secret key data."
+
+  @param[in]       LocalIp        A pointer to the local IP address of the TCP connection.
+  @param[in]       LocalIpSize    The size, in bytes, of the LocalIp buffer.
+  @param[in]       LocalPort      The local port number of the TCP connection.
+  @param[in]       RemoteIp       A pointer to the remote IP address of the TCP connection.
+  @param[in]       RemoteIpSize   The size, in bytes, of the RemoteIp buffer.
+  @param[in]       RemotePort     The remote port number of the TCP connection.
+  @param[out]      Isn            A pointer to the variable that will receive the Initial
+                                  Sequence Number (ISN).
+
+  @retval EFI_SUCCESS             The operation completed successfully, and the ISN was
+                                  retrieved.
+  @retval EFI_INVALID_PARAMETER   One or more of the input parameters are invalid.
+  @retval EFI_UNSUPPORTED         The operation is not supported.
+
+**/
+EFI_STATUS
+TcpGetIsn (
+  IN UINT8       *LocalIp,
+  IN UINTN       LocalIpSize,
+  IN UINT16      LocalPort,
+  IN UINT8       *RemoteIp,
+  IN UINTN       RemoteIpSize,
+  IN UINT16      RemotePort,
+  OUT TCP_SEQNO  *Isn
+  );
+
 #endif
diff --git a/NetworkPkg/TcpDxe/TcpMisc.c b/NetworkPkg/TcpDxe/TcpMisc.c
index 73ed33d..18fa1d9 100644
--- a/NetworkPkg/TcpDxe/TcpMisc.c
+++ b/NetworkPkg/TcpDxe/TcpMisc.c
@@ -3,7 +3,7 @@
 
   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
   Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
-
+  Copyright (c) Microsoft Corporation
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -20,7 +20,34 @@ LIST_ENTRY      mTcpListenQue = {
   &mTcpListenQue
 };
 
-TCP_SEQNO       mTcpGlobalIss = TCP_BASE_ISS;
+//
+// The Session secret
+// This must be initialized to a random value at boot time
+//
+TCP_SEQNO  mTcpGlobalSecret;
+
+//
+// Union to hold either an IPv4 or IPv6 address
+// This is used to simplify the ISN hash computation
+//
+typedef union {
+  UINT8    IPv4[4];
+  UINT8    IPv6[16];
+} NETWORK_ADDRESS;
+
+//
+// The ISN is computed by hashing this structure
+// It is initialized with the local and remote IP addresses and ports
+// and the secret
+//
+//
+typedef struct {
+  UINT16             LocalPort;
+  UINT16             RemotePort;
+  NETWORK_ADDRESS    LocalAddress;
+  NETWORK_ADDRESS    RemoteAddress;
+  TCP_SEQNO          Secret;
+} ISN_HASH_CTX;
 
 CHAR16          *mTcpStateName[] = {
   L"TCP_CLOSED",
@@ -42,12 +69,18 @@ CHAR16          *mTcpStateName[] = {
 
   @param[in, out]  Tcb               Pointer to the TCP_CB of this TCP instance.
 
+  @retval EFI_SUCCESS             The operation completed successfully
+  @retval others                  The underlying functions failed and could not complete the operation
+
 **/
-VOID
+EFI_STATUS
 TcpInitTcbLocal (
   IN OUT TCP_CB *Tcb
   )
 {
+  TCP_SEQNO   Isn;
+  EFI_STATUS  Status;
+
   //
   // Compute the checksum of the fixed parts of pseudo header
   //
@@ -58,6 +91,16 @@ TcpInitTcbLocal (
                     0x06,
                     0
                     );
+
+    Status = TcpGetIsn (
+               Tcb->LocalEnd.Ip.v4.Addr,
+               sizeof (IPv4_ADDRESS),
+               Tcb->LocalEnd.Port,
+               Tcb->RemoteEnd.Ip.v4.Addr,
+               sizeof (IPv4_ADDRESS),
+               Tcb->RemoteEnd.Port,
+               &Isn
+               );
   } else {
     Tcb->HeadSum = NetIp6PseudoHeadChecksum (
                     &Tcb->LocalEnd.Ip.v6,
@@ -65,9 +108,25 @@ TcpInitTcbLocal (
                     0x06,
                     0
                     );
+
+    Status = TcpGetIsn (
+               Tcb->LocalEnd.Ip.v6.Addr,
+               sizeof (IPv6_ADDRESS),
+               Tcb->LocalEnd.Port,
+               Tcb->RemoteEnd.Ip.v6.Addr,
+               sizeof (IPv6_ADDRESS),
+               Tcb->RemoteEnd.Port,
+               &Isn
+               );
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "TcpInitTcbLocal: failed to get isn\n"));
+    ASSERT (FALSE);
+    return Status;
   }
 
-  Tcb->Iss    = TcpGetIss ();
+  Tcb->Iss    = Isn;
   Tcb->SndUna = Tcb->Iss;
   Tcb->SndNxt = Tcb->Iss;
 
@@ -83,6 +142,8 @@ TcpInitTcbLocal (
   Tcb->RetxmitSeqMax = 0;
 
   Tcb->ProbeTimerOn = FALSE;
+
+  return EFI_SUCCESS;
 }
 
 /**
@@ -512,18 +573,162 @@ TcpCloneTcb (
 }
 
 /**
-  Compute an ISS to be used by a new connection.
-
-  @return The resulting ISS.
+  Retrieves the Initial Sequence Number (ISN) for a TCP connection identified by local
+  and remote IP addresses and ports.
+
+  This method is based on https://datatracker.ietf.org/doc/html/rfc9293#section-3.4.1
+  Where the ISN is computed as follows:
+    ISN = TimeStamp + MD5(LocalIP, LocalPort, RemoteIP, RemotePort, Secret)
+
+  Otherwise:
+    ISN = M + F(localip, localport, remoteip, remoteport, secretkey)
+
+    "Here M is the 4 microsecond timer, and F() is a pseudorandom function (PRF) of the
+    connection's identifying parameters ("localip, localport, remoteip, remoteport")
+    and a secret key ("secretkey") (SHLD-1). F() MUST NOT be computable from the
+    outside (MUST-9), or an attacker could still guess at sequence numbers from the
+    ISN used for some other connection. The PRF could be implemented as a
+    cryptographic hash of the concatenation of the TCP connection parameters and some
+    secret data. For discussion of the selection of a specific hash algorithm and
+    management of the secret key data."
+
+  @param[in]       LocalIp        A pointer to the local IP address of the TCP connection.
+  @param[in]       LocalIpSize    The size, in bytes, of the LocalIp buffer.
+  @param[in]       LocalPort      The local port number of the TCP connection.
+  @param[in]       RemoteIp       A pointer to the remote IP address of the TCP connection.
+  @param[in]       RemoteIpSize   The size, in bytes, of the RemoteIp buffer.
+  @param[in]       RemotePort     The remote port number of the TCP connection.
+  @param[out]      Isn            A pointer to the variable that will receive the Initial
+                                  Sequence Number (ISN).
+
+  @retval EFI_SUCCESS             The operation completed successfully, and the ISN was
+                                  retrieved.
+  @retval EFI_INVALID_PARAMETER   One or more of the input parameters are invalid.
+  @retval EFI_UNSUPPORTED         The operation is not supported.
 
 **/
-TCP_SEQNO
-TcpGetIss (
-  VOID
+EFI_STATUS
+TcpGetIsn (
+  IN UINT8       *LocalIp,
+  IN UINTN       LocalIpSize,
+  IN UINT16      LocalPort,
+  IN UINT8       *RemoteIp,
+  IN UINTN       RemoteIpSize,
+  IN UINT16      RemotePort,
+  OUT TCP_SEQNO  *Isn
   )
 {
-  mTcpGlobalIss += TCP_ISS_INCREMENT_1;
-  return mTcpGlobalIss;
+  EFI_STATUS          Status;
+  EFI_HASH2_PROTOCOL  *Hash2Protocol;
+  EFI_HASH2_OUTPUT    HashResult;
+  ISN_HASH_CTX        IsnHashCtx;
+  EFI_TIME            TimeStamp;
+
+  //
+  // Check that the ISN pointer is valid
+  //
+  if (Isn == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // The local ip may be a v4 or v6 address and may not be NULL
+  //
+  if ((LocalIp == NULL) || (LocalIpSize == 0) || (RemoteIp == NULL) || (RemoteIpSize == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // the local ip may be a v4 or v6 address
+  //
+  if ((LocalIpSize != sizeof (EFI_IPv4_ADDRESS)) && (LocalIpSize != sizeof (EFI_IPv6_ADDRESS))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Locate the Hash Protocol
+  //
+  Status = gBS->LocateProtocol (&gEfiHash2ProtocolGuid, NULL, (VOID **)&Hash2Protocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_NET, "Failed to locate Hash Protocol: %r\n", Status));
+
+    //
+    // TcpCreateService(..) is expected to be called prior to this function
+    //
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  //
+  // Initialize the hash algorithm
+  //
+  Status = Hash2Protocol->HashInit (Hash2Protocol, &gEfiHashAlgorithmSha256Guid);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_NET, "Failed to initialize sha256 hash algorithm: %r\n", Status));
+    return Status;
+  }
+
+  IsnHashCtx.LocalPort  = LocalPort;
+  IsnHashCtx.RemotePort = RemotePort;
+  IsnHashCtx.Secret     = mTcpGlobalSecret;
+
+  //
+  // Check the IP address family and copy accordingly
+  //
+  if (LocalIpSize == sizeof (EFI_IPv4_ADDRESS)) {
+    CopyMem (&IsnHashCtx.LocalAddress.IPv4, LocalIp, LocalIpSize);
+  } else if (LocalIpSize == sizeof (EFI_IPv6_ADDRESS)) {
+    CopyMem (&IsnHashCtx.LocalAddress.IPv6, LocalIp, LocalIpSize);
+  } else {
+    return EFI_INVALID_PARAMETER; // Unsupported address size
+  }
+
+  //
+  // Repeat the process for the remote IP address
+  //
+  if (RemoteIpSize == sizeof (EFI_IPv4_ADDRESS)) {
+    CopyMem (&IsnHashCtx.RemoteAddress.IPv4, RemoteIp, RemoteIpSize);
+  } else if (RemoteIpSize == sizeof (EFI_IPv6_ADDRESS)) {
+    CopyMem (&IsnHashCtx.RemoteAddress.IPv6, RemoteIp, RemoteIpSize);
+  } else {
+    return EFI_INVALID_PARAMETER; // Unsupported address size
+  }
+
+  //
+  // Compute the hash
+  // Update the hash with the data
+  //
+  Status = Hash2Protocol->HashUpdate (Hash2Protocol, (UINT8 *)&IsnHashCtx, sizeof (IsnHashCtx));
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_NET, "Failed to update hash: %r\n", Status));
+    return Status;
+  }
+
+  //
+  // Finalize the hash and retrieve the result
+  //
+  Status = Hash2Protocol->HashFinal (Hash2Protocol, &HashResult);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_NET, "Failed to finalize hash: %r\n", Status));
+    return Status;
+  }
+
+  Status = gRT->GetTime (&TimeStamp, NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // copy the first 4 bytes of the hash result into the ISN
+  //
+  CopyMem (Isn, HashResult.Md5Hash, sizeof (*Isn));
+
+  //
+  // now add the timestamp to the ISN as 4 microseconds units (1000 / 4 = 250)
+  //
+  *Isn += (TCP_SEQNO)TimeStamp.Nanosecond * 250;
+
+  return Status;
 }
 
 /**
@@ -727,17 +932,28 @@ TcpFormatNetbuf (
   @param[in, out]  Tcb          Pointer to the TCP_CB that wants to initiate a
                                 connection.
 
+  @retval EFI_SUCCESS             The operation completed successfully
+  @retval others                  The underlying functions failed and could not complete the operation
+
 **/
-VOID
+EFI_STATUS
 TcpOnAppConnect (
   IN OUT TCP_CB  *Tcb
   )
 {
-  TcpInitTcbLocal (Tcb);
+  EFI_STATUS  Status;
+
+  Status = TcpInitTcbLocal (Tcb);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
   TcpSetState (Tcb, TCP_SYN_SENT);
 
   TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
   TcpToSendData (Tcb, 1);
+
+  return EFI_SUCCESS;
 }
 
 /**
diff --git a/NetworkPkg/TcpDxe/TcpTimer.c b/NetworkPkg/TcpDxe/TcpTimer.c
index 106d947..4d0b7fe 100644
--- a/NetworkPkg/TcpDxe/TcpTimer.c
+++ b/NetworkPkg/TcpDxe/TcpTimer.c
@@ -2,7 +2,7 @@
   TCP timer related functions.
 
   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
-
+  Copyright (c) Microsoft Corporation
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -497,7 +497,6 @@ TcpTickingDpc (
   INT16           Index;
 
   mTcpTick++;
-  mTcpGlobalIss += TCP_ISS_INCREMENT_2;
 
   //
   // Don't use LIST_FOR_EACH, which isn't delete safe.
-- 
2.33.0

