Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@hp.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17773 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2060 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2060 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   The operations for IKEv2 SA.
 | |
| 
 | |
|   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
 | |
|   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            *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;
 | |
|   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 ((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;
 | |
|   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);
 | |
| 
 | |
|   //
 | |
|   // 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
 | |
|     },
 | |
|   },
 | |
| };
 |