Signed-off-by: sfu5 Reviewed-by: xdu2 Reviewed-by: ydong10 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12514 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2067 lines
		
	
	
		
			67 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2067 lines
		
	
	
		
			67 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The operations for IKEv2 SA.
 | 
						|
 | 
						|
  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php.
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Utility.h"
 | 
						|
#include "IpSecDebug.h"
 | 
						|
#include "IkeService.h"
 | 
						|
#include "Ikev2.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the DH Key.
 | 
						|
 | 
						|
  This generates the DH local public key and store it in the IKEv2 SA Session's GxBuffer.
 | 
						|
  
 | 
						|
  @param[in]  IkeSaSession   Pointer to related IKE SA Session.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        The operation succeeded.
 | 
						|
  @retval Others             The operation failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2GenerateSaDhPublicKey (
 | 
						|
  IN IKEV2_SA_SESSION         *IkeSaSession
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the IKEv2 SA key for the furthure IKEv2 exchange.
 | 
						|
 | 
						|
  @param[in]  IkeSaSession       Pointer to IKEv2 SA Session.
 | 
						|
  @param[in]  KePayload          Pointer to Key payload used to generate the Key.
 | 
						|
 | 
						|
  @retval EFI_UNSUPPORTED    If the Algorithm Id is not supported.
 | 
						|
  @retval EFI_SUCCESS        The operation succeeded.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2GenerateSaKeys (
 | 
						|
  IN IKEV2_SA_SESSION       *IkeSaSession,
 | 
						|
  IN IKE_PAYLOAD            *KePayload
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the Keys for the furthure IPsec Protocol.
 | 
						|
 | 
						|
  @param[in]  ChildSaSession     Pointer to IKE Child SA Session.
 | 
						|
  @param[in]  KePayload          Pointer to Key payload used to generate the Key.
 | 
						|
 | 
						|
  @retval EFI_UNSUPPORTED    If one or more Algorithm Id is unsupported.
 | 
						|
  @retval EFI_SUCCESS        The operation succeeded.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2GenerateChildSaKeys (
 | 
						|
  IN IKEV2_CHILD_SA_SESSION     *ChildSaSession,
 | 
						|
  IN IKE_PAYLOAD                *KePayload
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Gernerates IKEv2 packet for IKE_SA_INIT exchange.
 | 
						|
 | 
						|
  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.
 | 
						|
  @param[in] Context    Context Data passed by caller.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The IKEv2 packet generation succeeded.
 | 
						|
  @retval Others        The IKEv2 packet generation failed.
 | 
						|
 | 
						|
**/
 | 
						|
IKE_PACKET *
 | 
						|
Ikev2InitPskGenerator (
 | 
						|
  IN UINT8           *SaSession,
 | 
						|
  IN VOID            *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  IKE_PACKET         *IkePacket;
 | 
						|
  IKEV2_SA_SESSION   *IkeSaSession;
 | 
						|
  IKE_PAYLOAD        *SaPayload;
 | 
						|
  IKE_PAYLOAD        *KePayload;
 | 
						|
  IKE_PAYLOAD        *NoncePayload;
 | 
						|
  IKE_PAYLOAD        *NotifyPayload;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
 | 
						|
  SaPayload      = NULL;
 | 
						|
  KePayload      = NULL;
 | 
						|
  NoncePayload   = NULL;
 | 
						|
  NotifyPayload  = NULL;
 | 
						|
 | 
						|
  IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. Allocate IKE packet
 | 
						|
  //
 | 
						|
  IkePacket = IkePacketAlloc ();
 | 
						|
  ASSERT (IkePacket != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // 1.a Fill the IkePacket->Hdr
 | 
						|
  //
 | 
						|
  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_INIT;
 | 
						|
  IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
 | 
						|
  IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
 | 
						|
  IkePacket->Header->Version         = (UINT8) (2 << 4);
 | 
						|
  IkePacket->Header->MessageId       = 0;
 | 
						|
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
 | 
						|
  } else {
 | 
						|
    IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If the NCookie is not NULL, this IKE_SA_INIT packet is resent by the NCookie
 | 
						|
  // and the NCookie payload should be the first payload in this packet.
 | 
						|
  //
 | 
						|
  if (IkeSaSession->NCookie != NULL) {
 | 
						|
    IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NOTIFY;
 | 
						|
    NotifyPayload = Ikev2GenerateNotifyPayload (
 | 
						|
                      IPSEC_PROTO_ISAKMP,
 | 
						|
                      IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                      0,
 | 
						|
                      IKEV2_NOTIFICATION_COOKIE,
 | 
						|
                      NULL,
 | 
						|
                      IkeSaSession->NCookie,
 | 
						|
                      IkeSaSession->NCookieSize
 | 
						|
                      );
 | 
						|
  } else {
 | 
						|
    IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_SA;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Generate SA Payload according to the SaData & SaParams
 | 
						|
  //
 | 
						|
  SaPayload = Ikev2GenerateSaPayload (
 | 
						|
                IkeSaSession->SaData,
 | 
						|
                IKEV2_PAYLOAD_TYPE_KE,
 | 
						|
                IkeSessionTypeIkeSa
 | 
						|
                );
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Generate DH public key.
 | 
						|
  //    The DhPrivate Key has been generated in Ikev2InitPskParser, if the
 | 
						|
  //    IkeSaSession is responder. If resending IKE_SA_INIT with Cookie Notify
 | 
						|
  //    No need to recompute the Public key.
 | 
						|
  //
 | 
						|
  if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {    
 | 
						|
    Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto CheckError;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 4. Generate KE Payload according to SaParams->DhGroup
 | 
						|
  //
 | 
						|
  KePayload = Ikev2GenerateKePayload (
 | 
						|
                IkeSaSession, 
 | 
						|
                IKEV2_PAYLOAD_TYPE_NONCE
 | 
						|
                );
 | 
						|
 | 
						|
  //
 | 
						|
  // 5. Generate Nonce Payload
 | 
						|
  //    If resending IKE_SA_INIT with Cookie Notify paylaod, no need to regenerate
 | 
						|
  //    the Nonce Payload.
 | 
						|
  //
 | 
						|
  if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {
 | 
						|
    IkeSaSession->NiBlkSize = IKE_NONCE_SIZE;
 | 
						|
    IkeSaSession->NiBlock   = IkeGenerateNonce (IKE_NONCE_SIZE);
 | 
						|
    ASSERT (IkeSaSession->NiBlock != NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    NoncePayload = Ikev2GenerateNoncePayload (
 | 
						|
                     IkeSaSession->NiBlock,
 | 
						|
                     IkeSaSession->NiBlkSize,
 | 
						|
                     IKEV2_PAYLOAD_TYPE_NONE
 | 
						|
                     );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // The Nonce Payload has been created in Ikev2PskParser if the IkeSaSession is
 | 
						|
    // responder.
 | 
						|
    //
 | 
						|
    NoncePayload = Ikev2GenerateNoncePayload (
 | 
						|
                     IkeSaSession->NrBlock,
 | 
						|
                     IkeSaSession->NrBlkSize,
 | 
						|
                     IKEV2_PAYLOAD_TYPE_NONE
 | 
						|
                     );
 | 
						|
  }
 | 
						|
 | 
						|
  if (NotifyPayload != NULL) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
 | 
						|
  }
 | 
						|
  if (SaPayload != NULL) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
 | 
						|
  }
 | 
						|
  if (KePayload != NULL) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, KePayload);
 | 
						|
  }
 | 
						|
  if (NoncePayload != NULL) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NoncePayload);
 | 
						|
  }
 | 
						|
 | 
						|
  return IkePacket;
 | 
						|
 | 
						|
CheckError:
 | 
						|
  if (IkePacket != NULL) {
 | 
						|
    IkePacketFree (IkePacket);
 | 
						|
  }
 | 
						|
  if (SaPayload != NULL) {
 | 
						|
    IkePayloadFree (SaPayload);
 | 
						|
  }
 | 
						|
  return NULL;    
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parses the IKEv2 packet for IKE_SA_INIT exchange.
 | 
						|
 | 
						|
  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.
 | 
						|
  @param[in] IkePacket  The received IKE packet to be parsed.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The IKEv2 packet is acceptable and the relative data is
 | 
						|
                                 saved for furthure communication.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The IKEv2 packet is malformed or the SA proposal is unacceptable.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2InitPskParser (
 | 
						|
  IN UINT8            *SaSession,
 | 
						|
  IN IKE_PACKET       *IkePacket
 | 
						|
  ) 
 | 
						|
{
 | 
						|
  IKEV2_SA_SESSION     *IkeSaSession;
 | 
						|
  IKE_PAYLOAD          *SaPayload;
 | 
						|
  IKE_PAYLOAD          *KeyPayload;
 | 
						|
  IKE_PAYLOAD          *IkePayload;
 | 
						|
  IKE_PAYLOAD          *NoncePayload;
 | 
						|
  IKE_PAYLOAD          *NotifyPayload;
 | 
						|
  UINT8                *NonceBuffer;
 | 
						|
  UINTN                NonceSize;
 | 
						|
  LIST_ENTRY           *Entry;
 | 
						|
  EFI_STATUS           Status;
 | 
						|
 | 
						|
  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;
 | 
						|
  KeyPayload     = NULL;
 | 
						|
  SaPayload      = NULL;
 | 
						|
  NoncePayload   = NULL;
 | 
						|
  IkePayload     = NULL;
 | 
						|
  NotifyPayload  = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Iterate payloads to find the SaPayload and KeyPayload.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
 | 
						|
    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
 | 
						|
      SaPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_KE) {
 | 
						|
      KeyPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NONCE) {
 | 
						|
      NoncePayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) {
 | 
						|
      NotifyPayload = IkePayload;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // According to RFC 4306 - 2.6. If the responder responds with the COOKIE Notify
 | 
						|
  // payload with the cookie data, initiator MUST retry the IKE_SA_INIT with a
 | 
						|
  // Notify payload of type COOKIE containing the responder suppplied cookie data
 | 
						|
  // as first payload and all other payloads unchanged.
 | 
						|
  //
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    if (NotifyPayload != NULL) {
 | 
						|
      Status = Ikev2ParserNotifyCookiePayload (NotifyPayload, IkeSaSession);
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((KeyPayload == NULL) || (SaPayload == NULL) || (NoncePayload == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Store NoncePayload for SKEYID computing.
 | 
						|
  //
 | 
						|
  NonceSize   = NoncePayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
 | 
						|
  NonceBuffer = (UINT8 *) AllocatePool (NonceSize);
 | 
						|
  ASSERT (NonceBuffer != NULL);
 | 
						|
  CopyMem (
 | 
						|
    NonceBuffer,
 | 
						|
    NoncePayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
 | 
						|
    NonceSize
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if IkePacket Header matches the state
 | 
						|
  //
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    //
 | 
						|
    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
 | 
						|
    //
 | 
						|
    if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto CheckError;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 2. Parse the SA Payload and Key Payload to find out the cryptographic
 | 
						|
    //    suite and fill in the Sa paramse into CommonSession->SaParams
 | 
						|
    //
 | 
						|
    if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto CheckError;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 3. If Initiator, the NoncePayload is Nr_b.
 | 
						|
    //
 | 
						|
    IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateAuth);
 | 
						|
    IkeSaSession->NrBlock             = NonceBuffer;
 | 
						|
    IkeSaSession->NrBlkSize           = NonceSize;
 | 
						|
    IkeSaSession->SessionCommon.State = IkeStateAuth;
 | 
						|
    IkeSaSession->ResponderCookie     = IkePacket->Header->ResponderCookie;
 | 
						|
 | 
						|
    //
 | 
						|
    // 4. Change the state of IkeSaSession
 | 
						|
    //
 | 
						|
    IkeSaSession->SessionCommon.State = IkeStateAuth;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
 | 
						|
    //
 | 
						|
    if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto CheckError;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 2. Parse the SA payload and find out the perfered one
 | 
						|
    //    and fill in the SA parameters into CommonSession->SaParams and SaData into
 | 
						|
    //    IkeSaSession for the responder SA payload generation.
 | 
						|
    //
 | 
						|
    if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto CheckError;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 3. Generat Dh Y parivate Key
 | 
						|
    //
 | 
						|
    Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto CheckError;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 4. If Responder, the NoncePayload is Ni_b and go to generate Nr_b.
 | 
						|
    //
 | 
						|
    IkeSaSession->NiBlock   = NonceBuffer;
 | 
						|
    IkeSaSession->NiBlkSize = NonceSize;
 | 
						|
 | 
						|
    //
 | 
						|
    // 5. Generate Nr_b
 | 
						|
    //
 | 
						|
    IkeSaSession->NrBlock   = IkeGenerateNonce (IKE_NONCE_SIZE);
 | 
						|
    ASSERT_EFI_ERROR (IkeSaSession->NrBlock != NULL);
 | 
						|
    IkeSaSession->NrBlkSize = IKE_NONCE_SIZE;
 | 
						|
 | 
						|
    //
 | 
						|
    // 6. Save the Cookies
 | 
						|
    //
 | 
						|
    IkeSaSession->InitiatorCookie = IkePacket->Header->InitiatorCookie;
 | 
						|
    IkeSaSession->ResponderCookie = IkeGenerateCookie ();
 | 
						|
  }
 | 
						|
 | 
						|
  if (IkeSaSession->SessionCommon.PreferDhGroup != ((IKEV2_KEY_EXCHANGE *)KeyPayload->PayloadBuf)->DhGroup) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto CheckError;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Call Ikev2GenerateSaKeys to create SKEYID, SKEYID_d, SKEYID_a, SKEYID_e.
 | 
						|
  //
 | 
						|
  Status = Ikev2GenerateSaKeys (IkeSaSession, KeyPayload);
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    goto CheckError;
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
CheckError:
 | 
						|
  if (NonceBuffer != NULL) {
 | 
						|
    FreePool (NonceBuffer);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the IKEv2 packet for IKE_AUTH exchange.
 | 
						|
 | 
						|
  @param[in] SaSession  Pointer to IKEV2_SA_SESSION.
 | 
						|
  @param[in] Context    Context data passed by caller.
 | 
						|
 | 
						|
  @retval   Pointer to IKE Packet to be sent out.
 | 
						|
 | 
						|
**/
 | 
						|
IKE_PACKET *
 | 
						|
Ikev2AuthPskGenerator (
 | 
						|
  IN UINT8         *SaSession,
 | 
						|
  IN VOID          *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  IKE_PACKET             *IkePacket;
 | 
						|
  IKEV2_SA_SESSION       *IkeSaSession;
 | 
						|
  IKE_PAYLOAD            *IdPayload;
 | 
						|
  IKE_PAYLOAD            *AuthPayload;
 | 
						|
  IKE_PAYLOAD            *SaPayload;
 | 
						|
  IKE_PAYLOAD            *TsiPayload;
 | 
						|
  IKE_PAYLOAD            *TsrPayload;
 | 
						|
  IKE_PAYLOAD            *NotifyPayload;
 | 
						|
  IKE_PAYLOAD            *CpPayload;
 | 
						|
  IKEV2_CHILD_SA_SESSION *ChildSaSession;
 | 
						|
  
 | 
						|
 | 
						|
  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;
 | 
						|
  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
 | 
						|
 | 
						|
  CpPayload      = NULL;
 | 
						|
  NotifyPayload  = NULL;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // 1. Allocate IKE Packet
 | 
						|
  //
 | 
						|
  IkePacket= IkePacketAlloc ();
 | 
						|
  ASSERT (IkePacket != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // 1.a Fill the IkePacket Header.
 | 
						|
  //
 | 
						|
  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_AUTH;
 | 
						|
  IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
 | 
						|
  IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
 | 
						|
  IkePacket->Header->Version         = (UINT8)(2 << 4);
 | 
						|
  if (ChildSaSession->SessionCommon.IsInitiator) {
 | 
						|
    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_INIT;
 | 
						|
  } else {
 | 
						|
    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_RSP;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should 
 | 
						|
  // be always number 0 and 1;
 | 
						|
  //
 | 
						|
  IkePacket->Header->MessageId = 1;
 | 
						|
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
 | 
						|
  } else {
 | 
						|
    IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Generate ID Payload according to IP version and address.
 | 
						|
  //
 | 
						|
  IdPayload = Ikev2GenerateIdPayload (
 | 
						|
                &IkeSaSession->SessionCommon,
 | 
						|
                IKEV2_PAYLOAD_TYPE_AUTH
 | 
						|
                );
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Generate Auth Payload
 | 
						|
  //    If it is tunnel mode, should create the configuration payload after the
 | 
						|
  //    Auth payload.
 | 
						|
  //
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
 | 
						|
 | 
						|
    AuthPayload = Ikev2PskGenerateAuthPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IdPayload,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                    FALSE
 | 
						|
                    );
 | 
						|
  } else {
 | 
						|
    AuthPayload = Ikev2PskGenerateAuthPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IdPayload,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_CP,
 | 
						|
                    FALSE
 | 
						|
                    );
 | 
						|
    if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {
 | 
						|
      CpPayload = Ikev2GenerateCpPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                    IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS
 | 
						|
                    );
 | 
						|
    } else {
 | 
						|
      CpPayload = Ikev2GenerateCpPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                    IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS
 | 
						|
                    );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 4. Generate SA Payload according to the SA Data in ChildSaSession
 | 
						|
  //
 | 
						|
  SaPayload = Ikev2GenerateSaPayload (
 | 
						|
                ChildSaSession->SaData,
 | 
						|
                IKEV2_PAYLOAD_TYPE_TS_INIT,
 | 
						|
                IkeSessionTypeChildSa
 | 
						|
                );
 | 
						|
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
 | 
						|
    //
 | 
						|
    // Generate Tsi and Tsr.
 | 
						|
    //
 | 
						|
    TsiPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_TS_RSP,
 | 
						|
                   FALSE
 | 
						|
                   );
 | 
						|
 | 
						|
    TsrPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_NOTIFY,
 | 
						|
                   FALSE
 | 
						|
                   );
 | 
						|
 | 
						|
    //
 | 
						|
    // Generate Notify Payload. If transport mode, there should have Notify
 | 
						|
    // payload with TRANSPORT_MODE notification.
 | 
						|
    //
 | 
						|
    NotifyPayload = Ikev2GenerateNotifyPayload (
 | 
						|
                      0,
 | 
						|
                      IKEV2_PAYLOAD_TYPE_NONE,
 | 
						|
                      0,
 | 
						|
                      IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,
 | 
						|
                      NULL,
 | 
						|
                      NULL,
 | 
						|
                      0
 | 
						|
                      );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Generate Tsr for Tunnel mode.
 | 
						|
    //
 | 
						|
    TsiPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_TS_RSP,
 | 
						|
                   TRUE
 | 
						|
                   );
 | 
						|
    TsrPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_NONE,
 | 
						|
                   FALSE
 | 
						|
                   );
 | 
						|
  }
 | 
						|
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);
 | 
						|
  }
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
 | 
						|
  }
 | 
						|
 | 
						|
  return IkePacket;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parses IKE_AUTH packet.
 | 
						|
 | 
						|
  @param[in]  SaSession   Pointer to the IKE_SA_SESSION related to this packet.
 | 
						|
  @param[in]  IkePacket   Pointer to the IKE_AUTH packet to be parsered.
 | 
						|
 | 
						|
  @retval     EFI_INVALID_PARAMETER   The IKE packet is malformed or the SA 
 | 
						|
                                      proposal is unacceptable.
 | 
						|
  @retval     EFI_SUCCESS             The IKE packet is acceptable and the
 | 
						|
                                      relative data is saved for furthure communication.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS 
 | 
						|
Ikev2AuthPskParser (
 | 
						|
  IN UINT8             *SaSession,
 | 
						|
  IN IKE_PACKET        *IkePacket
 | 
						|
  )
 | 
						|
{
 | 
						|
  IKEV2_CHILD_SA_SESSION *ChildSaSession;
 | 
						|
  IKEV2_SA_SESSION       *IkeSaSession;
 | 
						|
  IKE_PAYLOAD            *IkePayload;
 | 
						|
  IKE_PAYLOAD            *SaPayload;
 | 
						|
  IKE_PAYLOAD            *IdiPayload;
 | 
						|
  IKE_PAYLOAD            *IdrPayload;
 | 
						|
  IKE_PAYLOAD            *AuthPayload;
 | 
						|
  IKE_PAYLOAD            *TsiPayload;
 | 
						|
  IKE_PAYLOAD            *TsrPayload;
 | 
						|
  IKE_PAYLOAD            *VerifiedAuthPayload;
 | 
						|
  LIST_ENTRY             *Entry;
 | 
						|
  EFI_STATUS             Status;
 | 
						|
 | 
						|
  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;
 | 
						|
  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
 | 
						|
 | 
						|
  SaPayload   = NULL;
 | 
						|
  IdiPayload  = NULL;
 | 
						|
  IdrPayload  = NULL;
 | 
						|
  AuthPayload = NULL;
 | 
						|
  TsiPayload  = NULL;
 | 
						|
  TsrPayload  = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
 | 
						|
    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
 | 
						|
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {
 | 
						|
      IdiPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {
 | 
						|
      IdrPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
 | 
						|
      SaPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {
 | 
						|
      AuthPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {
 | 
						|
      TsiPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {
 | 
						|
      TsrPayload = IkePayload;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || (TsrPayload == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  if ((IdiPayload == NULL) && (IdrPayload == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check IkePacket Header is match the state
 | 
						|
  //
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    
 | 
						|
    //
 | 
						|
    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
 | 
						|
    //
 | 
						|
    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||
 | 
						|
        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)
 | 
						|
        ) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
 | 
						|
    //
 | 
						|
    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||
 | 
						|
        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)
 | 
						|
        ) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 2. Parse the SA payload and Key Payload and find out the perferable one
 | 
						|
    //    and fill in the Sa paramse into CommonSession->SaParams and SaData into
 | 
						|
    //    IkeSaSession for the responder SA payload generation.
 | 
						|
    //
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Verify the Auth Payload.
 | 
						|
  //
 | 
						|
  VerifiedAuthPayload = Ikev2PskGenerateAuthPayload (
 | 
						|
                          IkeSaSession,
 | 
						|
                          IkeSaSession->SessionCommon.IsInitiator ? IdrPayload : IdiPayload,
 | 
						|
                          IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                          TRUE
 | 
						|
                          );
 | 
						|
  if ((VerifiedAuthPayload != NULL) &&
 | 
						|
      (0 != CompareMem (
 | 
						|
              VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
 | 
						|
              AuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
 | 
						|
              VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER)
 | 
						|
              ))) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  };
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Parse the SA Payload to find out the cryptographic suite
 | 
						|
  //    and fill in the Sa paramse into CommonSession->SaParams. If no acceptable
 | 
						|
  //    porposal found, return EFI_INVALID_PARAMETER.
 | 
						|
  //
 | 
						|
  if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 4. Parse TSi, TSr payloads.
 | 
						|
  //
 | 
						|
  if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=
 | 
						|
       ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&
 | 
						|
      (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&
 | 
						|
      (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)
 | 
						|
      ) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    //
 | 
						|
    //TODO:check the Port range. Only support any port and one certain port here.
 | 
						|
    //
 | 
						|
    ChildSaSession->ProtoId    = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;
 | 
						|
    ChildSaSession->LocalPort  = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
 | 
						|
    ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
 | 
						|
    //
 | 
						|
    // Association a SPD with this SA.
 | 
						|
    //
 | 
						|
    Status = Ikev2ChildSaAssociateSpdEntry (ChildSaSession);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.
 | 
						|
    //
 | 
						|
    if (ChildSaSession->IkeSaSession->Spd == NULL) {
 | 
						|
      ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;
 | 
						|
      Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    //TODO:check the Port range.
 | 
						|
    //
 | 
						|
    if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
 | 
						|
        (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)
 | 
						|
        ) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    } 
 | 
						|
    if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
 | 
						|
        (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)
 | 
						|
        ) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.
 | 
						|
    //
 | 
						|
    if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
 | 
						|
      if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
        //
 | 
						|
        // If it is tunnel mode, the UEFI part must be the initiator.
 | 
						|
        //
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Get the Virtual IP address from the Tsi traffic selector. 
 | 
						|
      // TODO: check the CFG reply payload
 | 
						|
      //
 | 
						|
      CopyMem (
 | 
						|
        &ChildSaSession->SpdSelector->LocalAddress[0].Address,
 | 
						|
        TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),
 | 
						|
        (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?
 | 
						|
        sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)
 | 
						|
        );
 | 
						|
      }    
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 5. Generate keymats for IPsec protocol.
 | 
						|
  //
 | 
						|
  Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    //
 | 
						|
    // 6. Change the state of IkeSaSession
 | 
						|
    //
 | 
						|
    IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);
 | 
						|
    IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;
 | 
						|
  }
 | 
						|
  
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gernerates IKEv2 packet for IKE_SA_INIT exchange.
 | 
						|
 | 
						|
  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.
 | 
						|
  @param[in] Context    Context Data passed by caller.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The IKE packet generation succeeded.
 | 
						|
  @retval Others        The IKE packet generation failed.
 | 
						|
 | 
						|
**/
 | 
						|
IKE_PACKET*
 | 
						|
Ikev2InitCertGenerator (
 | 
						|
  IN UINT8           *SaSession,
 | 
						|
  IN VOID            *Context
 | 
						|
  ) 
 | 
						|
{
 | 
						|
  IKE_PACKET         *IkePacket;
 | 
						|
  IKE_PAYLOAD        *CertReqPayload;
 | 
						|
  LIST_ENTRY         *Node;
 | 
						|
  IKE_PAYLOAD        *NoncePayload;
 | 
						|
 | 
						|
  if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The first two messages exchange is same between PSK and Cert.
 | 
						|
  //
 | 
						|
  IkePacket = Ikev2InitPskGenerator (SaSession, Context);
 | 
						|
 | 
						|
  if ((IkePacket != NULL) && (!((IKEV2_SA_SESSION *)SaSession)->SessionCommon.IsInitiator)) {
 | 
						|
    //
 | 
						|
    // Add the Certification Request Payload
 | 
						|
    //
 | 
						|
    CertReqPayload = Ikev2GenerateCertificatePayload (
 | 
						|
                       (IKEV2_SA_SESSION *)SaSession,
 | 
						|
                       IKEV2_PAYLOAD_TYPE_NONE,
 | 
						|
                       (UINT8*)PcdGetPtr(PcdIpsecUefiCaFile),
 | 
						|
                       PcdGet32(PcdIpsecUefiCaFileSize),
 | 
						|
                       IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,
 | 
						|
                       TRUE
 | 
						|
                       );
 | 
						|
    //
 | 
						|
    // Change Nonce Payload Next payload type.
 | 
						|
    //
 | 
						|
    IKE_PACKET_END_PAYLOAD (IkePacket, Node);
 | 
						|
    NoncePayload = IKE_PAYLOAD_BY_PACKET (Node);
 | 
						|
    ((IKEV2_NONCE *)NoncePayload->PayloadBuf)->Header.NextPayload = IKEV2_PAYLOAD_TYPE_CERTREQ;
 | 
						|
 | 
						|
    //
 | 
						|
    // Add Certification Request Payload
 | 
						|
    //
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);
 | 
						|
  }
 | 
						|
 | 
						|
  return IkePacket;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parses the IKEv2 packet for IKE_SA_INIT exchange.
 | 
						|
 | 
						|
  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.
 | 
						|
  @param[in] IkePacket  The received IKEv2 packet to be parsed.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The IKEv2 packet is acceptable and the relative data is
 | 
						|
                                 saved for furthure communication.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The IKE packet is malformed or the SA proposal is unacceptable.                        
 | 
						|
  @retval EFI_UNSUPPORTED        The certificate authentication is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2InitCertParser (
 | 
						|
  IN UINT8            *SaSession,
 | 
						|
  IN IKE_PACKET       *IkePacket
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  } 
 | 
						|
  
 | 
						|
  //
 | 
						|
  // The first two messages exchange is same between PSK and Cert.
 | 
						|
  // Todo: Parse Certificate Request from responder Initial Exchange. 
 | 
						|
  //
 | 
						|
  return Ikev2InitPskParser (SaSession, IkePacket);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the IKEv2 packet for IKE_AUTH exchange.
 | 
						|
 | 
						|
  @param[in] SaSession  Pointer to IKEV2_SA_SESSION.
 | 
						|
  @param[in] Context    Context data passed by caller.
 | 
						|
 | 
						|
  @retval Pointer to IKEv2 Packet to be sent out.
 | 
						|
 | 
						|
**/
 | 
						|
IKE_PACKET *
 | 
						|
Ikev2AuthCertGenerator (
 | 
						|
  IN UINT8         *SaSession,
 | 
						|
  IN VOID          *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  IKE_PACKET             *IkePacket;
 | 
						|
  IKEV2_SA_SESSION       *IkeSaSession;
 | 
						|
  IKE_PAYLOAD            *IdPayload;
 | 
						|
  IKE_PAYLOAD            *AuthPayload;
 | 
						|
  IKE_PAYLOAD            *SaPayload;
 | 
						|
  IKE_PAYLOAD            *TsiPayload;
 | 
						|
  IKE_PAYLOAD            *TsrPayload;
 | 
						|
  IKE_PAYLOAD            *NotifyPayload;
 | 
						|
  IKE_PAYLOAD            *CpPayload;
 | 
						|
  IKE_PAYLOAD            *CertPayload;
 | 
						|
  IKE_PAYLOAD            *CertReqPayload;
 | 
						|
  IKEV2_CHILD_SA_SESSION *ChildSaSession;
 | 
						|
 | 
						|
  if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;
 | 
						|
  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
 | 
						|
 | 
						|
  CpPayload      = NULL;
 | 
						|
  NotifyPayload  = NULL;
 | 
						|
  CertPayload    = NULL;
 | 
						|
  CertReqPayload = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. Allocate IKE Packet
 | 
						|
  //
 | 
						|
  IkePacket= IkePacketAlloc ();
 | 
						|
  ASSERT (IkePacket != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // 1.a Fill the IkePacket Header.
 | 
						|
  //
 | 
						|
  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_AUTH;
 | 
						|
  IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
 | 
						|
  IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
 | 
						|
  IkePacket->Header->Version         = (UINT8)(2 << 4);
 | 
						|
  if (ChildSaSession->SessionCommon.IsInitiator) {
 | 
						|
    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_INIT;
 | 
						|
  } else {
 | 
						|
    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_RSP;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should
 | 
						|
  // be always number 0 and 1;
 | 
						|
  //
 | 
						|
  IkePacket->Header->MessageId = 1;
 | 
						|
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
 | 
						|
  } else {
 | 
						|
    IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Generate ID Payload according to IP version and address.
 | 
						|
  //
 | 
						|
  IdPayload = Ikev2GenerateCertIdPayload (
 | 
						|
                &IkeSaSession->SessionCommon,
 | 
						|
                IKEV2_PAYLOAD_TYPE_CERT,
 | 
						|
                (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificate),
 | 
						|
                PcdGet32 (PcdIpsecUefiCertificateSize)
 | 
						|
                );
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Generate Certificate Payload
 | 
						|
  //
 | 
						|
  CertPayload = Ikev2GenerateCertificatePayload (
 | 
						|
                  IkeSaSession,
 | 
						|
                  (UINT8)(IkeSaSession->SessionCommon.IsInitiator ? IKEV2_PAYLOAD_TYPE_CERTREQ : IKEV2_PAYLOAD_TYPE_AUTH),
 | 
						|
                  (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificate),
 | 
						|
                  PcdGet32 (PcdIpsecUefiCertificateSize),
 | 
						|
                  IKEV2_CERT_ENCODEING_X509_CERT_SIGN,
 | 
						|
                  FALSE
 | 
						|
                  );
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    CertReqPayload = Ikev2GenerateCertificatePayload (
 | 
						|
                       IkeSaSession,
 | 
						|
                       IKEV2_PAYLOAD_TYPE_AUTH,
 | 
						|
                       (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificate),
 | 
						|
                       PcdGet32 (PcdIpsecUefiCertificateSize),
 | 
						|
                       IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,
 | 
						|
                       TRUE
 | 
						|
                       );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 4. Generate Auth Payload
 | 
						|
  //    If it is tunnel mode, should create the configuration payload after the
 | 
						|
  //    Auth payload.
 | 
						|
  //
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
 | 
						|
    AuthPayload = Ikev2CertGenerateAuthPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IdPayload,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                    FALSE,
 | 
						|
                    (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificateKey),
 | 
						|
                    PcdGet32 (PcdIpsecUefiCertificateKeySize),
 | 
						|
                    ChildSaSession->IkeSaSession->Pad->Data->AuthData,
 | 
						|
                    ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize
 | 
						|
                    );
 | 
						|
  } else {
 | 
						|
    AuthPayload = Ikev2CertGenerateAuthPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IdPayload,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_CP,
 | 
						|
                    FALSE,
 | 
						|
                    (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificateKey),
 | 
						|
                    PcdGet32 (PcdIpsecUefiCertificateKeySize),
 | 
						|
                    ChildSaSession->IkeSaSession->Pad->Data->AuthData,
 | 
						|
                    ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize
 | 
						|
                    );
 | 
						|
    if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {
 | 
						|
      CpPayload = Ikev2GenerateCpPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                    IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS
 | 
						|
                    );
 | 
						|
    } else {
 | 
						|
      CpPayload = Ikev2GenerateCpPayload (
 | 
						|
                    ChildSaSession->IkeSaSession,
 | 
						|
                    IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                    IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS
 | 
						|
                    );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 5. Generate SA Payload according to the Sa Data in ChildSaSession
 | 
						|
  //
 | 
						|
  SaPayload = Ikev2GenerateSaPayload (
 | 
						|
                ChildSaSession->SaData,
 | 
						|
                IKEV2_PAYLOAD_TYPE_TS_INIT,
 | 
						|
                IkeSessionTypeChildSa
 | 
						|
                );
 | 
						|
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
 | 
						|
    //
 | 
						|
    // Generate Tsi and Tsr.
 | 
						|
    //
 | 
						|
    TsiPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_TS_RSP,
 | 
						|
                   FALSE
 | 
						|
                   );
 | 
						|
 | 
						|
    TsrPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_NOTIFY,
 | 
						|
                   FALSE
 | 
						|
                   );
 | 
						|
 | 
						|
    //
 | 
						|
    // Generate Notify Payload. If transport mode, there should have Notify 
 | 
						|
    // payload with TRANSPORT_MODE notification.
 | 
						|
    //
 | 
						|
    NotifyPayload = Ikev2GenerateNotifyPayload (
 | 
						|
                      0,
 | 
						|
                      IKEV2_PAYLOAD_TYPE_NONE,
 | 
						|
                      0,
 | 
						|
                      IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,
 | 
						|
                      NULL,
 | 
						|
                      NULL,
 | 
						|
                      0
 | 
						|
                      );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Generate Tsr for Tunnel mode.
 | 
						|
    //
 | 
						|
    TsiPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_TS_RSP,
 | 
						|
                   TRUE
 | 
						|
                   );
 | 
						|
    TsrPayload = Ikev2GenerateTsPayload (
 | 
						|
                   ChildSaSession,
 | 
						|
                   IKEV2_PAYLOAD_TYPE_NONE,
 | 
						|
                   FALSE
 | 
						|
                   );
 | 
						|
  }
 | 
						|
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertPayload);
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);
 | 
						|
  }
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);
 | 
						|
  }
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);
 | 
						|
  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);
 | 
						|
  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
 | 
						|
    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
 | 
						|
  }
 | 
						|
 | 
						|
  return IkePacket;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parses IKE_AUTH packet.
 | 
						|
 | 
						|
  @param[in]  SaSession   Pointer to the IKE_SA_SESSION related to this packet.
 | 
						|
  @param[in]  IkePacket   Pointer to the IKE_AUTH packet to be parsered.
 | 
						|
 | 
						|
  @retval     EFI_INVALID_PARAMETER   The IKEv2 packet is malformed or the SA
 | 
						|
                                      proposal is unacceptable.
 | 
						|
  @retval     EFI_SUCCESS             The IKE packet is acceptable and the
 | 
						|
                                      relative data is saved for furthure communication.
 | 
						|
  @retval     EFI_UNSUPPORTED         The certificate authentication is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2AuthCertParser (
 | 
						|
  IN UINT8             *SaSession,
 | 
						|
  IN IKE_PACKET        *IkePacket
 | 
						|
  )
 | 
						|
{
 | 
						|
  IKEV2_CHILD_SA_SESSION *ChildSaSession;
 | 
						|
  IKEV2_SA_SESSION       *IkeSaSession;
 | 
						|
  IKE_PAYLOAD            *IkePayload;
 | 
						|
  IKE_PAYLOAD            *SaPayload;
 | 
						|
  IKE_PAYLOAD            *IdiPayload;
 | 
						|
  IKE_PAYLOAD            *IdrPayload;
 | 
						|
  IKE_PAYLOAD            *AuthPayload;
 | 
						|
  IKE_PAYLOAD            *TsiPayload;
 | 
						|
  IKE_PAYLOAD            *TsrPayload;
 | 
						|
  IKE_PAYLOAD            *CertPayload;
 | 
						|
  IKE_PAYLOAD            *CertReqPayload;
 | 
						|
  IKE_PAYLOAD            *VerifiedAuthPayload;
 | 
						|
  LIST_ENTRY             *Entry;
 | 
						|
  EFI_STATUS             Status;
 | 
						|
 | 
						|
  if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;
 | 
						|
  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
 | 
						|
 | 
						|
  SaPayload           = NULL;
 | 
						|
  IdiPayload          = NULL;
 | 
						|
  IdrPayload          = NULL;
 | 
						|
  AuthPayload         = NULL;
 | 
						|
  TsiPayload          = NULL;
 | 
						|
  TsrPayload          = NULL;
 | 
						|
  CertPayload         = NULL;
 | 
						|
  CertReqPayload      = NULL;
 | 
						|
  VerifiedAuthPayload = NULL;
 | 
						|
  Status              = EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
  //
 | 
						|
  // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
 | 
						|
    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
 | 
						|
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {
 | 
						|
      IdiPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {
 | 
						|
      IdrPayload = IkePayload;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
 | 
						|
      SaPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {
 | 
						|
      AuthPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {
 | 
						|
      TsiPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {
 | 
						|
      TsrPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERT) {
 | 
						|
      CertPayload = IkePayload;
 | 
						|
    }
 | 
						|
    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERTREQ) {
 | 
						|
      CertReqPayload = IkePayload;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || 
 | 
						|
      (TsrPayload == NULL) || (CertPayload == NULL)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  if ((IdiPayload == NULL) && (IdrPayload == NULL)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check IkePacket Header is match the state
 | 
						|
  //
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    
 | 
						|
    //
 | 
						|
    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
 | 
						|
    //
 | 
						|
    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||
 | 
						|
        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
 | 
						|
    //
 | 
						|
    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||
 | 
						|
        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Verify the Auth Payload.
 | 
						|
  //
 | 
						|
  VerifiedAuthPayload = Ikev2CertGenerateAuthPayload (
 | 
						|
                          IkeSaSession,
 | 
						|
                          IkeSaSession->SessionCommon.IsInitiator ? IdrPayload:IdiPayload,
 | 
						|
                          IKEV2_PAYLOAD_TYPE_SA,
 | 
						|
                          TRUE,
 | 
						|
                          NULL,
 | 
						|
                          0,
 | 
						|
                          NULL,
 | 
						|
                          0
 | 
						|
                          );
 | 
						|
 | 
						|
  if ((VerifiedAuthPayload != NULL) &&
 | 
						|
      (!IpSecCryptoIoVerifySignDataByCertificate (
 | 
						|
          CertPayload->PayloadBuf + sizeof (IKEV2_CERT),
 | 
						|
          CertPayload->PayloadSize - sizeof (IKEV2_CERT),
 | 
						|
          (UINT8 *)PcdGetPtr (PcdIpsecUefiCaFile),
 | 
						|
          PcdGet32 (PcdIpsecUefiCaFileSize),
 | 
						|
          VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),
 | 
						|
          VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_AUTH),
 | 
						|
          AuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),
 | 
						|
          AuthPayload->PayloadSize - sizeof (IKEV2_AUTH)
 | 
						|
          ))) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Parse the SA Payload to find out the cryptographic suite
 | 
						|
  //    and fill in the SA paramse into CommonSession->SaParams. If no acceptable
 | 
						|
  //    porposal found, return EFI_INVALID_PARAMETER.
 | 
						|
  //
 | 
						|
  if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 4. Parse TSi, TSr payloads.
 | 
						|
  //
 | 
						|
  if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=
 | 
						|
      ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&
 | 
						|
      (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&
 | 
						|
      (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)
 | 
						|
      ) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    //
 | 
						|
    //Todo:check the Port range. Only support any port and one certain port here.
 | 
						|
    //
 | 
						|
    ChildSaSession->ProtoId    = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;
 | 
						|
    ChildSaSession->LocalPort  = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
 | 
						|
    ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
 | 
						|
    //
 | 
						|
    // Association a SPD with this SA.
 | 
						|
    //
 | 
						|
    if (EFI_ERROR (Ikev2ChildSaAssociateSpdEntry (ChildSaSession))) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.
 | 
						|
    //
 | 
						|
    if (ChildSaSession->IkeSaSession->Spd == NULL) {
 | 
						|
      ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;
 | 
						|
      Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Todo:check the Port range.
 | 
						|
    //
 | 
						|
    if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
 | 
						|
        (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)
 | 
						|
        ) {
 | 
						|
      goto Exit;
 | 
						|
    } 
 | 
						|
    if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
 | 
						|
        (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)
 | 
						|
        ) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.
 | 
						|
    //
 | 
						|
    if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
 | 
						|
      if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
        //
 | 
						|
        // If it is tunnel mode, the UEFI part must be the initiator.
 | 
						|
        //
 | 
						|
        goto Exit;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Get the Virtual IP address from the Tsi traffic selector. 
 | 
						|
      // TODO: check the CFG reply payload
 | 
						|
      //
 | 
						|
      CopyMem (
 | 
						|
        &ChildSaSession->SpdSelector->LocalAddress[0].Address,
 | 
						|
        TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),
 | 
						|
        (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?
 | 
						|
        sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // 5. Generat keymats for IPsec protocol.
 | 
						|
  //
 | 
						|
  Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
 | 
						|
  if (IkeSaSession->SessionCommon.IsInitiator) {
 | 
						|
    //
 | 
						|
    // 6. Change the state of IkeSaSession
 | 
						|
    //
 | 
						|
    IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);
 | 
						|
    IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
Exit:
 | 
						|
  if (VerifiedAuthPayload != NULL) {
 | 
						|
    IkePayloadFree (VerifiedAuthPayload);
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the DH Public Key.
 | 
						|
 | 
						|
  This generates the DH local public key and store it in the IKE SA Session's GxBuffer.
 | 
						|
 | 
						|
  @param[in]  IkeSaSession   Pointer to related IKE SA Session.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        The operation succeeded.
 | 
						|
  @retval Others             The operation failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2GenerateSaDhPublicKey (
 | 
						|
  IN IKEV2_SA_SESSION         *IkeSaSession
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  IKEV2_SESSION_KEYS *IkeKeys;
 | 
						|
 | 
						|
  IkeSaSession->IkeKeys = AllocateZeroPool (sizeof (IKEV2_SESSION_KEYS));
 | 
						|
  ASSERT (IkeSaSession->IkeKeys != NULL);
 | 
						|
  IkeKeys = IkeSaSession->IkeKeys;
 | 
						|
  IkeKeys->DhBuffer = AllocateZeroPool (sizeof (IKEV2_DH_BUFFER));
 | 
						|
  ASSERT (IkeKeys->DhBuffer != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Init DH with the certain DH Group Description.
 | 
						|
  //
 | 
						|
  IkeKeys->DhBuffer->GxSize   = OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size >> 3;
 | 
						|
  IkeKeys->DhBuffer->GxBuffer = AllocateZeroPool (IkeKeys->DhBuffer->GxSize);
 | 
						|
  ASSERT (IkeKeys->DhBuffer->GxBuffer != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get X PublicKey
 | 
						|
  //
 | 
						|
  Status = IpSecCryptoIoDhGetPublicKey (
 | 
						|
             &IkeKeys->DhBuffer->DhContext,
 | 
						|
             OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].GroupGenerator,
 | 
						|
             OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size,
 | 
						|
             OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Modulus,
 | 
						|
             IkeKeys->DhBuffer->GxBuffer,
 | 
						|
             &IkeKeys->DhBuffer->GxSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam X public key error Status = %r\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  IPSEC_DUMP_BUF ("DH Public Key (g^x) Dump", IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Computes the DH Shared/Exchange Key.
 | 
						|
 | 
						|
  Given peer's public key, this function computes the exchanged common key and
 | 
						|
  stores it in the IKEv2 SA Session's GxyBuffer.
 | 
						|
 | 
						|
  @param[in]  DhBuffer       Pointer to buffer of peer's puliic key.
 | 
						|
  @param[in]  KePayload      Pointer to received key payload.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS        The operation succeeded.
 | 
						|
  @retval Otherwise          The operation failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2GenerateSaDhComputeKey (
 | 
						|
  IN IKEV2_DH_BUFFER       *DhBuffer,
 | 
						|
  IN IKE_PAYLOAD            *KePayload
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  IKEV2_KEY_EXCHANGE  *Ke;
 | 
						|
  UINT8               *PubKey;
 | 
						|
  UINTN               PubKeySize;
 | 
						|
 | 
						|
  Ke                  = (IKEV2_KEY_EXCHANGE *) KePayload->PayloadBuf;
 | 
						|
  PubKey              = (UINT8 *) (Ke + 1);
 | 
						|
  PubKeySize          = KePayload->PayloadSize - sizeof (IKEV2_KEY_EXCHANGE);
 | 
						|
  DhBuffer->GxySize   = DhBuffer->GxSize;
 | 
						|
  DhBuffer->GxyBuffer = AllocateZeroPool (DhBuffer->GxySize);
 | 
						|
  ASSERT (DhBuffer->GxyBuffer != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get GxyBuf
 | 
						|
  //
 | 
						|
  Status = IpSecCryptoIoDhComputeKey (
 | 
						|
             DhBuffer->DhContext,
 | 
						|
             PubKey,
 | 
						|
             PubKeySize,
 | 
						|
             DhBuffer->GxyBuffer,
 | 
						|
             &DhBuffer->GxySize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam Y session key error Status = %r\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create GxyBuf.
 | 
						|
  //
 | 
						|
  DhBuffer->GySize   = PubKeySize;
 | 
						|
  DhBuffer->GyBuffer = AllocateZeroPool (DhBuffer->GySize);
 | 
						|
  ASSERT (DhBuffer->GyBuffer != NULL);
 | 
						|
  CopyMem (DhBuffer->GyBuffer, PubKey, DhBuffer->GySize);
 | 
						|
 | 
						|
  IPSEC_DUMP_BUF ("DH Public Key (g^y) Dump", DhBuffer->GyBuffer, DhBuffer->GySize);
 | 
						|
  IPSEC_DUMP_BUF ("DH Shared Key (g^xy) Dump", DhBuffer->GxyBuffer, DhBuffer->GxySize);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the IKE SKEYSEED and seven other secrets. SK_d, SK_ai, SK_ar, SK_ei, SK_er,
 | 
						|
  SK_pi, SK_pr are keys for the furthure IKE exchange.
 | 
						|
 | 
						|
  @param[in]  IkeSaSession       Pointer to IKE SA Session.
 | 
						|
  @param[in]  KePayload          Pointer to Key payload used to generate the Key.
 | 
						|
 | 
						|
  @retval EFI_UNSUPPORTED        If one or more Algorithm Id is not supported.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   If there is no enough resource to be allocated to
 | 
						|
                                 meet the requirement.
 | 
						|
  @retval EFI_SUCCESS            The operation succeeded.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2GenerateSaKeys (
 | 
						|
  IN IKEV2_SA_SESSION       *IkeSaSession,
 | 
						|
  IN IKE_PAYLOAD            *KePayload
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  IKEV2_SA_PARAMS     *SaParams;
 | 
						|
  IPSEC_PAD_ENTRY     *Pad;
 | 
						|
  PRF_DATA_FRAGMENT   Fragments[4];
 | 
						|
  UINT64              InitiatorCookieNet;
 | 
						|
  UINT64              ResponderCookieNet;
 | 
						|
  UINT8               *KeyBuffer;
 | 
						|
  UINTN               KeyBufferSize;
 | 
						|
  UINTN               AuthAlgKeyLen;
 | 
						|
  UINTN               EncryptAlgKeyLen;
 | 
						|
  UINTN               IntegrityAlgKeyLen;
 | 
						|
  UINTN               PrfAlgKeyLen;
 | 
						|
  UINT8               *OutputKey;
 | 
						|
  UINTN               OutputKeyLength;
 | 
						|
  UINT8               *Digest;
 | 
						|
  UINTN               DigestSize;
 | 
						|
 | 
						|
  Digest    = NULL;
 | 
						|
  OutputKey = NULL;
 | 
						|
  KeyBuffer = NULL;
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  // Generate Gxy
 | 
						|
  //
 | 
						|
  Ikev2GenerateSaDhComputeKey (IkeSaSession->IkeKeys->DhBuffer, KePayload);
 | 
						|
 | 
						|
  Pad = IkeSaSession->Pad;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the key length of Authenticaion, Encryption, PRF, and Integrity.
 | 
						|
  //
 | 
						|
  SaParams           = IkeSaSession->SessionCommon.SaParams;
 | 
						|
  AuthAlgKeyLen      = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
 | 
						|
  EncryptAlgKeyLen   = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);
 | 
						|
  IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);
 | 
						|
  PrfAlgKeyLen       = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
 | 
						|
 | 
						|
  //
 | 
						|
  // If one or more algorithm is not support, return EFI_UNSUPPORTED.
 | 
						|
  //
 | 
						|
  if (AuthAlgKeyLen == 0 || 
 | 
						|
      EncryptAlgKeyLen == 0 ||
 | 
						|
      IntegrityAlgKeyLen == 0 ||
 | 
						|
      PrfAlgKeyLen == 0
 | 
						|
      ) {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Compute SKEYSEED = prf(Ni | Nr, g^ir)
 | 
						|
  //
 | 
						|
  KeyBufferSize = IkeSaSession->NiBlkSize + IkeSaSession->NrBlkSize;
 | 
						|
  KeyBuffer     = AllocateZeroPool (KeyBufferSize);
 | 
						|
  ASSERT (KeyBuffer != NULL);
 | 
						|
 | 
						|
  CopyMem (KeyBuffer, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);
 | 
						|
  CopyMem (KeyBuffer + IkeSaSession->NiBlkSize, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);
 | 
						|
 | 
						|
  Fragments[0].Data     = IkeSaSession->IkeKeys->DhBuffer->GxyBuffer;
 | 
						|
  Fragments[0].DataSize = IkeSaSession->IkeKeys->DhBuffer->GxySize;
 | 
						|
 | 
						|
  DigestSize = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
 | 
						|
  Digest     = AllocateZeroPool (DigestSize);
 | 
						|
 | 
						|
  if (Digest == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  IpSecCryptoIoHmac (
 | 
						|
    (UINT8)SaParams->Prf,
 | 
						|
    KeyBuffer,
 | 
						|
    KeyBufferSize,
 | 
						|
    (HASH_DATA_FRAGMENT *) Fragments,
 | 
						|
    1,
 | 
						|
    Digest,
 | 
						|
    DigestSize
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = prf+
 | 
						|
  //               (SKEYSEED, Ni | Nr | SPIi | SPIr )
 | 
						|
  //
 | 
						|
  Fragments[0].Data     = IkeSaSession->NiBlock;
 | 
						|
  Fragments[0].DataSize = IkeSaSession->NiBlkSize;
 | 
						|
  Fragments[1].Data     = IkeSaSession->NrBlock;
 | 
						|
  Fragments[1].DataSize = IkeSaSession->NrBlkSize;
 | 
						|
  InitiatorCookieNet    = HTONLL (IkeSaSession->InitiatorCookie);
 | 
						|
  ResponderCookieNet    = HTONLL (IkeSaSession->ResponderCookie);
 | 
						|
  Fragments[2].Data     = (UINT8 *)(&InitiatorCookieNet);
 | 
						|
  Fragments[2].DataSize = sizeof (IkeSaSession->InitiatorCookie);
 | 
						|
  Fragments[3].Data     = (UINT8 *)(&ResponderCookieNet);
 | 
						|
  Fragments[3].DataSize = sizeof (IkeSaSession->ResponderCookie);
 | 
						|
 | 
						|
  IPSEC_DUMP_BUF (">>> NiBlock", IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);
 | 
						|
  IPSEC_DUMP_BUF (">>> NrBlock", IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);
 | 
						|
  IPSEC_DUMP_BUF (">>> InitiatorCookie", (UINT8 *)&IkeSaSession->InitiatorCookie, sizeof(UINT64));
 | 
						|
  IPSEC_DUMP_BUF (">>> ResponderCookie", (UINT8 *)&IkeSaSession->ResponderCookie, sizeof(UINT64));
 | 
						|
  
 | 
						|
  OutputKeyLength = PrfAlgKeyLen + 
 | 
						|
                    2 * EncryptAlgKeyLen +
 | 
						|
                    2 * AuthAlgKeyLen +
 | 
						|
                    2 * IntegrityAlgKeyLen;
 | 
						|
  OutputKey       = AllocateZeroPool (OutputKeyLength);
 | 
						|
  if (OutputKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Generate Seven Keymates.
 | 
						|
  //
 | 
						|
  Status = Ikev2SaGenerateKey (
 | 
						|
             (UINT8)SaParams->Prf,
 | 
						|
             Digest,
 | 
						|
             DigestSize,
 | 
						|
             OutputKey,
 | 
						|
             OutputKeyLength,
 | 
						|
             Fragments,
 | 
						|
             4
 | 
						|
             );
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Save the seven keys into KeySession.
 | 
						|
  // First, SK_d
 | 
						|
  //
 | 
						|
  IkeSaSession->IkeKeys->SkdKey     = AllocateZeroPool (PrfAlgKeyLen);
 | 
						|
  if (IkeSaSession->IkeKeys->SkdKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  IkeSaSession->IkeKeys->SkdKeySize = PrfAlgKeyLen;
 | 
						|
  CopyMem (IkeSaSession->IkeKeys->SkdKey, OutputKey, PrfAlgKeyLen);
 | 
						|
 | 
						|
  IPSEC_DUMP_BUF (">>> SK_D Key", IkeSaSession->IkeKeys->SkdKey, PrfAlgKeyLen);
 | 
						|
 | 
						|
  //
 | 
						|
  // Second, Sk_ai
 | 
						|
  //
 | 
						|
  IkeSaSession->IkeKeys->SkAiKey     = AllocateZeroPool (IntegrityAlgKeyLen);
 | 
						|
  if (IkeSaSession->IkeKeys->SkAiKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  IkeSaSession->IkeKeys->SkAiKeySize = IntegrityAlgKeyLen;
 | 
						|
  CopyMem (IkeSaSession->IkeKeys->SkAiKey, OutputKey + PrfAlgKeyLen, IntegrityAlgKeyLen);
 | 
						|
  
 | 
						|
  IPSEC_DUMP_BUF (">>> SK_Ai Key", IkeSaSession->IkeKeys->SkAiKey, IkeSaSession->IkeKeys->SkAiKeySize);
 | 
						|
 | 
						|
  //
 | 
						|
  // Third, Sk_ar
 | 
						|
  //
 | 
						|
  IkeSaSession->IkeKeys->SkArKey     = AllocateZeroPool (IntegrityAlgKeyLen);
 | 
						|
  if (IkeSaSession->IkeKeys->SkArKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  IkeSaSession->IkeKeys->SkArKeySize = IntegrityAlgKeyLen;
 | 
						|
  CopyMem (
 | 
						|
    IkeSaSession->IkeKeys->SkArKey,
 | 
						|
    OutputKey + PrfAlgKeyLen + IntegrityAlgKeyLen,
 | 
						|
    IntegrityAlgKeyLen
 | 
						|
    );
 | 
						|
  
 | 
						|
  IPSEC_DUMP_BUF (">>> SK_Ar Key", IkeSaSession->IkeKeys->SkArKey, IkeSaSession->IkeKeys->SkArKeySize);
 | 
						|
 | 
						|
  //
 | 
						|
  // Fourth, Sk_ei
 | 
						|
  //
 | 
						|
  IkeSaSession->IkeKeys->SkEiKey     = AllocateZeroPool (EncryptAlgKeyLen);
 | 
						|
  if (IkeSaSession->IkeKeys->SkEiKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  IkeSaSession->IkeKeys->SkEiKeySize = EncryptAlgKeyLen;
 | 
						|
  
 | 
						|
  CopyMem (
 | 
						|
    IkeSaSession->IkeKeys->SkEiKey,
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,
 | 
						|
    EncryptAlgKeyLen
 | 
						|
    );
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
    ">>> SK_Ei Key", 
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,
 | 
						|
    EncryptAlgKeyLen
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Fifth, Sk_er
 | 
						|
  //
 | 
						|
  IkeSaSession->IkeKeys->SkErKey     = AllocateZeroPool (EncryptAlgKeyLen);
 | 
						|
  if (IkeSaSession->IkeKeys->SkErKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  IkeSaSession->IkeKeys->SkErKeySize = EncryptAlgKeyLen;
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    IkeSaSession->IkeKeys->SkErKey,
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,
 | 
						|
    EncryptAlgKeyLen
 | 
						|
    );
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
    ">>> SK_Er Key",
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,
 | 
						|
    EncryptAlgKeyLen
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Sixth, Sk_pi
 | 
						|
  //
 | 
						|
  IkeSaSession->IkeKeys->SkPiKey     = AllocateZeroPool (AuthAlgKeyLen);
 | 
						|
  if (IkeSaSession->IkeKeys->SkPiKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  IkeSaSession->IkeKeys->SkPiKeySize = AuthAlgKeyLen;
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    IkeSaSession->IkeKeys->SkPiKey,
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen +  2 * EncryptAlgKeyLen,
 | 
						|
    AuthAlgKeyLen
 | 
						|
    );
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
    ">>> SK_Pi Key",
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen +  2 * EncryptAlgKeyLen,
 | 
						|
    AuthAlgKeyLen
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Seventh, Sk_pr
 | 
						|
  //
 | 
						|
  IkeSaSession->IkeKeys->SkPrKey     = AllocateZeroPool (AuthAlgKeyLen);
 | 
						|
  if (IkeSaSession->IkeKeys->SkPrKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
  IkeSaSession->IkeKeys->SkPrKeySize = AuthAlgKeyLen;
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    IkeSaSession->IkeKeys->SkPrKey,
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,
 | 
						|
    AuthAlgKeyLen
 | 
						|
    ); 
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
    ">>> SK_Pr Key",
 | 
						|
    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,
 | 
						|
    AuthAlgKeyLen
 | 
						|
    );
 | 
						|
 | 
						|
 | 
						|
Exit:
 | 
						|
  if (Digest != NULL) {
 | 
						|
    FreePool (Digest);
 | 
						|
  }
 | 
						|
  if (KeyBuffer != NULL) {
 | 
						|
    FreePool (KeyBuffer);
 | 
						|
  }
 | 
						|
  if (OutputKey != NULL) {
 | 
						|
    FreePool (OutputKey);
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    if (IkeSaSession->IkeKeys->SkdKey != NULL) {
 | 
						|
      FreePool (IkeSaSession->IkeKeys->SkdKey);
 | 
						|
    }
 | 
						|
    if (IkeSaSession->IkeKeys->SkAiKey != NULL) {
 | 
						|
      FreePool (IkeSaSession->IkeKeys->SkAiKey);
 | 
						|
    }
 | 
						|
    if (IkeSaSession->IkeKeys->SkArKey != NULL) {
 | 
						|
      FreePool (IkeSaSession->IkeKeys->SkArKey);
 | 
						|
    }
 | 
						|
    if (IkeSaSession->IkeKeys->SkEiKey != NULL) {
 | 
						|
      FreePool (IkeSaSession->IkeKeys->SkEiKey);
 | 
						|
    }
 | 
						|
    if (IkeSaSession->IkeKeys->SkErKey != NULL) {
 | 
						|
      FreePool (IkeSaSession->IkeKeys->SkErKey);
 | 
						|
    }
 | 
						|
    if (IkeSaSession->IkeKeys->SkPiKey != NULL) {
 | 
						|
      FreePool (IkeSaSession->IkeKeys->SkPiKey);
 | 
						|
    }
 | 
						|
    if (IkeSaSession->IkeKeys->SkPrKey != NULL) {
 | 
						|
      FreePool (IkeSaSession->IkeKeys->SkPrKey);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generates the Keys for the furthure IPsec Protocol.
 | 
						|
 | 
						|
  @param[in]  ChildSaSession     Pointer to IKE Child SA Session.
 | 
						|
  @param[in]  KePayload          Pointer to Key payload used to generate the Key.
 | 
						|
 | 
						|
  @retval EFI_UNSUPPORTED    If one or more Algorithm Id is not supported.
 | 
						|
  @retval EFI_SUCCESS        The operation succeeded.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2GenerateChildSaKeys (
 | 
						|
  IN IKEV2_CHILD_SA_SESSION     *ChildSaSession,
 | 
						|
  IN IKE_PAYLOAD                *KePayload
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  IKEV2_SA_PARAMS     *SaParams;
 | 
						|
  PRF_DATA_FRAGMENT   Fragments[3];
 | 
						|
  UINTN               EncryptAlgKeyLen;
 | 
						|
  UINTN               IntegrityAlgKeyLen;
 | 
						|
  UINT8*              OutputKey;
 | 
						|
  UINTN               OutputKeyLength;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  OutputKey = NULL;
 | 
						|
  
 | 
						|
  if (KePayload != NULL) {
 | 
						|
    //
 | 
						|
    // Generate Gxy 
 | 
						|
    //
 | 
						|
    Ikev2GenerateSaDhComputeKey (ChildSaSession->DhBuffer, KePayload);
 | 
						|
    Fragments[0].Data     = ChildSaSession->DhBuffer->GxyBuffer;
 | 
						|
    Fragments[0].DataSize = ChildSaSession->DhBuffer->GxySize;
 | 
						|
  }
 | 
						|
 | 
						|
  Fragments[1].Data     = ChildSaSession->NiBlock;
 | 
						|
  Fragments[1].DataSize = ChildSaSession->NiBlkSize;
 | 
						|
  Fragments[2].Data     = ChildSaSession->NrBlock;
 | 
						|
  Fragments[2].DataSize = ChildSaSession->NrBlkSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the key length of Authenticaion, Encryption, PRF, and Integrity.
 | 
						|
  //
 | 
						|
  SaParams           = ChildSaSession->SessionCommon.SaParams;
 | 
						|
  EncryptAlgKeyLen   = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);
 | 
						|
  IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);
 | 
						|
  OutputKeyLength    = 2 * EncryptAlgKeyLen + 2 * IntegrityAlgKeyLen;
 | 
						|
 | 
						|
  if ((EncryptAlgKeyLen == 0) || (IntegrityAlgKeyLen == 0)) {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 
 | 
						|
  // If KePayload is not NULL, calculate KEYMAT = prf+(SK_d, g^ir (new) | Ni | Nr ),
 | 
						|
  // otherwise, KEYMAT = prf+(SK_d, Ni | Nr )
 | 
						|
  //
 | 
						|
  OutputKey = AllocateZeroPool (OutputKeyLength);
 | 
						|
  if (OutputKey == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Derive Key from the SkdKey Buffer.
 | 
						|
  //
 | 
						|
  Status = Ikev2SaGenerateKey (
 | 
						|
             (UINT8)ChildSaSession->IkeSaSession->SessionCommon.SaParams->Prf,
 | 
						|
             ChildSaSession->IkeSaSession->IkeKeys->SkdKey,
 | 
						|
             ChildSaSession->IkeSaSession->IkeKeys->SkdKeySize,
 | 
						|
             OutputKey,
 | 
						|
             OutputKeyLength,
 | 
						|
             KePayload == NULL ? &Fragments[1] : Fragments,
 | 
						|
             KePayload == NULL ? 2 : 3
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Exit;  
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Copy KEYMATE (SK_ENCRYPT_i | SK_ENCRYPT_r | SK_INTEG_i | SK_INTEG_r) to
 | 
						|
  // ChildKeyMates.
 | 
						|
  //  
 | 
						|
  if (!ChildSaSession->SessionCommon.IsInitiator) {
 | 
						|
 | 
						|
    // 
 | 
						|
    // Initiator Encryption Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
 | 
						|
      OutputKey,
 | 
						|
      EncryptAlgKeyLen
 | 
						|
      );
 | 
						|
 | 
						|
    //
 | 
						|
    // Initiator Authentication Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }    
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
 | 
						|
      OutputKey + EncryptAlgKeyLen,
 | 
						|
      IntegrityAlgKeyLen
 | 
						|
      );
 | 
						|
 | 
						|
    //
 | 
						|
    // Responder Encrypt Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }   
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
 | 
						|
      OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,
 | 
						|
      EncryptAlgKeyLen
 | 
						|
      );
 | 
						|
 | 
						|
    //
 | 
						|
    // Responder Authentication Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }   
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
 | 
						|
      OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,
 | 
						|
      IntegrityAlgKeyLen
 | 
						|
      );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Initiator Encryption Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }   
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
 | 
						|
      OutputKey,
 | 
						|
      EncryptAlgKeyLen
 | 
						|
      );
 | 
						|
 | 
						|
    //
 | 
						|
    // Initiator Authentication Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }   
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
 | 
						|
      OutputKey + EncryptAlgKeyLen,
 | 
						|
      IntegrityAlgKeyLen
 | 
						|
      );
 | 
						|
 | 
						|
    //
 | 
						|
    // Responder Encryption Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }  
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
 | 
						|
      OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,
 | 
						|
      EncryptAlgKeyLen
 | 
						|
      );
 | 
						|
 | 
						|
    //
 | 
						|
    // Responder Authentication Key
 | 
						|
    //
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
 | 
						|
    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);
 | 
						|
    if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Exit;
 | 
						|
    }   
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
 | 
						|
      OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,
 | 
						|
      IntegrityAlgKeyLen
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
      " >>> Local Encryption Key",
 | 
						|
      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
 | 
						|
      EncryptAlgKeyLen
 | 
						|
      );
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
      " >>> Remote Encryption Key",
 | 
						|
      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
 | 
						|
      EncryptAlgKeyLen
 | 
						|
      );
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
      " >>> Local Authentication Key",
 | 
						|
      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
 | 
						|
      IntegrityAlgKeyLen
 | 
						|
      );
 | 
						|
  IPSEC_DUMP_BUF (
 | 
						|
    " >>> Remote Authentication Key",
 | 
						|
    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
 | 
						|
    IntegrityAlgKeyLen
 | 
						|
    );
 | 
						|
 | 
						|
 | 
						|
 | 
						|
Exit:
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey != NULL) {
 | 
						|
      FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey);
 | 
						|
    }
 | 
						|
    if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey != NULL) {
 | 
						|
      FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey);
 | 
						|
    }
 | 
						|
    if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey != NULL) {
 | 
						|
      FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey);
 | 
						|
    }
 | 
						|
    if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey != NULL) {
 | 
						|
      FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (OutputKey != NULL) {
 | 
						|
    FreePool (OutputKey);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Initial[][2] = {
 | 
						|
  { //PSK
 | 
						|
    { // IKEV2_INIT
 | 
						|
      Ikev2InitPskParser,
 | 
						|
      Ikev2InitPskGenerator
 | 
						|
    },
 | 
						|
    { //IKEV2_AUTH
 | 
						|
      Ikev2AuthPskParser,
 | 
						|
      Ikev2AuthPskGenerator
 | 
						|
    }
 | 
						|
  },
 | 
						|
  { // CERT
 | 
						|
    { // IKEV2_INIT
 | 
						|
      Ikev2InitCertParser,
 | 
						|
      Ikev2InitCertGenerator
 | 
						|
    },
 | 
						|
    { // IKEV2_AUTH
 | 
						|
      Ikev2AuthCertParser,
 | 
						|
      Ikev2AuthCertGenerator
 | 
						|
    },
 | 
						|
  },
 | 
						|
};
 |