1/** @file
2  The Implementations for Information Exchange.
3
4  (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5  Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
6
7  This program and the accompanying materials
8  are licensed and made available under the terms and conditions of the BSD License
9  which accompanies this distribution.  The full text of the license may be found at
10  http://opensource.org/licenses/bsd-license.php.
11
12  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15**/
16
17#include "Utility.h"
18#include "IpSecDebug.h"
19#include "IpSecConfigImpl.h"
20
21/**
22  Generate Information Packet.
23
24  The information Packet may contain one Delete Payload, or Notify Payload, which
25  dependes on the Context's parameters.
26
27  @param[in]  SaSession   Pointer to IKE SA Session or Child SA Session which is
28                          related to the information Exchange.
29  @param[in]  Context     The Data passed from the caller. If the Context is not NULL
30                          it should contain the information for Notification Data.
31
32  @retval     Pointer of IKE_PACKET generated.
33
34**/
35IKE_PACKET *
36Ikev2InfoGenerator (
37  IN UINT8                         *SaSession,
38  IN VOID                          *Context
39  )
40{
41  IKEV2_SA_SESSION            *IkeSaSession;
42  IKEV2_CHILD_SA_SESSION      *ChildSaSession;
43  IKE_PACKET                  *IkePacket;
44  IKE_PAYLOAD                 *IkePayload;
45  IKEV2_INFO_EXCHANGE_CONTEXT *InfoContext;
46
47  InfoContext  = NULL;
48  IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
49  IkePacket    = IkePacketAlloc ();
50  if (IkePacket == NULL) {
51    return NULL;
52  }
53
54  //
55  // Fill IkePacket Header.
56  //
57  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_INFO;
58  IkePacket->Header->Version         = (UINT8) (2 << 4);
59
60  if (Context != NULL) {
61    InfoContext = (IKEV2_INFO_EXCHANGE_CONTEXT *) Context;
62  }
63
64  //
65  // For Liveness Check
66  //
67  if (InfoContext != NULL &&
68      (InfoContext->InfoType == Ikev2InfoLiveCheck || InfoContext->InfoType == Ikev2InfoNotify)
69    ) {
70    IkePacket->Header->MessageId       = InfoContext->MessageId;
71    IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
72    IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
73    IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_NONE;
74    IkePacket->Header->Flags           = IKE_HEADER_FLAGS_RESPOND;
75    //
76    // TODO: add Notify Payload for Notification Information.
77    //
78    return IkePacket;
79  }
80
81  //
82  // For delete SAs
83  //
84  if (IkeSaSession->SessionCommon.IkeSessionType == IkeSessionTypeIkeSa) {
85
86    IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
87    IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
88
89    //
90    // If the information message is response message,the MessageId should
91    // be same as the request MessageId which passed through the Context.
92    //
93    if (InfoContext != NULL) {
94      IkePacket->Header->MessageId     = InfoContext->MessageId;
95    } else {
96      IkePacket->Header->MessageId     = IkeSaSession->MessageId;
97      Ikev2SaSessionIncreaseMessageId (IkeSaSession);
98    }
99    //
100    // If the state is on deleting generate a Delete Payload for it.
101    //
102    if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting ) {
103      IkePayload = Ikev2GenerateDeletePayload (
104                     IkeSaSession,
105                     IKEV2_PAYLOAD_TYPE_NONE,
106                     0,
107                     0,
108                     NULL
109                     );
110      if (IkePayload == NULL) {
111        goto ERROR_EXIT;
112      }
113      //
114      // Fill the next payload in IkePacket's Header.
115      //
116      IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_DELETE;
117      IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
118      IkePacket->Private           = IkeSaSession->SessionCommon.Private;
119      IkePacket->Spi               = 0;
120      IkePacket->IsDeleteInfo      = TRUE;
121
122    } else if (Context != NULL) {
123      //
124      // TODO: If contest is not NULL Generate a Notify Payload.
125      //
126    } else {
127      //
128      // The input parameter is not correct.
129      //
130      goto ERROR_EXIT;
131    }
132
133    if (IkeSaSession->SessionCommon.IsInitiator) {
134      IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT ;
135    }
136  } else {
137    //
138    // Delete the Child SA Information Exchagne
139    //
140    ChildSaSession                     = (IKEV2_CHILD_SA_SESSION *) SaSession;
141    IkeSaSession                       = ChildSaSession->IkeSaSession;
142    IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;
143    IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;
144
145    //
146    // If the information message is response message,the MessageId should
147    // be same as the request MessageId which passed through the Context.
148    //
149    if (InfoContext != NULL && InfoContext->MessageId != 0) {
150      IkePacket->Header->MessageId     = InfoContext->MessageId;
151    } else {
152      IkePacket->Header->MessageId     = ChildSaSession->IkeSaSession->MessageId;
153      Ikev2SaSessionIncreaseMessageId (IkeSaSession);
154    }
155
156    IkePayload     = Ikev2GenerateDeletePayload (
157                       ChildSaSession->IkeSaSession,
158                       IKEV2_PAYLOAD_TYPE_DELETE,
159                       4,
160                       1,
161                       (UINT8 *)&ChildSaSession->LocalPeerSpi
162                       );
163    if (IkePayload == NULL) {
164      goto ERROR_EXIT;
165    }
166    //
167    // Fill the Next Payload in IkePacket's Header.
168    //
169    IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_DELETE;
170    IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
171
172    IkePacket->Private      = IkeSaSession->SessionCommon.Private;
173    IkePacket->Spi          = ChildSaSession->LocalPeerSpi;
174    IkePacket->IsDeleteInfo = TRUE;
175
176    if (!ChildSaSession->SessionCommon.IsInitiator) {
177      //
178      // If responder, use the MessageId fromt the initiator.
179      //
180      IkePacket->Header->MessageId = ChildSaSession->MessageId;
181    }
182
183    //
184    // Change the IsOnDeleting Flag
185    //
186    ChildSaSession->SessionCommon.IsOnDeleting = TRUE;
187
188    if (ChildSaSession->SessionCommon.IsInitiator) {
189      IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT ;
190    }
191  }
192
193  if (InfoContext != NULL) {
194    IkePacket->Header->Flags |= IKE_HEADER_FLAGS_RESPOND;
195  }
196
197  return IkePacket;
198
199ERROR_EXIT:
200   if (IkePacket != NULL) {
201     FreePool (IkePacket);
202   }
203   return NULL;
204
205}
206
207/**
208  Parse the Info Exchange.
209
210  @param[in]  SaSession   Pointer to IKEV2_SA_SESSION.
211  @param[in]  IkePacket   Pointer to IkePacket related to the Information Exchange.
212
213  @retval  EFI_SUCCESS    The operation finised successed.
214
215**/
216EFI_STATUS
217Ikev2InfoParser (
218  IN UINT8                         *SaSession,
219  IN IKE_PACKET                    *IkePacket
220  )
221{
222  IKEV2_CHILD_SA_SESSION *ChildSaSession;
223  IKEV2_SA_SESSION       *IkeSaSession;
224  IKE_PAYLOAD            *DeletePayload;
225  IKE_PAYLOAD            *IkePayload;
226  IKEV2_DELETE           *Delete;
227  LIST_ENTRY             *Entry;
228  LIST_ENTRY             *ListEntry;
229  UINT8                  Index;
230  UINT32                 Spi;
231  UINT8                  *SpiBuffer;
232  IPSEC_PRIVATE_DATA     *Private;
233  UINT8                  Value;
234  EFI_STATUS             Status;
235  IKE_PACKET             *RespondPacket;
236
237  IKEV2_INFO_EXCHANGE_CONTEXT Context;
238
239  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;
240
241  DeletePayload  = NULL;
242  Private        = NULL;
243  RespondPacket  = NULL;
244  Status         = EFI_SUCCESS;
245
246  //
247  // For Liveness Check
248  //
249  if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE &&
250      (IkePacket->PayloadTotalSize == 0)
251      ) {
252    if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {
253      //
254      // If it is Liveness check request, reply it.
255      //
256      Context.InfoType  = Ikev2InfoLiveCheck;
257      Context.MessageId = IkePacket->Header->MessageId;
258      RespondPacket     = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
259
260      if (RespondPacket == NULL) {
261        Status = EFI_INVALID_PARAMETER;
262        return Status;
263      }
264      Status = Ikev2SendIkePacket (
265                 IkeSaSession->SessionCommon.UdpService,
266                 (UINT8 *)(&IkeSaSession->SessionCommon),
267                 RespondPacket,
268                 0
269                 );
270
271    } else {
272      //
273      // Todo: verify the liveness check response packet.
274      //
275    }
276    return Status;
277  }
278
279  //
280  // For SA Delete
281  //
282  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
283
284  //
285  // Iterate payloads to find the Delete/Notify Payload.
286  //
287    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
288
289    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_DELETE) {
290      DeletePayload = IkePayload;
291      Delete = (IKEV2_DELETE *)DeletePayload->PayloadBuf;
292
293      if (Delete->SpiSize == 0) {
294        //
295        // Delete IKE SA.
296        //
297        if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {
298          RemoveEntryList (&IkeSaSession->BySessionTable);
299          Ikev2SaSessionFree (IkeSaSession);
300          //
301          // Checking the Private status.
302          //
303          //
304          // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec
305          // status should be changed.
306          //
307          Private = IkeSaSession->SessionCommon.Private;
308          if (Private != NULL && Private->IsIPsecDisabling) {
309            //
310            // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
311            // IPsec status variable.
312            //
313            if (IsListEmpty (&Private->Ikev1EstablishedList) &&
314                (IsListEmpty (&Private->Ikev2EstablishedList))
315               ) {
316              Value  = IPSEC_STATUS_DISABLED;
317              Status = gRT->SetVariable (
318                         IPSECCONFIG_STATUS_NAME,
319                         &gEfiIpSecConfigProtocolGuid,
320                         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
321                         sizeof (Value),
322                         &Value
323                         );
324              if (!EFI_ERROR (Status)) {
325                //
326                // Set the DisabledFlag in Private data.
327                //
328                Private->IpSec.DisabledFlag = TRUE;
329                Private->IsIPsecDisabling   = FALSE;
330              }
331            }
332          }
333        } else {
334          IkeSaSession->SessionCommon.State = IkeStateSaDeleting;
335          Context.InfoType                  = Ikev2InfoDelete;
336          Context.MessageId                 = IkePacket->Header->MessageId;
337
338          RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
339          if (RespondPacket == NULL) {
340            Status = EFI_INVALID_PARAMETER;
341            return Status;
342          }
343          Status = Ikev2SendIkePacket (
344                     IkeSaSession->SessionCommon.UdpService,
345                     (UINT8 *)(&IkeSaSession->SessionCommon),
346                     RespondPacket,
347                     0
348                     );
349        }
350      } else if (Delete->SpiSize == 4) {
351        //
352        // Move the Child SAs to DeleteList
353        //
354        SpiBuffer = (UINT8 *)(Delete + 1);
355        for (Index = 0; Index < Delete->NumSpis; Index++) {
356          Spi = ReadUnaligned32 ((UINT32 *)SpiBuffer);
357          for (ListEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;
358               ListEntry != &IkeSaSession->ChildSaEstablishSessionList;
359          ) {
360            ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ListEntry);
361            ListEntry = ListEntry->ForwardLink;
362
363            if (ChildSaSession->RemotePeerSpi == HTONL(Spi)) {
364              if (ChildSaSession->SessionCommon.State != IkeStateSaDeleting) {
365
366                //
367                // Insert the ChildSa Session into Delete List.
368                //
369                InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);
370                ChildSaSession->SessionCommon.State       = IkeStateSaDeleting;
371                ChildSaSession->SessionCommon.IsInitiator = FALSE;
372                ChildSaSession->MessageId                 = IkePacket->Header->MessageId;
373
374                Context.InfoType = Ikev2InfoDelete;
375                Context.MessageId = IkePacket->Header->MessageId;
376
377                RespondPacket = Ikev2InfoGenerator ((UINT8 *)ChildSaSession, &Context);
378                if (RespondPacket == NULL) {
379                  Status = EFI_INVALID_PARAMETER;
380                  return Status;
381                }
382                Status = Ikev2SendIkePacket (
383                           ChildSaSession->SessionCommon.UdpService,
384                           (UINT8 *)(&ChildSaSession->SessionCommon),
385                           RespondPacket,
386                           0
387                           );
388              } else {
389                //
390                // Delete the Child SA.
391                //
392                Ikev2ChildSaSilentDelete (IkeSaSession, Spi);
393                RemoveEntryList (&ChildSaSession->ByDelete);
394              }
395            }
396          }
397          SpiBuffer = SpiBuffer + sizeof (Spi);
398        }
399      }
400    }
401  }
402
403  return Status;
404}
405
406GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER  mIkev2Info = {
407  Ikev2InfoParser,
408  Ikev2InfoGenerator
409};
410